Initial commit
This commit is contained in:
47
engines/ags/lib/allegro/aintern.h
Normal file
47
engines/ags/lib/allegro/aintern.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_AINTERN_H
|
||||
#define AGS_LIB_ALLEGRO_AINTERN_H
|
||||
|
||||
#include "ags/lib/allegro/base.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
|
||||
/* default truecolor pixel format */
|
||||
#define DEFAULT_RGB_R_SHIFT_15 0
|
||||
#define DEFAULT_RGB_G_SHIFT_15 5
|
||||
#define DEFAULT_RGB_B_SHIFT_15 10
|
||||
#define DEFAULT_RGB_R_SHIFT_16 0
|
||||
#define DEFAULT_RGB_G_SHIFT_16 5
|
||||
#define DEFAULT_RGB_B_SHIFT_16 11
|
||||
#define DEFAULT_RGB_R_SHIFT_24 0
|
||||
#define DEFAULT_RGB_G_SHIFT_24 8
|
||||
#define DEFAULT_RGB_B_SHIFT_24 16
|
||||
#define DEFAULT_RGB_R_SHIFT_32 0
|
||||
#define DEFAULT_RGB_G_SHIFT_32 8
|
||||
#define DEFAULT_RGB_B_SHIFT_32 16
|
||||
#define DEFAULT_RGB_A_SHIFT_32 24
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
83
engines/ags/lib/allegro/alconfig.h
Normal file
83
engines/ags/lib/allegro/alconfig.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_ALCONFIG_H
|
||||
#define AGS_LIB_ALLEGRO_ALCONFIG_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
/* which color depths to include? */
|
||||
#define ALLEGRO_COLOR8
|
||||
#define ALLEGRO_COLOR16
|
||||
#define ALLEGRO_COLOR24
|
||||
#define ALLEGRO_COLOR32
|
||||
|
||||
#ifndef INLINE
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#ifndef RET_VOLATILE
|
||||
#define RET_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
#ifndef ZERO_SIZE_ARRAY
|
||||
#define ZERO_SIZE_ARRAY(type, name) type name[]
|
||||
#endif
|
||||
|
||||
#ifndef AL_CONST
|
||||
#define AL_CONST const
|
||||
#endif
|
||||
|
||||
#ifndef AL_VAR
|
||||
#define AL_VAR(type, name) extern type name
|
||||
#endif
|
||||
|
||||
#ifndef AL_ARRAY
|
||||
#define AL_ARRAY(type, name) extern type name[]
|
||||
#endif
|
||||
|
||||
#ifndef AL_FUNC
|
||||
#define AL_FUNC(type, name, args) type name args
|
||||
#endif
|
||||
|
||||
#ifndef AL_PRINTFUNC
|
||||
#define AL_PRINTFUNC(type, name, args, a, b) AL_FUNC(type, name, args)
|
||||
#endif
|
||||
|
||||
#ifndef AL_METHOD
|
||||
#define AL_METHOD(type, name, args) type (*name) args
|
||||
#endif
|
||||
|
||||
#ifndef AL_FUNCPTR
|
||||
#define AL_FUNCPTR(type, name, args) extern type (*name) args
|
||||
#endif
|
||||
|
||||
#ifndef AL_FUNCPTRARRAY
|
||||
#define AL_FUNCPTRARRAY(type, name, args) extern type (*name[]) args
|
||||
#endif
|
||||
|
||||
#ifndef AL_INLINE
|
||||
#define AL_INLINE(type, name, args, code) type name args;
|
||||
#endif
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
52
engines/ags/lib/allegro/base.h
Normal file
52
engines/ags/lib/allegro/base.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_BASE_H
|
||||
#define AGS_LIB_ALLEGRO_BASE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/endian.h"
|
||||
#include "ags/lib/allegro/error.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define ALLEGRO_VERSION 4
|
||||
#define ALLEGRO_SUB_VERSION 4
|
||||
#define ALLEGRO_WIP_VERSION 2
|
||||
#define ALLEGRO_VERSION_STR "4.4.2"
|
||||
#define ALLEGRO_DATE_STR "2011"
|
||||
#define ALLEGRO_DATE 20110519 /* yyyymmdd */
|
||||
|
||||
/* Returns the median of x, y, z */
|
||||
#define MID(x,y,z) ((x) > (y) ? ((y) > (z) ? (y) : ((x) > (z) ? \
|
||||
(z) : (x))) : ((y) > (z) ? ((z) > (x) ? (z) : \
|
||||
(x)): (y)))
|
||||
|
||||
#define AL_ID MKTAG
|
||||
|
||||
#define AL_FUNC(type, name, args) type name args
|
||||
|
||||
#define SCUMMVM_ID MKTAG('S', 'C', 'V', 'M')
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
974
engines/ags/lib/allegro/color.cpp
Normal file
974
engines/ags/lib/allegro/color.cpp
Normal file
@@ -0,0 +1,974 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/lib/allegro/system.h"
|
||||
#include "ags/lib/allegro/aintern.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/globals.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/system.h"
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define VGA_COLOR_TRANS(x) ((x) * 255 / 63)
|
||||
|
||||
void color::readFromFile(AGS::Shared::Stream *file) {
|
||||
r = file->ReadByte();
|
||||
g = file->ReadByte();
|
||||
b = file->ReadByte();
|
||||
filler = file->ReadByte();
|
||||
}
|
||||
|
||||
void color::writeToFile(AGS::Shared::Stream *file) const {
|
||||
file->WriteByte(r);
|
||||
file->WriteByte(g);
|
||||
file->WriteByte(b);
|
||||
file->WriteByte(filler);
|
||||
}
|
||||
|
||||
static void convertPalette(const PALETTE src, byte dest[Graphics::PALETTE_SIZE]) {
|
||||
const color *cSrc = (const color *)src;
|
||||
for (int i = 0; i < Graphics::PALETTE_COUNT; ++i, cSrc++, dest += 3) {
|
||||
dest[0] = VGA_COLOR_TRANS(cSrc->r);
|
||||
dest[1] = VGA_COLOR_TRANS(cSrc->g);
|
||||
dest[2] = VGA_COLOR_TRANS(cSrc->b);
|
||||
}
|
||||
}
|
||||
|
||||
static void applyPalette() {
|
||||
if (g_system->getScreenFormat().bytesPerPixel == 1) {
|
||||
byte pal[Graphics::PALETTE_SIZE];
|
||||
convertPalette(_G(current_palette), pal);
|
||||
g_system->getPaletteManager()->setPalette(pal, 0, Graphics::PALETTE_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
void set_palette(const PALETTE p) {
|
||||
for (int idx = 0; idx < PAL_SIZE; ++idx)
|
||||
_G(current_palette)[idx] = p[idx];
|
||||
|
||||
applyPalette();
|
||||
}
|
||||
|
||||
void set_palette_range(const PALETTE p, int from, int to, int retracesync) {
|
||||
for (int i = from; i <= to; ++i) {
|
||||
_G(current_palette)[i] = p[i];
|
||||
}
|
||||
|
||||
applyPalette();
|
||||
}
|
||||
|
||||
int makecol15(int r, int g, int b) {
|
||||
return (((r >> 3) << _G(_rgb_r_shift_15)) |
|
||||
((g >> 3) << _G(_rgb_g_shift_15)) |
|
||||
((b >> 3) << _G(_rgb_b_shift_15)));
|
||||
}
|
||||
|
||||
int makecol16(int r, int g, int b) {
|
||||
return (((r >> 3) << _G(_rgb_r_shift_16)) |
|
||||
((g >> 2) << _G(_rgb_g_shift_16)) |
|
||||
((b >> 3) << _G(_rgb_b_shift_16)));
|
||||
}
|
||||
|
||||
int makecol24(int r, int g, int b) {
|
||||
return ((r << _G(_rgb_r_shift_24)) |
|
||||
(g << _G(_rgb_g_shift_24)) |
|
||||
(b << _G(_rgb_b_shift_24)));
|
||||
}
|
||||
|
||||
int makecol32(int r, int g, int b) {
|
||||
return ((r << _G(_rgb_r_shift_32)) |
|
||||
(g << _G(_rgb_g_shift_32)) |
|
||||
(b << _G(_rgb_b_shift_32)));
|
||||
}
|
||||
|
||||
int makeacol32(int r, int g, int b, int a) {
|
||||
return ((r << _G(_rgb_r_shift_32)) |
|
||||
(g << _G(_rgb_g_shift_32)) |
|
||||
(b << _G(_rgb_b_shift_32)) |
|
||||
(a << _G(_rgb_a_shift_32)));
|
||||
}
|
||||
|
||||
int getr8(int c) {
|
||||
return (int)_G(current_palette)[c].r;
|
||||
}
|
||||
|
||||
int getg8(int c) {
|
||||
return (int)_G(current_palette)[c].g;
|
||||
}
|
||||
|
||||
int getb8(int c) {
|
||||
return (int)_G(current_palette)[c].b;
|
||||
}
|
||||
|
||||
int getr15(int c) {
|
||||
return _rgb_scale_5[(c >> _G(_rgb_r_shift_15)) & 0x1F];
|
||||
}
|
||||
|
||||
int getg15(int c) {
|
||||
return _rgb_scale_5[(c >> _G(_rgb_g_shift_15)) & 0x1F];
|
||||
}
|
||||
|
||||
int getb15(int c) {
|
||||
return _rgb_scale_5[(c >> _G(_rgb_b_shift_15)) & 0x1F];
|
||||
}
|
||||
|
||||
int getr16(int c) {
|
||||
return _rgb_scale_5[(c >> _G(_rgb_r_shift_16)) & 0x1F];
|
||||
}
|
||||
|
||||
int getg16(int c) {
|
||||
return _rgb_scale_6[(c >> _G(_rgb_g_shift_16)) & 0x3F];
|
||||
}
|
||||
|
||||
int getb16(int c) {
|
||||
return _rgb_scale_5[(c >> _G(_rgb_b_shift_16)) & 0x1F];
|
||||
}
|
||||
|
||||
int getr24(int c) {
|
||||
return ((c >> _G(_rgb_r_shift_24)) & 0xFF);
|
||||
}
|
||||
|
||||
int getg24(int c) {
|
||||
return ((c >> _G(_rgb_g_shift_24)) & 0xFF);
|
||||
}
|
||||
|
||||
int getb24(int c) {
|
||||
return ((c >> _G(_rgb_b_shift_24)) & 0xFF);
|
||||
}
|
||||
|
||||
int getr32(int c) {
|
||||
return ((c >> _G(_rgb_r_shift_32)) & 0xFF);
|
||||
}
|
||||
|
||||
int getg32(int c) {
|
||||
return ((c >> _G(_rgb_g_shift_32)) & 0xFF);
|
||||
}
|
||||
|
||||
int getb32(int c) {
|
||||
return ((c >> _G(_rgb_b_shift_32)) & 0xFF);
|
||||
}
|
||||
|
||||
int geta32(int c) {
|
||||
return ((c >> _G(_rgb_a_shift_32)) & 0xFF);
|
||||
}
|
||||
|
||||
int makecol(byte r, byte g, byte b) {
|
||||
return (b) | (g << 8) | (r << 16);
|
||||
}
|
||||
|
||||
int makecol8(byte r, byte g, byte b) {
|
||||
return (b) | (g << 8) | (r << 16);
|
||||
}
|
||||
|
||||
void get_color(int idx, RGB *p) {
|
||||
*p = _G(current_palette)[idx];
|
||||
}
|
||||
|
||||
void get_palette_range(PALETTE p, int from, int to) {
|
||||
Common::copy(&_G(current_palette)[from], &_G(current_palette)[to + 1], &p[from]);
|
||||
}
|
||||
|
||||
void get_palette(PALETTE p) {
|
||||
get_palette_range(p, 0, PAL_SIZE - 1);
|
||||
}
|
||||
|
||||
void fade_interpolate(AL_CONST PALETTE source, AL_CONST PALETTE dest, PALETTE output, int pos, int from, int to) {
|
||||
assert(pos >= 0 && pos <= 64);
|
||||
assert(from >= 0 && from < PAL_SIZE);
|
||||
assert(to >= 0 && to < PAL_SIZE);
|
||||
|
||||
for (int c = from; c <= to; c++) {
|
||||
output[c].r = ((int)source[c].r * (63 - pos) + (int)dest[c].r * pos) / 64;
|
||||
output[c].g = ((int)source[c].g * (63 - pos) + (int)dest[c].g * pos) / 64;
|
||||
output[c].b = ((int)source[c].b * (63 - pos) + (int)dest[c].b * pos) / 64;
|
||||
}
|
||||
}
|
||||
|
||||
void select_palette(AL_CONST PALETTE p) {
|
||||
int c;
|
||||
|
||||
for (c = 0; c < PAL_SIZE; c++) {
|
||||
_G(prev_current_palette)[c] = _G(current_palette)[c];
|
||||
_G(current_palette)[c] = p[c];
|
||||
}
|
||||
|
||||
applyPalette();
|
||||
}
|
||||
|
||||
void unselect_palette(void) {
|
||||
int c;
|
||||
|
||||
for (c = 0; c < PAL_SIZE; c++)
|
||||
_G(current_palette)[c] = _G(prev_current_palette)[c];
|
||||
|
||||
applyPalette();
|
||||
}
|
||||
|
||||
void set_blender_mode(BlenderMode m, int r, int g, int b, int a) {
|
||||
_G(_blender_mode) = m;
|
||||
_G(trans_blend_alpha) = a;
|
||||
_G(trans_blend_red) = r;
|
||||
_G(trans_blend_green) = g;
|
||||
_G(trans_blend_blue) = b;
|
||||
}
|
||||
|
||||
void set_alpha_blender(void) {
|
||||
set_blender_mode(kSourceAlphaBlender, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void set_trans_blender(int r, int g, int b, int a) {
|
||||
set_blender_mode(kRgbToRgbBlender, r, g, b, a);
|
||||
}
|
||||
|
||||
/* makecol_depth:
|
||||
* Converts R, G, and B values (ranging 0-255) to whatever pixel format
|
||||
* is required by the specified color depth.
|
||||
*/
|
||||
int makecol_depth(int color_depth, int r, int g, int b) {
|
||||
switch (color_depth) {
|
||||
|
||||
case 8:
|
||||
return makecol8(r, g, b);
|
||||
|
||||
case 15:
|
||||
return makecol15(r, g, b);
|
||||
|
||||
case 16:
|
||||
return makecol16(r, g, b);
|
||||
|
||||
case 24:
|
||||
return makecol24(r, g, b);
|
||||
|
||||
case 32:
|
||||
return makecol32(r, g, b);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* makeacol_depth:
|
||||
* Converts R, G, B, and A values (ranging 0-255) to whatever pixel format
|
||||
* is required by the specified color depth.
|
||||
*/
|
||||
int makeacol_depth(int color_depth, int r, int g, int b, int a) {
|
||||
switch (color_depth) {
|
||||
|
||||
case 8:
|
||||
return makecol8(r, g, b);
|
||||
|
||||
case 15:
|
||||
return makecol15(r, g, b);
|
||||
|
||||
case 16:
|
||||
return makecol16(r, g, b);
|
||||
|
||||
case 24:
|
||||
return makecol24(r, g, b);
|
||||
|
||||
case 32:
|
||||
return makeacol32(r, g, b, a);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getr_depth:
|
||||
* Extracts the red component (ranging 0-255) from a pixel in the format
|
||||
* being used by the specified color depth.
|
||||
*/
|
||||
int getr_depth(int color_depth, int c) {
|
||||
switch (color_depth) {
|
||||
|
||||
case 8:
|
||||
return getr8(c);
|
||||
|
||||
case 15:
|
||||
return getr15(c);
|
||||
|
||||
case 16:
|
||||
return getr16(c);
|
||||
|
||||
case 24:
|
||||
return getr24(c);
|
||||
|
||||
case 32:
|
||||
return getr32(c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getg_depth:
|
||||
* Extracts the green component (ranging 0-255) from a pixel in the format
|
||||
* being used by the specified color depth.
|
||||
*/
|
||||
int getg_depth(int color_depth, int c) {
|
||||
switch (color_depth) {
|
||||
|
||||
case 8:
|
||||
return getg8(c);
|
||||
|
||||
case 15:
|
||||
return getg15(c);
|
||||
|
||||
case 16:
|
||||
return getg16(c);
|
||||
|
||||
case 24:
|
||||
return getg24(c);
|
||||
|
||||
case 32:
|
||||
return getg32(c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getb_depth:
|
||||
* Extracts the blue component (ranging 0-255) from a pixel in the format
|
||||
* being used by the specified color depth.
|
||||
*/
|
||||
int getb_depth(int color_depth, int c) {
|
||||
switch (color_depth) {
|
||||
|
||||
case 8:
|
||||
return getb8(c);
|
||||
|
||||
case 15:
|
||||
return getb15(c);
|
||||
|
||||
case 16:
|
||||
return getb16(c);
|
||||
|
||||
case 24:
|
||||
return getb24(c);
|
||||
|
||||
case 32:
|
||||
return getb32(c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* geta_depth:
|
||||
* Extracts the alpha component (ranging 0-255) from a pixel in the format
|
||||
* being used by the specified color depth.
|
||||
*/
|
||||
int geta_depth(int color_depth, int c) {
|
||||
if (color_depth == 32)
|
||||
return geta32(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getr:
|
||||
* Extracts the red component (ranging 0-255) from a pixel in the format
|
||||
* being used by the current video mode.
|
||||
*/
|
||||
int getr(int c) {
|
||||
return getr_depth(_G(_color_depth), c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getg:
|
||||
* Extracts the green component (ranging 0-255) from a pixel in the format
|
||||
* being used by the current video mode.
|
||||
*/
|
||||
int getg(int c) {
|
||||
return getg_depth(_G(_color_depth), c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* getb:
|
||||
* Extracts the blue component (ranging 0-255) from a pixel in the format
|
||||
* being used by the current video mode.
|
||||
*/
|
||||
int getb(int c) {
|
||||
return getb_depth(_G(_color_depth), c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* geta:
|
||||
* Extracts the alpha component (ranging 0-255) from a pixel in the format
|
||||
* being used by the current video mode.
|
||||
*/
|
||||
int geta(int c) {
|
||||
return geta_depth(_G(_color_depth), c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 1.5k lookup table for color matching */
|
||||
static unsigned int col_diff[3 * 128];
|
||||
|
||||
|
||||
|
||||
/* bestfit_init:
|
||||
* Color matching is done with weighted squares, which are much faster
|
||||
* if we pregenerate a little lookup table...
|
||||
*/
|
||||
static void bestfit_init(void) {
|
||||
int i;
|
||||
|
||||
for (i = 1; i < 64; i++) {
|
||||
int k = i * i;
|
||||
col_diff[0 + i] = col_diff[0 + 128 - i] = k * (59 * 59);
|
||||
col_diff[128 + i] = col_diff[128 + 128 - i] = k * (30 * 30);
|
||||
col_diff[256 + i] = col_diff[256 + 128 - i] = k * (11 * 11);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* bestfit_color:
|
||||
* Searches a palette for the color closest to the requested R, G, B value.
|
||||
*/
|
||||
int bestfit_color(AL_CONST PALETTE pal, int r, int g, int b) {
|
||||
int i, coldiff, lowest, bestfit;
|
||||
|
||||
assert(r >= 0 && r <= 63);
|
||||
assert(g >= 0 && g <= 63);
|
||||
assert(b >= 0 && b <= 63);
|
||||
|
||||
if (col_diff[1] == 0)
|
||||
bestfit_init();
|
||||
|
||||
bestfit = 0;
|
||||
lowest = INT_MAX;
|
||||
|
||||
/* only the transparent (pink) color can be mapped to index 0 */
|
||||
if ((r == 63) && (g == 0) && (b == 63))
|
||||
i = 0;
|
||||
else
|
||||
i = 1;
|
||||
|
||||
while (i < PAL_SIZE) {
|
||||
AL_CONST RGB *rgb = &pal[i];
|
||||
coldiff = (col_diff + 0)[(rgb->g - g) & 0x7F];
|
||||
if (coldiff < lowest) {
|
||||
coldiff += (col_diff + 128)[(rgb->r - r) & 0x7F];
|
||||
if (coldiff < lowest) {
|
||||
coldiff += (col_diff + 256)[(rgb->b - b) & 0x7F];
|
||||
if (coldiff < lowest) {
|
||||
bestfit = rgb - pal; /* faster than `bestfit = i;' */
|
||||
if (coldiff == 0)
|
||||
return bestfit;
|
||||
lowest = coldiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return bestfit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* makecol8:
|
||||
* Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
|
||||
* If the global _G(rgb_map) table is initialised, it uses that, otherwise
|
||||
* it searches through the current palette to find the best match.
|
||||
*/
|
||||
int makecol8(int r, int g, int b) {
|
||||
if (_G(rgb_map))
|
||||
return _G(rgb_map)->data[r >> 3][g >> 3][b >> 3];
|
||||
else
|
||||
return bestfit_color(_G(current_palette), r >> 2, g >> 2, b >> 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* hsv_to_rgb:
|
||||
* Converts from HSV colorspace to RGB values.
|
||||
*/
|
||||
void hsv_to_rgb(float h, float s, float v, int *r, int *g, int *b) {
|
||||
float f, x, y, z;
|
||||
int i;
|
||||
|
||||
assert(s >= 0 && s <= 1);
|
||||
assert(v >= 0 && v <= 1);
|
||||
|
||||
v *= 255.0f;
|
||||
|
||||
if (s == 0.0f) { /* ok since we don't divide by s, and faster */
|
||||
*r = *g = *b = v + 0.5f;
|
||||
} else {
|
||||
h = fmod(h, 360.0f) / 60.0f;
|
||||
if (h < 0.0f)
|
||||
h += 6.0f;
|
||||
|
||||
i = (int)h;
|
||||
f = h - i;
|
||||
x = v * s;
|
||||
y = x * f;
|
||||
v += 0.5f; /* round to the nearest integer below */
|
||||
z = v - x;
|
||||
|
||||
switch (i) {
|
||||
|
||||
case 6:
|
||||
case 0:
|
||||
*r = v;
|
||||
*g = z + y;
|
||||
*b = z;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*r = v - y;
|
||||
*g = v;
|
||||
*b = z;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*r = z;
|
||||
*g = v;
|
||||
*b = z + y;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
*r = z;
|
||||
*g = v - y;
|
||||
*b = v;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*r = z + y;
|
||||
*g = z;
|
||||
*b = v;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
*r = v;
|
||||
*g = z;
|
||||
*b = v - y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* rgb_to_hsv:
|
||||
* Converts an RGB value into the HSV colorspace.
|
||||
*/
|
||||
void rgb_to_hsv(int r, int g, int b, float *h, float *s, float *v) {
|
||||
int delta;
|
||||
|
||||
assert(r >= 0 && r <= 255);
|
||||
assert(g >= 0 && g <= 255);
|
||||
assert(b >= 0 && b <= 255);
|
||||
|
||||
if (r > g) {
|
||||
if (b > r) {
|
||||
/* b>r>g */
|
||||
delta = b - g;
|
||||
*h = 240.0f + ((r - g) * 60) / (float)delta;
|
||||
*s = (float)delta / (float)b;
|
||||
*v = (float)b * (1.0f / 255.0f);
|
||||
} else {
|
||||
/* r>g and r>b */
|
||||
delta = r - MIN(g, b);
|
||||
*h = ((g - b) * 60) / (float)delta;
|
||||
if (*h < 0.0f)
|
||||
*h += 360.0f;
|
||||
*s = (float)delta / (float)r;
|
||||
*v = (float)r * (1.0f / 255.0f);
|
||||
}
|
||||
} else {
|
||||
if (b > g) {
|
||||
/* b>g>=r */
|
||||
delta = b - r;
|
||||
*h = 240.0f + ((r - g) * 60) / (float)delta;
|
||||
*s = (float)delta / (float)b;
|
||||
*v = (float)b * (1.0f / 255.0f);
|
||||
} else {
|
||||
/* g>=b and g>=r */
|
||||
delta = g - MIN(r, b);
|
||||
if (delta == 0) {
|
||||
*h = 0.0f;
|
||||
if (g == 0)
|
||||
*s = *v = 0.0f;
|
||||
else {
|
||||
*s = (float)delta / (float)g;
|
||||
*v = (float)g * (1.0f / 255.0f);
|
||||
}
|
||||
} else {
|
||||
*h = 120.0f + ((b - r) * 60) / (float)delta;
|
||||
*s = (float)delta / (float)g;
|
||||
*v = (float)g * (1.0f / 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* create_rgb_table:
|
||||
* Fills an RGB_MAP lookup table with conversion data for the specified
|
||||
* palette. This is the faster version by Jan Hubicka.
|
||||
*
|
||||
* Uses alg. similar to floodfill - it adds one seed per every color in
|
||||
* palette to its best position. Then areas around seed are filled by
|
||||
* same color because it is best approximation for them, and then areas
|
||||
* about them etc...
|
||||
*
|
||||
* It does just about 80000 tests for distances and this is about 100
|
||||
* times better than normal 256*32000 tests so the calculation time
|
||||
* is now less than one second at all computers I tested.
|
||||
*/
|
||||
void create_rgb_table(RGB_MAP *table, AL_CONST PALETTE pal, void (*callback)(int pos)) {
|
||||
#define UNUSED 65535
|
||||
#define LAST 65532
|
||||
|
||||
/* macro add adds to single linked list */
|
||||
#define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
|
||||
(first != LAST ? (next[last] = (i)) : (first = (i))), \
|
||||
(last = (i))) : 0)
|
||||
|
||||
/* same but w/o checking for first element */
|
||||
#define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
|
||||
next[last] = (i), \
|
||||
(last = (i))) : 0)
|
||||
|
||||
/* calculates distance between two colors */
|
||||
#define dist(a1, a2, a3, b1, b2, b3) \
|
||||
(col_diff[ ((a2) - (b2)) & 0x7F] + \
|
||||
(col_diff + 128)[((a1) - (b1)) & 0x7F] + \
|
||||
(col_diff + 256)[((a3) - (b3)) & 0x7F])
|
||||
|
||||
/* converts r,g,b to position in array and back */
|
||||
#define pos(r, g, b) \
|
||||
(((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
|
||||
|
||||
#define depos(pal, r, g, b) \
|
||||
((b) = ((pal) & 31) * 2, \
|
||||
(g) = (((pal) >> 5) & 31) * 2, \
|
||||
(r) = (((pal) >> 10) & 31) * 2)
|
||||
|
||||
/* is current color better than pal1? */
|
||||
#define better(r1, g1, b1, pal1) \
|
||||
(((int)dist((r1), (g1), (b1), \
|
||||
(pal1).r, (pal1).g, (pal1).b)) > (int)dist2)
|
||||
|
||||
/* checking of position */
|
||||
#define dopos(rp, gp, bp, ts) \
|
||||
if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
|
||||
(gp > -1 || g > 0) && (gp < 1 || g < 61) && \
|
||||
(bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
|
||||
i = first + rp * 32 * 32 + gp * 32 + bp; \
|
||||
if (!data[i]) { \
|
||||
data[i] = val; \
|
||||
add1(i); \
|
||||
} \
|
||||
else if ((ts) && (data[i] != val)) { \
|
||||
dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
|
||||
(gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
|
||||
(bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
|
||||
if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
|
||||
data[i] = val; \
|
||||
add1(i); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
int i, curr, r, g, b, val, dist2;
|
||||
unsigned int r2, g2, b2;
|
||||
unsigned short next[32 * 32 * 32];
|
||||
unsigned char *data;
|
||||
int first = LAST;
|
||||
int last = LAST;
|
||||
int count = 0;
|
||||
int cbcount = 0;
|
||||
|
||||
#define AVERAGE_COUNT 18000
|
||||
|
||||
if (col_diff[1] == 0)
|
||||
bestfit_init();
|
||||
|
||||
memset(next, 255, sizeof(next));
|
||||
memset(table->data, 0, sizeof(char) * 32 * 32 * 32);
|
||||
|
||||
data = (unsigned char *)table->data;
|
||||
|
||||
/* add starting seeds for floodfill */
|
||||
for (i = 1; i < PAL_SIZE; i++) {
|
||||
curr = pos(pal[i].r, pal[i].g, pal[i].b);
|
||||
if (next[curr] == UNUSED) {
|
||||
data[curr] = i;
|
||||
add(curr);
|
||||
}
|
||||
}
|
||||
|
||||
/* main floodfill: two versions of loop for faster growing in blue axis */
|
||||
while (first != LAST) {
|
||||
depos(first, r, g, b);
|
||||
|
||||
/* calculate distance of current color */
|
||||
val = data[first];
|
||||
r2 = (col_diff + 128)[((pal[val].r) - (r)) & 0x7F];
|
||||
g2 = (col_diff)[((pal[val].g) - (g)) & 0x7F];
|
||||
b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7F];
|
||||
|
||||
/* try to grow to all directions */
|
||||
dopos(0, 0, 1, 1);
|
||||
dopos(0, 0, -1, 1);
|
||||
dopos(1, 0, 0, 1);
|
||||
dopos(-1, 0, 0, 1);
|
||||
dopos(0, 1, 0, 1);
|
||||
dopos(0, -1, 0, 1);
|
||||
|
||||
/* faster growing of blue direction */
|
||||
if ((b > 0) && (data[first - 1] == val)) {
|
||||
b -= 2;
|
||||
first--;
|
||||
b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7F];
|
||||
|
||||
dopos(-1, 0, 0, 0);
|
||||
dopos(1, 0, 0, 0);
|
||||
dopos(0, -1, 0, 0);
|
||||
dopos(0, 1, 0, 0);
|
||||
|
||||
first++;
|
||||
}
|
||||
|
||||
/* get next from list */
|
||||
i = first;
|
||||
first = next[first];
|
||||
next[i] = UNUSED;
|
||||
|
||||
/* second version of loop */
|
||||
if (first != LAST) {
|
||||
depos(first, r, g, b);
|
||||
|
||||
val = data[first];
|
||||
r2 = (col_diff + 128)[((pal[val].r) - (r)) & 0x7F];
|
||||
g2 = (col_diff)[((pal[val].g) - (g)) & 0x7F];
|
||||
b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7F];
|
||||
|
||||
dopos(0, 0, 1, 1);
|
||||
dopos(0, 0, -1, 1);
|
||||
dopos(1, 0, 0, 1);
|
||||
dopos(-1, 0, 0, 1);
|
||||
dopos(0, 1, 0, 1);
|
||||
dopos(0, -1, 0, 1);
|
||||
|
||||
if ((b < 61) && (data[first + 1] == val)) {
|
||||
b += 2;
|
||||
first++;
|
||||
b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7f];
|
||||
|
||||
dopos(-1, 0, 0, 0);
|
||||
dopos(1, 0, 0, 0);
|
||||
dopos(0, -1, 0, 0);
|
||||
dopos(0, 1, 0, 0);
|
||||
|
||||
first--;
|
||||
}
|
||||
|
||||
i = first;
|
||||
first = next[first];
|
||||
next[i] = UNUSED;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count == (cbcount + 1) * AVERAGE_COUNT / 256) {
|
||||
if (cbcount < 256) {
|
||||
if (callback)
|
||||
callback(cbcount);
|
||||
cbcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* only the transparent (pink) color can be mapped to index 0 */
|
||||
if ((pal[0].r == 63) && (pal[0].g == 0) && (pal[0].b == 63))
|
||||
table->data[31][0][31] = 0;
|
||||
|
||||
if (callback)
|
||||
while (cbcount < 256)
|
||||
callback(cbcount++);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* create_light_table:
|
||||
* Constructs a lighting color table for the specified palette. At light
|
||||
* intensity 255 the table will produce the palette colors directly, and
|
||||
* at level 0 it will produce the specified R, G, B value for all colors
|
||||
* (this is specified in 0-63 VGA format). If the callback function is
|
||||
* not NULL, it will be called 256 times during the calculation, allowing
|
||||
* you to display a progress indicator.
|
||||
*/
|
||||
void create_light_table(COLOR_MAP *table, AL_CONST PALETTE pal, int r, int g, int b, void (*callback)(int pos)) {
|
||||
int r1, g1, b1, r2, g2, b2, x, y;
|
||||
unsigned int t1, t2;
|
||||
|
||||
assert(table);
|
||||
assert(r >= 0 && r <= 63);
|
||||
assert(g >= 0 && g <= 63);
|
||||
assert(b >= 0 && b <= 63);
|
||||
|
||||
if (_G(rgb_map)) {
|
||||
for (x = 0; x < PAL_SIZE - 1; x++) {
|
||||
t1 = x * 0x010101;
|
||||
t2 = 0xFFFFFF - t1;
|
||||
|
||||
r1 = (1 << 24) + r * t2;
|
||||
g1 = (1 << 24) + g * t2;
|
||||
b1 = (1 << 24) + b * t2;
|
||||
|
||||
for (y = 0; y < PAL_SIZE; y++) {
|
||||
r2 = (r1 + pal[y].r * t1) >> 25;
|
||||
g2 = (g1 + pal[y].g * t1) >> 25;
|
||||
b2 = (b1 + pal[y].b * t1) >> 25;
|
||||
|
||||
table->data[x][y] = _G(rgb_map)->data[r2][g2][b2];
|
||||
}
|
||||
}
|
||||
if (callback)
|
||||
(*callback)(x);
|
||||
} else {
|
||||
for (x = 0; x < PAL_SIZE - 1; x++) {
|
||||
t1 = x * 0x010101;
|
||||
t2 = 0xFFFFFF - t1;
|
||||
|
||||
r1 = (1 << 23) + r * t2;
|
||||
g1 = (1 << 23) + g * t2;
|
||||
b1 = (1 << 23) + b * t2;
|
||||
|
||||
for (y = 0; y < PAL_SIZE; y++) {
|
||||
r2 = (r1 + pal[y].r * t1) >> 24;
|
||||
g2 = (g1 + pal[y].g * t1) >> 24;
|
||||
b2 = (b1 + pal[y].b * t1) >> 24;
|
||||
|
||||
table->data[x][y] = bestfit_color(pal, r2, g2, b2);
|
||||
}
|
||||
}
|
||||
|
||||
if (callback)
|
||||
(*callback)(x);
|
||||
}
|
||||
|
||||
for (y = 0; y < PAL_SIZE; y++)
|
||||
table->data[255][y] = y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* create_trans_table:
|
||||
* Constructs a translucency color table for the specified palette. The
|
||||
* r, g, and b parameters specifiy the solidity of each color component,
|
||||
* ranging from 0 (totally transparent) to 255 (totally solid). Source
|
||||
* color #0 is a special case, and is set to leave the destination
|
||||
* unchanged, so that masked sprites will draw correctly. If the callback
|
||||
* function is not NULL, it will be called 256 times during the calculation,
|
||||
* allowing you to display a progress indicator.
|
||||
*/
|
||||
void create_trans_table(COLOR_MAP *table, AL_CONST PALETTE pal, int r, int g, int b, void (*callback)(int pos)) {
|
||||
int tmp[768], *q;
|
||||
int x, y, i, j, k;
|
||||
unsigned char *p;
|
||||
int tr, tg, tb;
|
||||
int add;
|
||||
|
||||
assert(table);
|
||||
assert(r >= 0 && r <= 255);
|
||||
assert(g >= 0 && g <= 255);
|
||||
assert(b >= 0 && b <= 255);
|
||||
|
||||
/* This is a bit ugly, but accounts for the solidity parameters
|
||||
being in the range 0-255 rather than 0-256. Given that the
|
||||
precision of r,g,b components is only 6 bits it shouldn't do any
|
||||
harm. */
|
||||
if (r > 128)
|
||||
r++;
|
||||
if (g > 128)
|
||||
g++;
|
||||
if (b > 128)
|
||||
b++;
|
||||
|
||||
if (_G(rgb_map))
|
||||
add = 255;
|
||||
else
|
||||
add = 127;
|
||||
|
||||
for (x = 0; x < 256; x++) {
|
||||
tmp[x * 3] = pal[x].r * (256 - r) + add;
|
||||
tmp[x * 3 + 1] = pal[x].g * (256 - g) + add;
|
||||
tmp[x * 3 + 2] = pal[x].b * (256 - b) + add;
|
||||
}
|
||||
|
||||
for (x = 1; x < PAL_SIZE; x++) {
|
||||
i = pal[x].r * r;
|
||||
j = pal[x].g * g;
|
||||
k = pal[x].b * b;
|
||||
|
||||
p = table->data[x];
|
||||
q = tmp;
|
||||
|
||||
if (_G(rgb_map)) {
|
||||
for (y = 0; y < PAL_SIZE; y++) {
|
||||
tr = (i + * (q++)) >> 9;
|
||||
tg = (j + * (q++)) >> 9;
|
||||
tb = (k + * (q++)) >> 9;
|
||||
p[y] = _G(rgb_map)->data[tr][tg][tb];
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < PAL_SIZE; y++) {
|
||||
tr = (i + * (q++)) >> 8;
|
||||
tg = (j + * (q++)) >> 8;
|
||||
tb = (k + * (q++)) >> 8;
|
||||
p[y] = bestfit_color(pal, tr, tg, tb);
|
||||
}
|
||||
}
|
||||
|
||||
if (callback)
|
||||
(*callback)(x - 1);
|
||||
}
|
||||
|
||||
for (y = 0; y < PAL_SIZE; y++) {
|
||||
table->data[0][y] = y;
|
||||
table->data[y][y] = y;
|
||||
}
|
||||
|
||||
if (callback)
|
||||
(*callback)(255);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
155
engines/ags/lib/allegro/color.h
Normal file
155
engines/ags/lib/allegro/color.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_COLOR_H
|
||||
#define AGS_LIB_ALLEGRO_COLOR_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "ags/lib/allegro/base.h"
|
||||
#include "ags/lib/allegro/alconfig.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define PAL_SIZE 256
|
||||
#define MASK_COLOR_8 0
|
||||
#define MASK_COLOR_15 0x7C1F
|
||||
#define MASK_COLOR_16 0xF81F
|
||||
#define MASK_COLOR_24 0xFF00FF
|
||||
#define MASK_COLOR_32 0xFF00FF
|
||||
|
||||
class BITMAP;
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
struct color {
|
||||
byte r, g, b;
|
||||
byte filler;
|
||||
|
||||
void readFromFile(AGS::Shared::Stream *file);
|
||||
void writeToFile(AGS::Shared::Stream *file) const;
|
||||
void clear() {
|
||||
r = g = b = filler = 0;
|
||||
}
|
||||
} PACKED_STRUCT;
|
||||
|
||||
typedef color RGB;
|
||||
typedef RGB PALETTE[PAL_SIZE];
|
||||
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
struct RGB_MAP {
|
||||
byte data[32][32][32];
|
||||
};
|
||||
|
||||
struct COLOR_MAP {
|
||||
byte data[PAL_SIZE][PAL_SIZE];
|
||||
};
|
||||
|
||||
enum BlenderMode {
|
||||
kSourceAlphaBlender,
|
||||
kArgbToArgbBlender,
|
||||
kArgbToRgbBlender,
|
||||
kRgbToArgbBlender,
|
||||
kRgbToRgbBlender,
|
||||
kAlphaPreservedBlenderMode,
|
||||
kOpaqueBlenderMode,
|
||||
kAdditiveBlenderMode,
|
||||
kTintBlenderMode,
|
||||
kTintLightBlenderMode
|
||||
};
|
||||
|
||||
extern int makecol(byte r, byte g, byte b);
|
||||
|
||||
AL_ARRAY(const int, _rgb_scale_5);
|
||||
AL_ARRAY(const int, _rgb_scale_6);
|
||||
|
||||
AL_FUNC(void, set_palette, (AL_CONST PALETTE p));
|
||||
AL_FUNC(void, set_palette_range, (AL_CONST PALETTE p, int from, int to, int retracesync));
|
||||
|
||||
AL_FUNC(void, get_color, (int idx, RGB *p));
|
||||
AL_FUNC(void, get_palette, (PALETTE p));
|
||||
AL_FUNC(void, get_palette_range, (PALETTE p, int from, int to));
|
||||
|
||||
AL_FUNC(void, fade_interpolate, (AL_CONST PALETTE source, AL_CONST PALETTE dest, PALETTE output, int pos, int from, int to));
|
||||
|
||||
AL_FUNC(void, select_palette, (AL_CONST PALETTE p));
|
||||
AL_FUNC(void, unselect_palette, (void));
|
||||
|
||||
AL_FUNC(void, create_rgb_table, (RGB_MAP *table, AL_CONST PALETTE pal, AL_METHOD(void, callback, (int pos))));
|
||||
AL_FUNC(void, create_light_table, (COLOR_MAP *table, AL_CONST PALETTE pal, int r, int g, int b, AL_METHOD(void, callback, (int pos))));
|
||||
AL_FUNC(void, create_trans_table, (COLOR_MAP *table, AL_CONST PALETTE pal, int r, int g, int b, AL_METHOD(void, callback, (int pos))));
|
||||
|
||||
AL_FUNC(void, set_blender_mode, (BlenderMode, int r, int g, int b, int a));
|
||||
AL_FUNC(void, set_alpha_blender, (void));
|
||||
AL_FUNC(void, set_trans_blender, (int r, int g, int b, int a));
|
||||
|
||||
AL_FUNC(void, hsv_to_rgb, (float h, float s, float v, int *r, int *g, int *b));
|
||||
AL_FUNC(void, rgb_to_hsv, (int r, int g, int b, float *h, float *s, float *v));
|
||||
|
||||
AL_FUNC(int, bestfit_color, (AL_CONST PALETTE pal, int r, int g, int b));
|
||||
|
||||
AL_FUNC(int, makecol8, (int r, int g, int b));
|
||||
AL_FUNC(int, makecol_depth, (int color_depth, int r, int g, int b));
|
||||
|
||||
AL_FUNC(int, makeacol_depth, (int color_depth, int r, int g, int b, int a));
|
||||
|
||||
AL_FUNC(int, getr, (int c));
|
||||
AL_FUNC(int, getg, (int c));
|
||||
AL_FUNC(int, getb, (int c));
|
||||
AL_FUNC(int, geta, (int c));
|
||||
|
||||
AL_FUNC(int, getr_depth, (int color_depth, int c));
|
||||
AL_FUNC(int, getg_depth, (int color_depth, int c));
|
||||
AL_FUNC(int, getb_depth, (int color_depth, int c));
|
||||
AL_FUNC(int, geta_depth, (int color_depth, int c));
|
||||
|
||||
extern int makecol15(int r, int g, int b);
|
||||
extern int makecol16(int r, int g, int b);
|
||||
extern int makecol24(int r, int g, int b);
|
||||
extern int makecol32(int r, int g, int b);
|
||||
extern int makeacol32(int r, int g, int b, int a);
|
||||
extern int getr8(int c);
|
||||
extern int getg8(int c);
|
||||
extern int getb8(int c);
|
||||
extern int getr15(int c);
|
||||
extern int getg15(int c);
|
||||
extern int getb15(int c);
|
||||
extern int getr16(int c);
|
||||
extern int getg16(int c);
|
||||
extern int getb16(int c);
|
||||
extern int getr24(int c);
|
||||
extern int getg24(int c);
|
||||
extern int getb24(int c);
|
||||
extern int getr32(int c);
|
||||
extern int getg32(int c);
|
||||
extern int getb32(int c);
|
||||
extern int geta32(int c);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
31
engines/ags/lib/allegro/config.cpp
Normal file
31
engines/ags/lib/allegro/config.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/config.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
void override_config_data(const char *data, int length) {
|
||||
// No implementation
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
31
engines/ags/lib/allegro/config.h
Normal file
31
engines/ags/lib/allegro/config.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_CONFIG_H
|
||||
#define AGS_LIB_ALLEGRO_CONFIG_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
extern void override_config_data(const char *data, int length);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
115
engines/ags/lib/allegro/draw.cpp
Normal file
115
engines/ags/lib/allegro/draw.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/draw.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
void drawing_mode(int mode, BITMAP *pattern, int x_anchor, int y_anchor) {
|
||||
// TODO: Drawing mode
|
||||
}
|
||||
|
||||
void xor_mode(int on) {
|
||||
drawing_mode(on ? DRAW_MODE_XOR : DRAW_MODE_SOLID, NULL, 0, 0);
|
||||
}
|
||||
|
||||
void solid_mode(void) {
|
||||
drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
|
||||
}
|
||||
|
||||
void do_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int d, DrawMethod proc) {
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
int i1, i2;
|
||||
int x, y;
|
||||
int dd;
|
||||
|
||||
/* worker macro */
|
||||
#define DO_LINE(pri_sign, pri_c, pri_cond, sec_sign, sec_c, sec_cond) \
|
||||
{ \
|
||||
if (d##pri_c == 0) { \
|
||||
proc(bmp, x1, y1, d); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
i1 = 2 * d##sec_c; \
|
||||
dd = i1 - (sec_sign (pri_sign d##pri_c)); \
|
||||
i2 = dd - (sec_sign (pri_sign d##pri_c)); \
|
||||
\
|
||||
x = x1; \
|
||||
y = y1; \
|
||||
\
|
||||
while (pri_c pri_cond pri_c##2) { \
|
||||
proc(bmp, x, y, d); \
|
||||
\
|
||||
if (dd sec_cond 0) { \
|
||||
sec_c = sec_c sec_sign 1; \
|
||||
dd += i2; \
|
||||
} \
|
||||
else \
|
||||
dd += i1; \
|
||||
\
|
||||
pri_c = pri_c pri_sign 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
if (dx >= 0) {
|
||||
if (dy >= 0) {
|
||||
if (dx >= dy) {
|
||||
/* (x1 <= x2) && (y1 <= y2) && (dx >= dy) */
|
||||
DO_LINE(+, x, <= , +, y, >=);
|
||||
} else {
|
||||
/* (x1 <= x2) && (y1 <= y2) && (dx < dy) */
|
||||
DO_LINE(+, y, <= , +, x, >=);
|
||||
}
|
||||
} else {
|
||||
if (dx >= -dy) {
|
||||
/* (x1 <= x2) && (y1 > y2) && (dx >= dy) */
|
||||
DO_LINE(+, x, <= , -, y, <=);
|
||||
} else {
|
||||
/* (x1 <= x2) && (y1 > y2) && (dx < dy) */
|
||||
DO_LINE(-, y, >= , +, x, >=);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dy >= 0) {
|
||||
if (-dx >= dy) {
|
||||
/* (x1 > x2) && (y1 <= y2) && (dx >= dy) */
|
||||
DO_LINE(-, x, >= , +, y, >=);
|
||||
} else {
|
||||
/* (x1 > x2) && (y1 <= y2) && (dx < dy) */
|
||||
DO_LINE(+, y, <= , -, x, <=);
|
||||
}
|
||||
} else {
|
||||
if (-dx >= -dy) {
|
||||
/* (x1 > x2) && (y1 > y2) && (dx >= dy) */
|
||||
DO_LINE(-, x, >= , -, y, <=);
|
||||
} else {
|
||||
/* (x1 > x2) && (y1 > y2) && (dx < dy) */
|
||||
DO_LINE(-, y, >= , -, x, <=);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef DO_LINE
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
48
engines/ags/lib/allegro/draw.h
Normal file
48
engines/ags/lib/allegro/draw.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/base.h"
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "ags/lib/allegro/surface.h"
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_DRAW_H
|
||||
#define AGS_LIB_ALLEGRO_DRAW_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define DRAW_MODE_SOLID 0 /* flags for drawing_mode() */
|
||||
#define DRAW_MODE_XOR 1
|
||||
#define DRAW_MODE_COPY_PATTERN 2
|
||||
#define DRAW_MODE_SOLID_PATTERN 3
|
||||
#define DRAW_MODE_MASKED_PATTERN 4
|
||||
#define DRAW_MODE_TRANS 5
|
||||
|
||||
AL_FUNC(void, drawing_mode, (int mode, BITMAP *pattern, int x_anchor, int y_anchor));
|
||||
AL_FUNC(void, xor_mode, (int on));
|
||||
AL_FUNC(void, solid_mode, (void));
|
||||
|
||||
typedef void (*DrawMethod)(BITMAP *, int, int, int);
|
||||
|
||||
extern void do_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int d, DrawMethod proc);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
74
engines/ags/lib/allegro/error.h
Normal file
74
engines/ags/lib/allegro/error.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_ERROR_H
|
||||
#define AGS_LIB_ALLEGRO_ERROR_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Error codes
|
||||
enum AllegroError {
|
||||
AL_NOERROR = 0,
|
||||
AL_EPERM = 1,
|
||||
AL_ENOENT = 2,
|
||||
AL_ESRCH = 3,
|
||||
AL_EINTR = 4,
|
||||
AL_EIO = 5,
|
||||
AL_ENXIO = 6,
|
||||
AL_E2BIG = 7,
|
||||
AL_ENOEXEC = 8,
|
||||
AL_EBADF = 9,
|
||||
AL_ECHILD = 10,
|
||||
AL_EAGAIN = 11,
|
||||
AL_ENOMEM = 12,
|
||||
AL_EACCES = 13,
|
||||
AL_EFAULT = 14,
|
||||
AL_EBUSY = 16,
|
||||
AL_EEXIST = 17,
|
||||
AL_EXDEV = 18,
|
||||
AL_ENODEV = 19,
|
||||
AL_ENOTDIR = 20,
|
||||
AL_EISDIR = 21,
|
||||
AL_EINVAL = 22,
|
||||
AL_ENFILE = 23,
|
||||
AL_EMFILE = 24,
|
||||
AL_ENOTTY = 25,
|
||||
AL_EFBIG = 27,
|
||||
AL_ENOSPC = 28,
|
||||
AL_ESPIPE = 29,
|
||||
AL_EROFS = 30,
|
||||
AL_EMLINK = 31,
|
||||
AL_EPIPE = 32,
|
||||
AL_EDOM = 33,
|
||||
AL_ERANGE = 34,
|
||||
AL_EDEADLK = 36,
|
||||
AL_ENAMETOOLONG = 38,
|
||||
AL_ENOLCK = 39,
|
||||
AL_ENOSYS = 40,
|
||||
AL_ENOTEMPTY = 41,
|
||||
AL_EILSEQ = 42
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
261
engines/ags/lib/allegro/file.cpp
Normal file
261
engines/ags/lib/allegro/file.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/file.h"
|
||||
#include "common/file.h"
|
||||
#include "common/str.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
PACKFILE *PACKFILE::pack_fopen_chunk(int pack) {
|
||||
error("TODO: pack_fopen_chunk is not yet supported");
|
||||
}
|
||||
|
||||
PACKFILE *PACKFILE::pack_fclose_chunk() {
|
||||
error("TODO: pack_fclose_chunk is not yet supported");
|
||||
}
|
||||
|
||||
int PACKFILE::pack_igetw() {
|
||||
byte buf[2];
|
||||
return pack_fread(buf, 2) == 2 ? READ_LE_UINT16(buf) : 0;
|
||||
}
|
||||
|
||||
int32_t PACKFILE::pack_igetl() {
|
||||
byte buf[4];
|
||||
return pack_fread(buf, 4) == 4 ? READ_LE_UINT32(buf) : 0;
|
||||
}
|
||||
|
||||
int PACKFILE::pack_iputw(int w) {
|
||||
byte buf[2];
|
||||
WRITE_LE_UINT16(buf, w);
|
||||
pack_fwrite(buf, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t PACKFILE::pack_iputl(int32_t l) {
|
||||
byte buf[4];
|
||||
WRITE_LE_UINT32(buf, l);
|
||||
pack_fwrite(buf, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PACKFILE::pack_mgetw() {
|
||||
byte buf[2];
|
||||
return pack_fread(buf, 2) == 2 ? READ_BE_UINT16(buf) : 0;
|
||||
}
|
||||
|
||||
int32_t PACKFILE::pack_mgetl() {
|
||||
byte buf[4];
|
||||
return pack_fread(buf, 4) == 4 ? READ_BE_UINT32(buf) : 0;
|
||||
}
|
||||
|
||||
int PACKFILE::pack_mputw(int w) {
|
||||
byte buf[2];
|
||||
WRITE_BE_UINT16(buf, 2);
|
||||
pack_fwrite(buf, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t PACKFILE::pack_mputl(int32_t l) {
|
||||
byte buf[4];
|
||||
WRITE_BE_UINT16(buf, 4);
|
||||
pack_fwrite(buf, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *PACKFILE::pack_fgets(char *p, int max) {
|
||||
int c;
|
||||
char *dest = p;
|
||||
|
||||
while ((c = pack_getc()) != 0 && !pack_feof() && max-- > 0) {
|
||||
*dest++ = c;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int PACKFILE::pack_fputs(AL_CONST char *p) {
|
||||
pack_fwrite(p, strlen(p));
|
||||
pack_putc(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
/* Use strictly UTF-8 encoding for the file paths
|
||||
*/
|
||||
#define U_CURRENT U_UTF8
|
||||
#define ugetc utf8_getc
|
||||
#define ugetx utf8_getx
|
||||
#define ugetxc utf8_getx
|
||||
#define usetc utf8_setc
|
||||
#define uwidth utf8_width
|
||||
#define ucwidth utf8_cwidth
|
||||
#define uisok utf8_isok
|
||||
|
||||
void set_filename_encoding(int) {
|
||||
// No implementation
|
||||
}
|
||||
|
||||
char *fix_filename_case(char *path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
char *fix_filename_slashes(char *path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
char *append_filename(char *dest, const char *path, const char *filename, int size) {
|
||||
strncpy(dest, path, size);
|
||||
strncat(dest, filename, size);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *canonicalize_filename(char *dest, const char *filename, int size) {
|
||||
strncpy(dest, filename, size);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *make_relative_filename(char *dest, const char *path, const char *filename, int size) {
|
||||
strncpy(dest, filename, size);
|
||||
return dest;
|
||||
}
|
||||
|
||||
int is_relative_filename(const char *filename) {
|
||||
// ScummVM doesn't have absolute paths
|
||||
return true;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
void packfile_password(AL_CONST char *password) {
|
||||
error("TODO: packfile_password");
|
||||
}
|
||||
|
||||
PACKFILE *pack_fopen(AL_CONST char *filename, AL_CONST char *mode) {
|
||||
assert(!strcmp(mode, "r") || !strcmp(mode, "rb"));
|
||||
|
||||
Common::File *f = new Common::File();
|
||||
if (f->open(filename)) {
|
||||
return new ScummVMPackFile(f);
|
||||
|
||||
} else {
|
||||
delete f;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PACKFILE *pack_fopen_vtable(AL_CONST PACKFILE_VTABLE *vtable, void *userdata) {
|
||||
return new VTablePackFile(vtable, userdata);
|
||||
}
|
||||
|
||||
int pack_fclose(PACKFILE *f) {
|
||||
f->close();
|
||||
delete f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pack_fseek(PACKFILE *f, int offset) {
|
||||
return f->pack_fseek(offset);
|
||||
}
|
||||
|
||||
PACKFILE *pack_fopen_chunk(PACKFILE *f, int pack) {
|
||||
return f->pack_fopen_chunk(pack);
|
||||
}
|
||||
|
||||
PACKFILE *pack_fclose_chunk(PACKFILE *f) {
|
||||
return f->pack_fclose_chunk();
|
||||
}
|
||||
|
||||
int pack_getc(PACKFILE *f) {
|
||||
return f->pack_getc();
|
||||
}
|
||||
|
||||
int pack_putc(int c, PACKFILE *f) {
|
||||
return f->pack_putc(c);
|
||||
}
|
||||
|
||||
int pack_feof(PACKFILE *f) {
|
||||
return f->pack_feof();
|
||||
}
|
||||
|
||||
int pack_ferror(PACKFILE *f) {
|
||||
return f->pack_ferror();
|
||||
}
|
||||
|
||||
int pack_igetw(PACKFILE *f) {
|
||||
error("TODO: xxx");
|
||||
}
|
||||
|
||||
int32_t pack_igetl(PACKFILE *f) {
|
||||
return f->pack_igetl();
|
||||
}
|
||||
|
||||
int pack_iputw(int w, PACKFILE *f) {
|
||||
return f->pack_iputw(w);
|
||||
}
|
||||
|
||||
int32_t pack_iputl(int32_t l, PACKFILE *f) {
|
||||
return f->pack_iputl(l);
|
||||
}
|
||||
|
||||
int pack_mgetw(PACKFILE *f) {
|
||||
return f->pack_mgetw();
|
||||
}
|
||||
|
||||
int32_t pack_mgetl(PACKFILE *f) {
|
||||
return f->pack_mgetl();
|
||||
}
|
||||
|
||||
int pack_mputw(int w, PACKFILE *f) {
|
||||
return f->pack_mputw(w);
|
||||
}
|
||||
|
||||
int32_t pack_mputl(int32_t l, PACKFILE *f) {
|
||||
return f->pack_mputl(l);
|
||||
}
|
||||
|
||||
long pack_fread(void *p, long n, PACKFILE *f) {
|
||||
return f->pack_fread(p, n);
|
||||
}
|
||||
|
||||
long pack_fwrite(AL_CONST void *p, long n, PACKFILE *f) {
|
||||
return f->pack_fwrite(p, n);
|
||||
}
|
||||
|
||||
int pack_ungetc(int c, PACKFILE *f) {
|
||||
return f->pack_ungetc(c);
|
||||
}
|
||||
|
||||
char *pack_fgets(char *p, int max, PACKFILE *f) {
|
||||
return f->pack_fgets(p, max);
|
||||
}
|
||||
|
||||
int pack_fputs(AL_CONST char *p, PACKFILE *f) {
|
||||
return f->pack_fputs(p);
|
||||
}
|
||||
|
||||
void *pack_get_userdata(PACKFILE *f) {
|
||||
return f->pack_get_userdata();
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
227
engines/ags/lib/allegro/file.h
Normal file
227
engines/ags/lib/allegro/file.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_FILE_H
|
||||
#define AGS_LIB_ALLEGRO_FILE_H
|
||||
|
||||
#include "ags/lib/allegro/alconfig.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define F_READ "r"
|
||||
#define F_WRITE "w"
|
||||
|
||||
#define F_BUF_SIZE 4096 /* 4K buffer for caching data */
|
||||
|
||||
struct _al_normal_packfile_details {
|
||||
int hndl; /* DOS file handle */
|
||||
int flags; /* PACKFILE_FLAG_* constants */
|
||||
unsigned char *buf_pos; /* position in buffer */
|
||||
int buf_size; /* number of bytes in the buffer */
|
||||
long todo; /* number of bytes still on the disk */
|
||||
struct PACKFILE *parent; /* nested, parent file */
|
||||
char *filename; /* name of the file */
|
||||
unsigned char buf[F_BUF_SIZE]; /* the actual data buffer */
|
||||
};
|
||||
|
||||
struct PACKFILE_VTABLE {
|
||||
AL_METHOD(int, pf_fclose, (void *userdata));
|
||||
AL_METHOD(int, pf_getc, (void *userdata));
|
||||
AL_METHOD(int, pf_ungetc, (int c, void *userdata));
|
||||
AL_METHOD(long, pf_fread, (void *p, long n, void *userdata));
|
||||
AL_METHOD(int, pf_putc, (int c, void *userdata));
|
||||
AL_METHOD(long, pf_fwrite, (AL_CONST void *p, long n, void *userdata));
|
||||
AL_METHOD(int, pf_fseek, (void *userdata, int offset));
|
||||
AL_METHOD(int, pf_feof, (void *userdata));
|
||||
AL_METHOD(int, pf_ferror, (void *userdata));
|
||||
};
|
||||
|
||||
/**
|
||||
* Allegro file class
|
||||
*/
|
||||
struct PACKFILE {
|
||||
virtual ~PACKFILE() {
|
||||
close();
|
||||
}
|
||||
|
||||
virtual void close() {}
|
||||
virtual int pack_fseek(int offset) = 0;
|
||||
virtual int pack_getc() = 0;
|
||||
virtual int pack_putc(int c) = 0;
|
||||
virtual int pack_ungetc(int c) = 0;
|
||||
virtual long pack_fread(void *p, long n) = 0;
|
||||
virtual long pack_fwrite(AL_CONST void *p, long n) = 0;
|
||||
virtual int pack_feof() = 0;
|
||||
virtual int pack_ferror() = 0;
|
||||
virtual void *pack_get_userdata() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PACKFILE *pack_fopen_chunk(int pack);
|
||||
PACKFILE *pack_fclose_chunk();
|
||||
int pack_igetw();
|
||||
int32_t pack_igetl();
|
||||
int pack_iputw(int w);
|
||||
int32_t pack_iputl(int32_t l);
|
||||
int pack_mgetw();
|
||||
int32_t pack_mgetl();
|
||||
int pack_mputw(int w);
|
||||
int32_t pack_mputl(int32_t l);
|
||||
char *pack_fgets(char *p, int max);
|
||||
int pack_fputs(AL_CONST char *p);
|
||||
};
|
||||
|
||||
struct ScummVMPackFile : public PACKFILE {
|
||||
public:
|
||||
Common::SeekableReadStream *_stream;
|
||||
|
||||
ScummVMPackFile(Common::SeekableReadStream *rs) : PACKFILE(), _stream(rs) {
|
||||
}
|
||||
|
||||
virtual ~ScummVMPackFile() {}
|
||||
|
||||
void close() override {
|
||||
delete _stream;
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
int pack_fseek(int offset) override {
|
||||
return _stream->seek(offset, SEEK_CUR);
|
||||
}
|
||||
|
||||
int pack_getc() override {
|
||||
return _stream->readByte();
|
||||
}
|
||||
|
||||
int pack_putc(int c) override {
|
||||
error("pack_putc is not yet supported");
|
||||
}
|
||||
|
||||
int pack_ungetc(int c) override {
|
||||
_stream->seek(-1, SEEK_CUR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
long pack_fread(void *p, long n) override {
|
||||
return _stream->read(p, n);
|
||||
}
|
||||
|
||||
long pack_fwrite(AL_CONST void *p, long n) override {
|
||||
error("pack_fwrite is not yet supported");
|
||||
}
|
||||
|
||||
int pack_feof() override {
|
||||
return _stream->eos();
|
||||
}
|
||||
|
||||
int pack_ferror() override {
|
||||
return _stream->err();
|
||||
}
|
||||
};
|
||||
|
||||
struct VTablePackFile : public PACKFILE {
|
||||
AL_CONST PACKFILE_VTABLE *_vTable;
|
||||
void *_userData;
|
||||
|
||||
VTablePackFile(AL_CONST PACKFILE_VTABLE *vTable, void *userData) :
|
||||
_vTable(vTable), _userData(userData) {
|
||||
}
|
||||
|
||||
void close() override {
|
||||
_vTable->pf_fclose(_userData);
|
||||
}
|
||||
|
||||
int pack_fseek(int offset) override {
|
||||
return _vTable->pf_fseek(_userData, offset);
|
||||
}
|
||||
|
||||
int pack_getc() override {
|
||||
return _vTable->pf_getc(_userData);
|
||||
}
|
||||
|
||||
int pack_putc(int c) override {
|
||||
return _vTable->pf_putc(c, _userData);
|
||||
}
|
||||
|
||||
int pack_ungetc(int c) override {
|
||||
return _vTable->pf_ungetc(c, _userData);
|
||||
}
|
||||
|
||||
long pack_fread(void *p, long n) override {
|
||||
return _vTable->pf_fread(p, n, _userData);
|
||||
}
|
||||
|
||||
long pack_fwrite(AL_CONST void *p, long n) override {
|
||||
return _vTable->pf_fwrite(p, n, _userData);
|
||||
}
|
||||
|
||||
int pack_feof() override {
|
||||
return _vTable->pf_feof(_userData);
|
||||
}
|
||||
|
||||
int pack_ferror() override {
|
||||
return _vTable->pf_ferror(_userData);
|
||||
}
|
||||
|
||||
void *pack_get_userdata() const override {
|
||||
return _userData;
|
||||
}
|
||||
};
|
||||
|
||||
extern void set_filename_encoding(int);
|
||||
extern char *fix_filename_case(char *path);
|
||||
extern char *fix_filename_slashes(char *path);
|
||||
extern char *append_filename(char *dest, const char *path, const char *filename, int size);
|
||||
extern char *canonicalize_filename(char *dest, const char *filename, int size);
|
||||
extern char *make_relative_filename(char *dest, const char *path, const char *filename, int size);
|
||||
extern int is_relative_filename(const char *filename);
|
||||
|
||||
AL_FUNC(void, packfile_password, (AL_CONST char *password));
|
||||
AL_FUNC(PACKFILE *, pack_fopen, (AL_CONST char *filename, AL_CONST char *mode));
|
||||
AL_FUNC(PACKFILE *, pack_fopen_vtable, (AL_CONST PACKFILE_VTABLE *vtable, void *userdata));
|
||||
AL_FUNC(int, pack_fclose, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_fseek, (PACKFILE *f, int offset));
|
||||
AL_FUNC(PACKFILE *, pack_fopen_chunk, (PACKFILE *f, int pack));
|
||||
AL_FUNC(PACKFILE *, pack_fclose_chunk, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_getc, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_putc, (int c, PACKFILE *f));
|
||||
AL_FUNC(int, pack_feof, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_ferror, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_igetw, (PACKFILE *f));
|
||||
AL_FUNC(int32_t, pack_igetl, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_iputw, (int w, PACKFILE *f));
|
||||
AL_FUNC(int32_t, pack_iputl, (int32_t l, PACKFILE *f));
|
||||
AL_FUNC(int, pack_mgetw, (PACKFILE *f));
|
||||
AL_FUNC(int32_t, pack_mgetl, (PACKFILE *f));
|
||||
AL_FUNC(int, pack_mputw, (int w, PACKFILE *f));
|
||||
AL_FUNC(int32_t, pack_mputl, (int32_t l, PACKFILE *f));
|
||||
AL_FUNC(long, pack_fread, (void *p, long n, PACKFILE *f));
|
||||
AL_FUNC(long, pack_fwrite, (AL_CONST void *p, long n, PACKFILE *f));
|
||||
AL_FUNC(int, pack_ungetc, (int c, PACKFILE *f));
|
||||
AL_FUNC(char *, pack_fgets, (char *p, int max, PACKFILE *f));
|
||||
AL_FUNC(int, pack_fputs, (AL_CONST char *p, PACKFILE *f));
|
||||
AL_FUNC(void *, pack_get_userdata, (PACKFILE *f));
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
174
engines/ags/lib/allegro/fixed.cpp
Normal file
174
engines/ags/lib/allegro/fixed.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/fixed.h"
|
||||
#include "ags/lib/allegro/error.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
fixed ftofix(double x) {
|
||||
if (x > 32767.0) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
if (x < -32767.0) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return (fixed) - 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
return (fixed)(x * 65536.0 + (x < 0 ? -0.5 : 0.5));
|
||||
}
|
||||
|
||||
double fixtof(fixed x) {
|
||||
return (double)x / 65536.0;
|
||||
}
|
||||
|
||||
fixed fixadd(fixed x, fixed y) {
|
||||
fixed result = x + y;
|
||||
|
||||
if (result >= 0) {
|
||||
if ((x < 0) && (y < 0)) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return (fixed) - 0x7FFFFFFF;
|
||||
} else
|
||||
return result;
|
||||
} else {
|
||||
if ((x > 0) && (y > 0)) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
} else
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
fixed fixsub(fixed x, fixed y) {
|
||||
fixed result = x - y;
|
||||
|
||||
if (result >= 0) {
|
||||
if ((x < 0) && (y > 0)) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return (fixed) - 0x7FFFFFFF;
|
||||
} else
|
||||
return result;
|
||||
} else {
|
||||
if ((x > 0) && (y < 0)) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
} else
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
fixed fixmul(fixed x, fixed y) {
|
||||
int64 lx = x;
|
||||
int64 ly = y;
|
||||
int64 lres = (lx * ly);
|
||||
|
||||
if (lres > 0x7FFFFFFF0000LL) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
} else if (lres < -0x7FFFFFFF0000LL) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return 0x80000000;
|
||||
} else {
|
||||
int res = lres >> 16;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
fixed fixdiv(fixed x, fixed y) {
|
||||
if (y == 0) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return (fixed)(x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF;
|
||||
} else
|
||||
return ftofix(fixtof(x) / fixtof(y));
|
||||
}
|
||||
|
||||
int fixfloor(fixed x) {
|
||||
// FIXME: GCC warning "this condition has identical branches [-Wduplicated-branches]" on this code i.e. both branches are functionally identical. Remove?
|
||||
#if 0
|
||||
/* (x >> 16) is not portable */
|
||||
if (x >= 0)
|
||||
return (x >> 16);
|
||||
else
|
||||
return ~((~x) >> 16);
|
||||
#else
|
||||
return (x >> 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int fixceil(fixed x) {
|
||||
if (x > 0x7FFF0000) {
|
||||
*_G(allegro_errno) = AL_ERANGE;
|
||||
return 0x7FFF;
|
||||
}
|
||||
|
||||
return fixfloor(x + 0xFFFF);
|
||||
}
|
||||
|
||||
fixed itofix(int x) {
|
||||
return x << 16;
|
||||
}
|
||||
|
||||
|
||||
int fixtoi(fixed x) {
|
||||
return fixfloor(x) + ((x & 0x8000) >> 15);
|
||||
}
|
||||
|
||||
|
||||
fixed fixcos(fixed x) {
|
||||
return _cos_tbl[((x + 0x4000) >> 15) & 0x1FF];
|
||||
}
|
||||
|
||||
|
||||
fixed fixsin(fixed x) {
|
||||
return _cos_tbl[((x - 0x400000 + 0x4000) >> 15) & 0x1FF];
|
||||
}
|
||||
|
||||
|
||||
fixed fixtan(fixed x) {
|
||||
return _tan_tbl[((x + 0x4000) >> 15) & 0xFF];
|
||||
}
|
||||
|
||||
|
||||
fixed fixacos(fixed x) {
|
||||
if ((x < -65536) || (x > 65536)) {
|
||||
*_G(allegro_errno) = AL_EDOM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _acos_tbl[(x + 65536 + 127) >> 8];
|
||||
}
|
||||
|
||||
|
||||
fixed fixasin(fixed x) {
|
||||
if ((x < -65536) || (x > 65536)) {
|
||||
*_G(allegro_errno) = AL_EDOM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0x00400000 - _acos_tbl[(x + 65536 + 127) >> 8];
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
54
engines/ags/lib/allegro/fixed.h
Normal file
54
engines/ags/lib/allegro/fixed.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_FIXED_H
|
||||
#define AGS_LIB_ALLEGRO_FIXED_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
typedef int32_t fixed;
|
||||
|
||||
extern const fixed _cos_tbl[];
|
||||
extern const fixed _tan_tbl[];
|
||||
extern const fixed _acos_tbl[];
|
||||
|
||||
extern fixed ftofix(double x);
|
||||
extern double fixtof(fixed x);
|
||||
extern fixed fixadd(fixed x, fixed y);
|
||||
extern fixed fixsub(fixed x, fixed y);
|
||||
extern fixed fixmul(fixed x, fixed y);
|
||||
extern fixed fixdiv(fixed x, fixed y);
|
||||
extern int fixfloor(fixed x);
|
||||
extern int fixceil(fixed x);
|
||||
extern fixed itofix(int x);
|
||||
extern int fixtoi(fixed x);
|
||||
extern fixed fixcos(fixed x);
|
||||
extern fixed fixsin(fixed x);
|
||||
extern fixed fixtan(fixed x);
|
||||
extern fixed fixacos(fixed x);
|
||||
extern fixed fixasin(fixed x);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
233
engines/ags/lib/allegro/flood.cpp
Normal file
233
engines/ags/lib/allegro/flood.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/flood.h"
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
struct FLOODED_LINE {
|
||||
short flags; /* status of the segment */
|
||||
short lpos, rpos; /* left and right ends of segment */
|
||||
short y; /* y coordinate of the segment */
|
||||
int next; /* linked list if several per line */
|
||||
};
|
||||
|
||||
#define FLOOD_IN_USE 1
|
||||
#define FLOOD_TODO_ABOVE 2
|
||||
#define FLOOD_TODO_BELOW 4
|
||||
|
||||
#define FLOOD_LINE(c) (&scratchMem[c])
|
||||
|
||||
template<class SIZE>
|
||||
static bool scanLine(BITMAP *bmp, int x, int y, int src_color, int &left, int &right) {
|
||||
// check start pixel
|
||||
const SIZE *pixel = (const SIZE *)bmp->getBasePtr(x, y);
|
||||
if (*pixel != src_color)
|
||||
return false;
|
||||
|
||||
// Work left from starting point
|
||||
const SIZE *pixelLeft = pixel - 1;
|
||||
for (left = x - 1; left >= bmp->cl; left--, pixelLeft--) {
|
||||
if (*pixelLeft != src_color)
|
||||
break;
|
||||
}
|
||||
|
||||
// Work right from starting point
|
||||
const SIZE *pixelRight = pixel + 1;
|
||||
for (right = x + 1; right < bmp->cr; right++, pixelRight++) {
|
||||
if (*pixelRight != src_color)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills a horizontal line around the specified position, and adds it
|
||||
* to the list of drawn segments. Returns the first x coordinate after
|
||||
* the part of the line which it has dealt with.
|
||||
*/
|
||||
static int flooder(BITMAP *bmp, int x, int y, int src_color, int dest_color,
|
||||
Common::Array<FLOODED_LINE> &scratchMem) {
|
||||
FLOODED_LINE *p;
|
||||
int left = 0, right = 0;
|
||||
int c;
|
||||
|
||||
assert(bmp);
|
||||
|
||||
bool ret;
|
||||
switch (bmp->format.bytesPerPixel) {
|
||||
case 1:
|
||||
ret = scanLine<byte>(bmp, x, y, src_color, left, right);
|
||||
break;
|
||||
case 2:
|
||||
ret = scanLine<byte>(bmp, x, y, src_color, left, right);
|
||||
break;
|
||||
case 4:
|
||||
ret = scanLine<byte>(bmp, x, y, src_color, left, right);
|
||||
break;
|
||||
default:
|
||||
error("Unknown format");
|
||||
}
|
||||
if (!ret)
|
||||
return x + 1;
|
||||
|
||||
left++;
|
||||
right--;
|
||||
|
||||
/* draw the line */
|
||||
bmp->hLine(left, y, right, dest_color);
|
||||
|
||||
/* store it in the list of flooded segments */
|
||||
c = y;
|
||||
p = FLOOD_LINE(c);
|
||||
|
||||
if (p->flags) {
|
||||
while (p->next) {
|
||||
c = p->next;
|
||||
p = FLOOD_LINE(c);
|
||||
}
|
||||
|
||||
p->next = c = scratchMem.size();
|
||||
scratchMem.resize(scratchMem.size() + 1);
|
||||
p = FLOOD_LINE(c);
|
||||
}
|
||||
|
||||
p->flags = FLOOD_IN_USE;
|
||||
p->lpos = left;
|
||||
p->rpos = right;
|
||||
p->y = y;
|
||||
p->next = 0;
|
||||
|
||||
if (y > bmp->ct)
|
||||
p->flags |= FLOOD_TODO_ABOVE;
|
||||
|
||||
if (y + 1 < bmp->cb)
|
||||
p->flags |= FLOOD_TODO_BELOW;
|
||||
|
||||
return right + 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Checks a line segment, using the scratch buffer is to store a list of
|
||||
* segments which have already been drawn in order to minimise the required
|
||||
* number of tests.
|
||||
*/
|
||||
static bool check_flood_line(BITMAP *bmp, int y, int left, int right, int src_color, int dest_color,
|
||||
Common::Array<FLOODED_LINE> &scratchMem) {
|
||||
int c;
|
||||
FLOODED_LINE *p;
|
||||
bool ret = false;
|
||||
|
||||
while (left <= right) {
|
||||
c = y;
|
||||
|
||||
for (;;) {
|
||||
p = FLOOD_LINE(c);
|
||||
|
||||
if ((left >= p->lpos) && (left <= p->rpos)) {
|
||||
left = p->rpos + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
c = p->next;
|
||||
|
||||
if (!c) {
|
||||
left = flooder(bmp, left, y, src_color, dest_color, scratchMem);
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void floodfill(BITMAP *bmp, int x, int y, int color) {
|
||||
int src_color;
|
||||
int c;
|
||||
bool done;
|
||||
FLOODED_LINE *p;
|
||||
Common::Array<FLOODED_LINE> scratchMem;
|
||||
|
||||
/* make sure we have a valid starting point */
|
||||
if ((x < bmp->cl) || (x >= bmp->cr) || (y < bmp->ct) || (y >= bmp->cb))
|
||||
return;
|
||||
|
||||
/* what color to replace? */
|
||||
src_color = getpixel(bmp, x, y);
|
||||
if (src_color == color) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* set up the list of flooded segments */
|
||||
scratchMem.resize(bmp->cb);
|
||||
|
||||
p = FLOOD_LINE(0);
|
||||
for (c = 0; c < (int)scratchMem.size(); c++) {
|
||||
p[c].flags = 0;
|
||||
p[c].lpos = INT16_MAX;
|
||||
p[c].rpos = INT16_MIN;
|
||||
p[c].y = y;
|
||||
p[c].next = 0;
|
||||
}
|
||||
|
||||
/* start up the flood algorithm */
|
||||
flooder(bmp, x, y, src_color, color, scratchMem);
|
||||
|
||||
/* continue as long as there are some segments still to test */
|
||||
do {
|
||||
done = true;
|
||||
|
||||
/* for each line on the screen */
|
||||
for (c = 0; c < (int)scratchMem.size(); c++) {
|
||||
p = FLOOD_LINE(c);
|
||||
|
||||
/* check below the segment? */
|
||||
if (p->flags & FLOOD_TODO_BELOW) {
|
||||
p->flags &= ~FLOOD_TODO_BELOW;
|
||||
if (check_flood_line(bmp, p->y + 1, p->lpos, p->rpos, src_color, color, scratchMem)) {
|
||||
done = false;
|
||||
p = FLOOD_LINE(c);
|
||||
}
|
||||
}
|
||||
|
||||
/* check above the segment? */
|
||||
if (p->flags & FLOOD_TODO_ABOVE) {
|
||||
p->flags &= ~FLOOD_TODO_ABOVE;
|
||||
if (check_flood_line(bmp, p->y - 1, p->lpos, p->rpos, src_color, color, scratchMem)) {
|
||||
done = false;
|
||||
/* special case shortcut for going backwards */
|
||||
if ((c < bmp->cb) && (c > 0))
|
||||
c -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
36
engines/ags/lib/allegro/flood.h
Normal file
36
engines/ags/lib/allegro/flood.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_FLOOD_H
|
||||
#define AGS_LIB_ALLEGRO_FLOOD_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ags/lib/allegro/base.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
class BITMAP;
|
||||
|
||||
extern void floodfill(BITMAP *bmp, int x, int y, int color);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
99
engines/ags/lib/allegro/fmaths.cpp
Normal file
99
engines/ags/lib/allegro/fmaths.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/fmaths.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
fixed fixsqrt(fixed x) {
|
||||
if (x > 0)
|
||||
return ftofix(sqrt(fixtof(x)));
|
||||
|
||||
if (x < 0)
|
||||
*allegro_errno = EDOM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fixed fixhypot(fixed x, fixed y) {
|
||||
return ftofix(hypot(fixtof(x), fixtof(y)));
|
||||
}
|
||||
|
||||
fixed fixatan(fixed x) {
|
||||
int a, b, c; /* for binary search */
|
||||
fixed d; /* difference value for search */
|
||||
|
||||
if (x >= 0) { /* search the first part of tan table */
|
||||
a = 0;
|
||||
b = 127;
|
||||
} else { /* search the second half instead */
|
||||
a = 128;
|
||||
b = 255;
|
||||
}
|
||||
|
||||
do {
|
||||
c = (a + b) >> 1;
|
||||
d = x - _tan_tbl[c];
|
||||
|
||||
if (d > 0)
|
||||
a = c + 1;
|
||||
else if (d < 0)
|
||||
b = c - 1;
|
||||
|
||||
} while ((a <= b) && (d));
|
||||
|
||||
if (x >= 0)
|
||||
return ((long)c) << 15;
|
||||
|
||||
return (-0x00800000L + (((long)c) << 15));
|
||||
}
|
||||
|
||||
fixed fixatan2(fixed y, fixed x) {
|
||||
fixed r;
|
||||
|
||||
if (x == 0) {
|
||||
if (y == 0) {
|
||||
*allegro_errno = EDOM;
|
||||
return 0L;
|
||||
} else
|
||||
return ((y < 0) ? -0x00400000L : 0x00400000L);
|
||||
}
|
||||
|
||||
*allegro_errno = 0;
|
||||
r = fixdiv(y, x);
|
||||
|
||||
if (*allegro_errno) {
|
||||
*allegro_errno = 0;
|
||||
return ((y < 0) ? -0x00400000L : 0x00400000L);
|
||||
}
|
||||
|
||||
r = fixatan(r);
|
||||
|
||||
if (x >= 0)
|
||||
return r;
|
||||
|
||||
if (y >= 0)
|
||||
return 0x00800000L + r;
|
||||
|
||||
return r - 0x00800000L;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
40
engines/ags/lib/allegro/fmaths.h
Normal file
40
engines/ags/lib/allegro/fmaths.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_FMATHS_H
|
||||
#define AGS_LIB_ALLEGRO_FMATHS_H
|
||||
|
||||
#include "ags/lib/allegro/fixed.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
AL_FUNC(fixed, fixsqrt, (fixed x));
|
||||
AL_FUNC(fixed, fixhypot, (fixed x, fixed y));
|
||||
AL_FUNC(fixed, fixatan, (fixed x));
|
||||
AL_FUNC(fixed, fixatan2, (fixed y, fixed x));
|
||||
|
||||
AL_ARRAY(const fixed, _cos_tbl);
|
||||
AL_ARRAY(const fixed, _tan_tbl);
|
||||
AL_ARRAY(const fixed, _acos_tbl);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
390
engines/ags/lib/allegro/gfx.cpp
Normal file
390
engines/ags/lib/allegro/gfx.cpp
Normal file
@@ -0,0 +1,390 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/lib/allegro/flood.h"
|
||||
#include "ags/lib/allegro/rotate.h"
|
||||
#include "ags/ags.h"
|
||||
#include "ags/globals.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/util.h"
|
||||
#include "graphics/screen.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
int color_conversion;
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
void set_color_conversion(int mode) {
|
||||
color_conversion = mode;
|
||||
}
|
||||
|
||||
int get_color_conversion() {
|
||||
return color_conversion;
|
||||
}
|
||||
|
||||
int set_gfx_mode(int card, int w, int h, int depth) {
|
||||
// Graphics shutdown can be ignored
|
||||
if (card != -1) {
|
||||
assert(card == SCUMMVM_ID);
|
||||
::AGS::g_vm->setGraphicsMode(w, h, depth);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_clip_rect(BITMAP *bitmap, int x1, int y1, int x2, int y2) {
|
||||
// The rect passed to the function in inclusive-inclusive, but
|
||||
// internally the clipping rect in BITMAP is inclusive-exclusive.
|
||||
bitmap->cl = CLIP(x1, 0, (int)bitmap->w - 1);
|
||||
bitmap->ct = CLIP(y1, 0, (int)bitmap->h - 1);
|
||||
bitmap->cr = CLIP(x2 + 1, 0, (int)bitmap->w);
|
||||
bitmap->cb = CLIP(y2 + 1, 0, (int)bitmap->h);
|
||||
}
|
||||
|
||||
void get_clip_rect(BITMAP *bitmap, int *x1, int *y1, int *x2, int *y2) {
|
||||
if (x1)
|
||||
*x1 = bitmap->cl;
|
||||
if (y1)
|
||||
*y1 = bitmap->ct;
|
||||
if (x2)
|
||||
*x2 = bitmap->cr - 1;
|
||||
if (y2)
|
||||
*y2 = bitmap->cb - 1;
|
||||
}
|
||||
|
||||
void acquire_bitmap(BITMAP *bitmap) {
|
||||
// No implementation needed
|
||||
}
|
||||
|
||||
void release_bitmap(BITMAP *bitmap) {
|
||||
// No implementation needed
|
||||
}
|
||||
|
||||
void clear_to_color(BITMAP *bitmap, int color) {
|
||||
Graphics::ManagedSurface &surf = **bitmap;
|
||||
|
||||
surf.clear(color);
|
||||
}
|
||||
|
||||
int bitmap_color_depth(BITMAP *bmp) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
|
||||
return (surf.format.bytesPerPixel == 1) ? 8 : surf.format.bpp();
|
||||
}
|
||||
|
||||
int bitmap_mask_color(BITMAP *bmp) {
|
||||
// For paletted sprites this is 0.
|
||||
// For other color depths this is bright pink (RGB 255, 0, 255).
|
||||
// The alpha chanel should be 0.
|
||||
//if (bmp-format.bytesPerPixel == 1)
|
||||
// return 0;
|
||||
//return bmp->format.AGRBToColor(0, 255, 0, 255);
|
||||
return bmp->getTransparentColor();
|
||||
}
|
||||
|
||||
void blit(const BITMAP *src, BITMAP *dest, int src_x, int src_y, int dst_x, int dst_y, int width, int height) {
|
||||
dest->draw(src, Common::Rect(src_x, src_y, src_x + width, src_y + height),
|
||||
dst_x, dst_y, false, false, false, -1);
|
||||
}
|
||||
|
||||
void stretch_blit(const BITMAP *src, BITMAP *dest,
|
||||
int source_x, int source_y, int source_width, int source_height,
|
||||
int dest_x, int dest_y, int dest_width, int dest_height) {
|
||||
dest->stretchDraw(src,
|
||||
Common::Rect(source_x, source_y, source_x + source_width, source_y + source_height),
|
||||
Common::Rect(dest_x, dest_y, dest_x + dest_width, dest_y + dest_height),
|
||||
false, -1);
|
||||
}
|
||||
|
||||
void masked_blit(const BITMAP *src, BITMAP *dest, int src_x, int src_y, int dst_x, int dst_y, int width, int height) {
|
||||
assert(src->format == dest->format);
|
||||
|
||||
dest->draw(src, Common::Rect(src_x, src_y, src_x + width, src_y + height),
|
||||
dst_x, dst_y, false, false, true, -1);
|
||||
}
|
||||
|
||||
void masked_stretch_blit(const BITMAP *src, BITMAP *dest,
|
||||
int source_x, int source_y, int source_width, int source_height,
|
||||
int dest_x, int dest_y, int dest_width, int dest_height) {
|
||||
dest->stretchDraw(src,
|
||||
Common::Rect(source_x, source_y, source_x + source_width, source_y + source_height),
|
||||
Common::Rect(dest_x, dest_y, dest_x + dest_width, dest_y + dest_height),
|
||||
true, -1);
|
||||
}
|
||||
|
||||
void draw_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y) {
|
||||
bmp->draw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
x, y, false, false, true, -1);
|
||||
}
|
||||
|
||||
void stretch_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, int w, int h) {
|
||||
bmp->stretchDraw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
Common::Rect(x, y, x + w, y + h),
|
||||
true, -1);
|
||||
}
|
||||
|
||||
void draw_trans_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y) {
|
||||
bmp->draw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
x, y, false, false, true, _G(trans_blend_alpha));
|
||||
}
|
||||
|
||||
void draw_lit_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, int color) {
|
||||
bmp->draw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
x, y, false, false, true, color,
|
||||
_G(trans_blend_red), _G(trans_blend_green), _G(trans_blend_blue));
|
||||
}
|
||||
|
||||
void draw_sprite_h_flip(BITMAP *bmp, const BITMAP *sprite, int x, int y) {
|
||||
bmp->draw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
x, y, true, false, true, -1);
|
||||
}
|
||||
|
||||
void draw_sprite_v_flip(BITMAP *bmp, const BITMAP *sprite, int x, int y) {
|
||||
bmp->draw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
x, y, false, true, true, -1);
|
||||
}
|
||||
|
||||
void draw_sprite_vh_flip(BITMAP *bmp, const BITMAP *sprite, int x, int y) {
|
||||
bmp->draw(sprite, Common::Rect(0, 0, sprite->w, sprite->h),
|
||||
x, y, true, true, true, -1);
|
||||
}
|
||||
|
||||
void rotate_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, fixed angle) {
|
||||
pivot_scaled_sprite(bmp, sprite, (x<<16) + (sprite->w * 0x10000) / 2, (y<<16) + (sprite->h * 0x10000) / 2, sprite->w << 15, sprite->h << 15, angle, 0x10000);
|
||||
}
|
||||
|
||||
void pivot_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, int cx, int cy, fixed angle) {
|
||||
pivot_scaled_sprite(bmp, sprite, x<<16, y<<16, cx<<16, cy<<16, angle, 0x10000);
|
||||
}
|
||||
|
||||
|
||||
bool is_screen_bitmap(BITMAP *bmp) {
|
||||
return dynamic_cast<Graphics::Screen *>(bmp) != nullptr;
|
||||
}
|
||||
|
||||
bool is_video_bitmap(BITMAP *bmp) {
|
||||
return dynamic_cast<Graphics::Screen *>(bmp) != nullptr;
|
||||
}
|
||||
|
||||
bool is_planar_bitmap(BITMAP *bmp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_linear_bitmap(BITMAP *bmp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_same_bitmap(BITMAP *bmp1, BITMAP *bmp2) {
|
||||
if ((bmp1 == nullptr) || (bmp2 == nullptr))
|
||||
return false;
|
||||
if (bmp1 == bmp2)
|
||||
return true;
|
||||
|
||||
// TODO: allegro also returns true if one bmp is a sub of the other,
|
||||
// i.e. they share the same id
|
||||
// This (if needed?) would require a different implementation
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void bmp_select(BITMAP *bmp) {
|
||||
// No implementation needed
|
||||
}
|
||||
|
||||
byte *bmp_write_line(BITMAP *bmp, int line) {
|
||||
return bmp->line[line];
|
||||
}
|
||||
|
||||
void bmp_write8(byte *addr, int color) {
|
||||
*addr = color;
|
||||
}
|
||||
|
||||
void bmp_write15(byte *addr, int color) {
|
||||
*((uint16 *)addr) = color;
|
||||
}
|
||||
|
||||
void bmp_write16(byte *addr, int color) {
|
||||
*((uint16 *)addr) = color;
|
||||
}
|
||||
|
||||
void bmp_write24(byte *addr, int color) {
|
||||
*addr = (color & 0xff);
|
||||
*(addr + 1) = ((color >> 8) & 0xff);
|
||||
*(addr + 2) = ((color >> 16) & 0xff);
|
||||
}
|
||||
|
||||
void bmp_write32(byte *addr, int color) {
|
||||
*((uint32 *)addr) = color;
|
||||
}
|
||||
|
||||
void memory_putpixel(BITMAP *bmp, int x, int y, int color) {
|
||||
putpixel(bmp, x, y, color);
|
||||
}
|
||||
|
||||
void putpixel(BITMAP *bmp, int x, int y, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || x >= surf.w || y < 0 || y >= surf.h)
|
||||
return;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
|
||||
switch (surf.format.bytesPerPixel) {
|
||||
case 1:
|
||||
*((uint8 *)p) = color;
|
||||
break;
|
||||
case 2:
|
||||
*((uint16 *)p) = color;
|
||||
break;
|
||||
case 4:
|
||||
*((uint32 *)p) = color;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _putpixel(BITMAP *bmp, int x, int y, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || x >= surf.w || y < 0 || y >= surf.h)
|
||||
return;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
*((uint8 *)p) = color;
|
||||
}
|
||||
|
||||
void _putpixel15(BITMAP *bmp, int x, int y, int color) {
|
||||
error("Unsupported bpp");
|
||||
}
|
||||
|
||||
void _putpixel16(BITMAP *bmp, int x, int y, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || x >= surf.w || y < 0 || y >= surf.h)
|
||||
return;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
*((uint16 *)p) = color;
|
||||
}
|
||||
|
||||
void _putpixel24(BITMAP *bmp, int x, int y, int color) {
|
||||
error("Unsupported bpp");
|
||||
}
|
||||
|
||||
void _putpixel32(BITMAP *bmp, int x, int y, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || x >= surf.w || y < 0 || y >= surf.h)
|
||||
return;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
*((uint32 *)p) = color;
|
||||
}
|
||||
|
||||
int getpixel(const BITMAP *bmp, int x, int y) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
|
||||
// Allegro returns -1 if the pixel lies outside the bitmap
|
||||
if (x < 0 || y < 0 || x >= surf.w || y >= surf.h)
|
||||
return -1;
|
||||
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
|
||||
switch (surf.format.bytesPerPixel) {
|
||||
case 1:
|
||||
return *((uint8 *)p);
|
||||
case 2:
|
||||
return *((uint16 *)p);
|
||||
case 4:
|
||||
return *((uint32 *)p);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
error("Unsupported bpp");
|
||||
}
|
||||
|
||||
int _getpixel(const BITMAP *bmp, int x, int y) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || y < 0 || x >= surf.w || y >= surf.h)
|
||||
return -1;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
return *((uint8 *)p);
|
||||
}
|
||||
|
||||
int _getpixel15(const BITMAP *bmp, int x, int y) {
|
||||
error("Unsupported bpp");
|
||||
}
|
||||
|
||||
int _getpixel16(const BITMAP *bmp, int x, int y) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || y < 0 || x >= surf.w || y >= surf.h)
|
||||
return -1;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
return *((uint16 *)p);
|
||||
}
|
||||
|
||||
int _getpixel24(const BITMAP *bmp, int x, int y) {
|
||||
error("Unsupported bpp");
|
||||
}
|
||||
|
||||
int _getpixel32(const BITMAP *bmp, int x, int y) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x < 0 || y < 0 || x >= surf.w || y >= surf.h)
|
||||
return -1;
|
||||
void *p = surf.getBasePtr(x, y);
|
||||
return *((uint32 *)p);
|
||||
}
|
||||
|
||||
void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
surf.drawLine(x1, y1, x2, y2, color);
|
||||
}
|
||||
|
||||
void rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x1 > x2)
|
||||
SWAP(x1, x2);
|
||||
if (y1 > y2)
|
||||
SWAP(y1, y2);
|
||||
surf.frameRect(Common::Rect(x1, y1, x2 + 1, y2 + 1), color);
|
||||
}
|
||||
|
||||
void rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
if (x1 > x2)
|
||||
SWAP(x1, x2);
|
||||
if (y1 > y2)
|
||||
SWAP(y1, y2);
|
||||
surf.fillRect(Common::Rect(x1, y1, x2 + 1, y2 + 1), color);
|
||||
}
|
||||
|
||||
void triangle(BITMAP *bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color) {
|
||||
Graphics::ManagedSurface &surf = **bmp;
|
||||
surf.drawLine(x1, y1, x2, y2, color);
|
||||
surf.drawLine(x2, y2, x3, y3, color);
|
||||
surf.drawLine(x3, y3, x1, y1, color);
|
||||
}
|
||||
|
||||
void circlefill(BITMAP *bmp, int x, int y, int radius, int color) {
|
||||
bmp->circlefill(x, y, radius, color);
|
||||
}
|
||||
|
||||
void clear_bitmap(BITMAP *bmp) {
|
||||
bmp->clear();
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
240
engines/ags/lib/allegro/gfx.h
Normal file
240
engines/ags/lib/allegro/gfx.h
Normal file
@@ -0,0 +1,240 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_GRAPHICS_H
|
||||
#define AGS_LIB_ALLEGRO_GRAPHICS_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ags/lib/allegro/base.h"
|
||||
#include "ags/lib/allegro/fixed.h"
|
||||
#include "ags/lib/allegro/surface.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define GFX_TEXT -1
|
||||
#define GFX_AUTODETECT 0
|
||||
#define GFX_AUTODETECT_FULLSCREEN 1
|
||||
#define GFX_AUTODETECT_WINDOWED 2
|
||||
#define GFX_SAFE AL_ID('S','A','F','E')
|
||||
#define GFX_NONE AL_ID('N','O','N','E')
|
||||
|
||||
/* Bitfield for relaying graphics driver type information */
|
||||
#define GFX_TYPE_UNKNOWN 0
|
||||
#define GFX_TYPE_WINDOWED 1
|
||||
#define GFX_TYPE_FULLSCREEN 2
|
||||
#define GFX_TYPE_DEFINITE 4
|
||||
#define GFX_TYPE_MAGIC 8
|
||||
|
||||
/* drawing modes for draw_sprite_ex() */
|
||||
#define DRAW_SPRITE_NORMAL 0
|
||||
#define DRAW_SPRITE_LIT 1
|
||||
#define DRAW_SPRITE_TRANS 2
|
||||
|
||||
/* flipping modes for draw_sprite_ex() */
|
||||
#define DRAW_SPRITE_NO_FLIP 0x0
|
||||
#define DRAW_SPRITE_H_FLIP 0x1
|
||||
#define DRAW_SPRITE_V_FLIP 0x2
|
||||
#define DRAW_SPRITE_VH_FLIP 0x3
|
||||
|
||||
/* Blender mode defines, for the gfx_driver->set_blender_mode() function */
|
||||
#define blender_mode_none 0
|
||||
#define blender_mode_trans 1
|
||||
#define blender_mode_add 2
|
||||
#define blender_mode_burn 3
|
||||
#define blender_mode_color 4
|
||||
#define blender_mode_difference 5
|
||||
#define blender_mode_dissolve 6
|
||||
#define blender_mode_dodge 7
|
||||
#define blender_mode_hue 8
|
||||
#define blender_mode_invert 9
|
||||
#define blender_mode_luminance 10
|
||||
#define blender_mode_multiply 11
|
||||
#define blender_mode_saturation 12
|
||||
#define blender_mode_screen 13
|
||||
#define blender_mode_alpha 14
|
||||
|
||||
|
||||
#define SCREEN_W (gfx_driver ? gfx_driver->w : 0)
|
||||
#define SCREEN_H (gfx_driver ? gfx_driver->h : 0)
|
||||
|
||||
#define VIRTUAL_W (screen ? screen->w : 0)
|
||||
#define VIRTUAL_H (screen ? screen->h : 0)
|
||||
|
||||
#define COLORCONV_NONE 0
|
||||
|
||||
#define COLORCONV_8_TO_15 1
|
||||
#define COLORCONV_8_TO_16 2
|
||||
#define COLORCONV_8_TO_24 4
|
||||
#define COLORCONV_8_TO_32 8
|
||||
|
||||
#define COLORCONV_15_TO_8 0x10
|
||||
#define COLORCONV_15_TO_16 0x20
|
||||
#define COLORCONV_15_TO_24 0x40
|
||||
#define COLORCONV_15_TO_32 0x80
|
||||
|
||||
#define COLORCONV_16_TO_8 0x100
|
||||
#define COLORCONV_16_TO_15 0x200
|
||||
#define COLORCONV_16_TO_24 0x400
|
||||
#define COLORCONV_16_TO_32 0x800
|
||||
|
||||
#define COLORCONV_24_TO_8 0x1000
|
||||
#define COLORCONV_24_TO_15 0x2000
|
||||
#define COLORCONV_24_TO_16 0x4000
|
||||
#define COLORCONV_24_TO_32 0x8000
|
||||
|
||||
#define COLORCONV_32_TO_8 0x10000
|
||||
#define COLORCONV_32_TO_15 0x20000
|
||||
#define COLORCONV_32_TO_16 0x40000
|
||||
#define COLORCONV_32_TO_24 0x80000
|
||||
|
||||
#define COLORCONV_32A_TO_8 0x100000
|
||||
#define COLORCONV_32A_TO_15 0x200000
|
||||
#define COLORCONV_32A_TO_16 0x400000
|
||||
#define COLORCONV_32A_TO_24 0x800000
|
||||
|
||||
#define COLORCONV_DITHER_PAL 0x1000000
|
||||
#define COLORCONV_DITHER_HI 0x2000000
|
||||
#define COLORCONV_KEEP_TRANS 0x4000000
|
||||
|
||||
#define COLORCONV_DITHER (COLORCONV_DITHER_PAL | \
|
||||
COLORCONV_DITHER_HI)
|
||||
|
||||
#define COLORCONV_EXPAND_256 (COLORCONV_8_TO_15 | \
|
||||
COLORCONV_8_TO_16 | \
|
||||
COLORCONV_8_TO_24 | \
|
||||
COLORCONV_8_TO_32)
|
||||
|
||||
#define COLORCONV_REDUCE_TO_256 (COLORCONV_15_TO_8 | \
|
||||
COLORCONV_16_TO_8 | \
|
||||
COLORCONV_24_TO_8 | \
|
||||
COLORCONV_32_TO_8 | \
|
||||
COLORCONV_32A_TO_8)
|
||||
|
||||
#define COLORCONV_EXPAND_15_TO_16 COLORCONV_15_TO_16
|
||||
|
||||
#define COLORCONV_REDUCE_16_TO_15 COLORCONV_16_TO_15
|
||||
|
||||
#define COLORCONV_EXPAND_HI_TO_TRUE (COLORCONV_15_TO_24 | \
|
||||
COLORCONV_15_TO_32 | \
|
||||
COLORCONV_16_TO_24 | \
|
||||
COLORCONV_16_TO_32)
|
||||
|
||||
#define COLORCONV_REDUCE_TRUE_TO_HI (COLORCONV_24_TO_15 | \
|
||||
COLORCONV_24_TO_16 | \
|
||||
COLORCONV_32_TO_15 | \
|
||||
COLORCONV_32_TO_16)
|
||||
|
||||
#define COLORCONV_24_EQUALS_32 (COLORCONV_24_TO_32 | \
|
||||
COLORCONV_32_TO_24)
|
||||
|
||||
#define COLORCONV_TOTAL (COLORCONV_EXPAND_256 | \
|
||||
COLORCONV_REDUCE_TO_256 | \
|
||||
COLORCONV_EXPAND_15_TO_16 | \
|
||||
COLORCONV_REDUCE_16_TO_15 | \
|
||||
COLORCONV_EXPAND_HI_TO_TRUE | \
|
||||
COLORCONV_REDUCE_TRUE_TO_HI | \
|
||||
COLORCONV_24_EQUALS_32 | \
|
||||
COLORCONV_32A_TO_15 | \
|
||||
COLORCONV_32A_TO_16 | \
|
||||
COLORCONV_32A_TO_24)
|
||||
|
||||
#define COLORCONV_PARTIAL (COLORCONV_EXPAND_15_TO_16 | \
|
||||
COLORCONV_REDUCE_16_TO_15 | \
|
||||
COLORCONV_24_EQUALS_32)
|
||||
|
||||
#define COLORCONV_MOST (COLORCONV_EXPAND_15_TO_16 | \
|
||||
COLORCONV_REDUCE_16_TO_15 | \
|
||||
COLORCONV_EXPAND_HI_TO_TRUE | \
|
||||
COLORCONV_REDUCE_TRUE_TO_HI | \
|
||||
COLORCONV_24_EQUALS_32)
|
||||
|
||||
#define COLORCONV_KEEP_ALPHA (COLORCONV_TOTAL \
|
||||
& ~(COLORCONV_32A_TO_8 | \
|
||||
COLORCONV_32A_TO_15 | \
|
||||
COLORCONV_32A_TO_16 | \
|
||||
COLORCONV_32A_TO_24))
|
||||
|
||||
AL_FUNC(void, set_color_conversion, (int mode));
|
||||
AL_FUNC(int, get_color_conversion, ());
|
||||
AL_FUNC(int, set_gfx_mode, (int card, int w, int h, int depth));
|
||||
|
||||
AL_FUNC(void, set_clip_rect, (BITMAP *bitmap, int x1, int y1, int x2, int y2));
|
||||
AL_FUNC(void, get_clip_rect, (BITMAP *bitmap, int *x1, int *y1, int *x2, int *y2));
|
||||
AL_FUNC(void, clear_bitmap, (BITMAP *bitmap));
|
||||
|
||||
AL_FUNC(void, acquire_bitmap, (BITMAP *bitmap));
|
||||
AL_FUNC(void, release_bitmap, (BITMAP *bitmap));
|
||||
AL_FUNC(void, draw_sprite, (BITMAP *bmp, const BITMAP *sprite, int x, int y));
|
||||
AL_FUNC(void, stretch_sprite, (BITMAP *bmp, const BITMAP *sprite, int x, int y, int w, int h));
|
||||
|
||||
extern void clear_to_color(BITMAP *bitmap, int color);
|
||||
extern int bitmap_color_depth(BITMAP *bmp);
|
||||
extern int bitmap_mask_color(BITMAP *bmp);
|
||||
extern void add_palette_if_needed(Graphics::ManagedSurface &surf);
|
||||
extern void blit(const BITMAP *src, BITMAP *dest, int src_x, int src_y, int dst_x, int dst_y, int width, int height);
|
||||
extern void masked_blit(const BITMAP *src, BITMAP *dest, int src_x, int src_y, int dst_x, int dst_y, int width, int height);
|
||||
extern void stretch_blit(const BITMAP *src, BITMAP *dest, int source_x, int source_y, int source_width, int source_height,
|
||||
int dest_x, int dest_y, int dest_width, int dest_height);
|
||||
extern void masked_stretch_blit(const BITMAP *src, BITMAP *dest, int source_x, int source_y, int source_width, int source_height,
|
||||
int dest_x, int dest_y, int dest_width, int dest_height);
|
||||
extern void draw_trans_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y);
|
||||
extern void draw_lit_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, int color);
|
||||
extern void draw_sprite_h_flip(BITMAP *bmp, const BITMAP *sprite, int x, int y);
|
||||
extern void draw_sprite_v_flip(BITMAP *bmp, const BITMAP *sprite, int x, int y);
|
||||
extern void draw_sprite_vh_flip(BITMAP *bmp, const BITMAP *sprite, int x, int y);
|
||||
extern void rotate_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, fixed angle);
|
||||
extern void pivot_sprite(BITMAP *bmp, const BITMAP *sprite, int x, int y, int cx, int cy, fixed angle);
|
||||
|
||||
extern bool is_screen_bitmap(BITMAP *bmp);
|
||||
extern bool is_video_bitmap(BITMAP *bmp);
|
||||
extern bool is_linear_bitmap(BITMAP *bmp);
|
||||
extern bool is_same_bitmap(BITMAP *bmp1, BITMAP *bmp2);
|
||||
extern bool is_planar_bitmap(BITMAP *bmp);
|
||||
extern void bmp_select(BITMAP *bmp);
|
||||
extern byte *bmp_write_line(BITMAP *bmp, int line);
|
||||
extern void bmp_write8(byte *addr, int color);
|
||||
extern void bmp_write15(byte *addr, int color);
|
||||
extern void bmp_write16(byte *addr, int color);
|
||||
extern void bmp_write24(byte *addr, int color);
|
||||
extern void bmp_write32(byte *addr, int color);
|
||||
extern void memory_putpixel(BITMAP *bmp, int x, int y, int color);
|
||||
extern void putpixel(BITMAP *bmp, int x, int y, int color);
|
||||
extern void _putpixel(BITMAP *bmp, int x, int y, int color);
|
||||
extern void _putpixel15(BITMAP *bmp, int x, int y, int color);
|
||||
extern void _putpixel16(BITMAP *bmp, int x, int y, int color);
|
||||
extern void _putpixel24(BITMAP *bmp, int x, int y, int color);
|
||||
extern void _putpixel32(BITMAP *bmp, int x, int y, int color);
|
||||
extern int getpixel(const BITMAP *bmp, int x, int y);
|
||||
extern int _getpixel(const BITMAP *bmp, int x, int y);
|
||||
extern int _getpixel15(const BITMAP *bmp, int x, int y);
|
||||
extern int _getpixel16(const BITMAP *bmp, int x, int y);
|
||||
extern int _getpixel24(const BITMAP *bmp, int x, int y);
|
||||
extern int _getpixel32(const BITMAP *bmp, int x, int y);
|
||||
extern void line(BITMAP *bmp, int x1, int y_1, int x2, int y2, int color);
|
||||
extern void rect(BITMAP *bmp, int x1, int y_1, int x2, int y2, int color);
|
||||
extern void rectfill(BITMAP *bmp, int x1, int y_1, int x2, int y2, int color);
|
||||
extern void triangle(BITMAP *bmp, int x1, int y_1, int x2, int y2, int x3, int y3, int color);
|
||||
extern void circlefill(BITMAP *bmp, int x, int y, int radius, int color);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
48
engines/ags/lib/allegro/graphics.cpp
Normal file
48
engines/ags/lib/allegro/graphics.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
/* lookup table for scaling 5 bit colors up to 8 bits */
|
||||
const int _rgb_scale_5[32] = {
|
||||
0, 8, 16, 24, 33, 41, 49, 57,
|
||||
66, 74, 82, 90, 99, 107, 115, 123,
|
||||
132, 140, 148, 156, 165, 173, 181, 189,
|
||||
198, 206, 214, 222, 231, 239, 247, 255
|
||||
};
|
||||
|
||||
|
||||
/* lookup table for scaling 6 bit colors up to 8 bits */
|
||||
const int _rgb_scale_6[64] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28,
|
||||
32, 36, 40, 44, 48, 52, 56, 60,
|
||||
65, 69, 73, 77, 81, 85, 89, 93,
|
||||
97, 101, 105, 109, 113, 117, 121, 125,
|
||||
130, 134, 138, 142, 146, 150, 154, 158,
|
||||
162, 166, 170, 174, 178, 182, 186, 190,
|
||||
195, 199, 203, 207, 211, 215, 219, 223,
|
||||
227, 231, 235, 239, 243, 247, 251, 255
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
277
engines/ags/lib/allegro/math.cpp
Normal file
277
engines/ags/lib/allegro/math.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_MATH_H
|
||||
#define AGS_LIB_ALLEGRO_MATH_H
|
||||
|
||||
#include "ags/lib/allegro/error.h"
|
||||
#include "ags/lib/allegro/fixed.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
const fixed _cos_tbl[512] = {
|
||||
/* precalculated fixed point (16.16) cosines for a full circle (0-255) */
|
||||
|
||||
65536L, 65531L, 65516L, 65492L, 65457L, 65413L, 65358L, 65294L,
|
||||
65220L, 65137L, 65043L, 64940L, 64827L, 64704L, 64571L, 64429L,
|
||||
64277L, 64115L, 63944L, 63763L, 63572L, 63372L, 63162L, 62943L,
|
||||
62714L, 62476L, 62228L, 61971L, 61705L, 61429L, 61145L, 60851L,
|
||||
60547L, 60235L, 59914L, 59583L, 59244L, 58896L, 58538L, 58172L,
|
||||
57798L, 57414L, 57022L, 56621L, 56212L, 55794L, 55368L, 54934L,
|
||||
54491L, 54040L, 53581L, 53114L, 52639L, 52156L, 51665L, 51166L,
|
||||
50660L, 50146L, 49624L, 49095L, 48559L, 48015L, 47464L, 46906L,
|
||||
46341L, 45769L, 45190L, 44604L, 44011L, 43412L, 42806L, 42194L,
|
||||
41576L, 40951L, 40320L, 39683L, 39040L, 38391L, 37736L, 37076L,
|
||||
36410L, 35738L, 35062L, 34380L, 33692L, 33000L, 32303L, 31600L,
|
||||
30893L, 30182L, 29466L, 28745L, 28020L, 27291L, 26558L, 25821L,
|
||||
25080L, 24335L, 23586L, 22834L, 22078L, 21320L, 20557L, 19792L,
|
||||
19024L, 18253L, 17479L, 16703L, 15924L, 15143L, 14359L, 13573L,
|
||||
12785L, 11996L, 11204L, 10411L, 9616L, 8820L, 8022L, 7224L,
|
||||
6424L, 5623L, 4821L, 4019L, 3216L, 2412L, 1608L, 804L,
|
||||
0L, -804L, -1608L, -2412L, -3216L, -4019L, -4821L, -5623L,
|
||||
-6424L, -7224L, -8022L, -8820L, -9616L, -10411L, -11204L, -11996L,
|
||||
-12785L, -13573L, -14359L, -15143L, -15924L, -16703L, -17479L, -18253L,
|
||||
-19024L, -19792L, -20557L, -21320L, -22078L, -22834L, -23586L, -24335L,
|
||||
-25080L, -25821L, -26558L, -27291L, -28020L, -28745L, -29466L, -30182L,
|
||||
-30893L, -31600L, -32303L, -33000L, -33692L, -34380L, -35062L, -35738L,
|
||||
-36410L, -37076L, -37736L, -38391L, -39040L, -39683L, -40320L, -40951L,
|
||||
-41576L, -42194L, -42806L, -43412L, -44011L, -44604L, -45190L, -45769L,
|
||||
-46341L, -46906L, -47464L, -48015L, -48559L, -49095L, -49624L, -50146L,
|
||||
-50660L, -51166L, -51665L, -52156L, -52639L, -53114L, -53581L, -54040L,
|
||||
-54491L, -54934L, -55368L, -55794L, -56212L, -56621L, -57022L, -57414L,
|
||||
-57798L, -58172L, -58538L, -58896L, -59244L, -59583L, -59914L, -60235L,
|
||||
-60547L, -60851L, -61145L, -61429L, -61705L, -61971L, -62228L, -62476L,
|
||||
-62714L, -62943L, -63162L, -63372L, -63572L, -63763L, -63944L, -64115L,
|
||||
-64277L, -64429L, -64571L, -64704L, -64827L, -64940L, -65043L, -65137L,
|
||||
-65220L, -65294L, -65358L, -65413L, -65457L, -65492L, -65516L, -65531L,
|
||||
-65536L, -65531L, -65516L, -65492L, -65457L, -65413L, -65358L, -65294L,
|
||||
-65220L, -65137L, -65043L, -64940L, -64827L, -64704L, -64571L, -64429L,
|
||||
-64277L, -64115L, -63944L, -63763L, -63572L, -63372L, -63162L, -62943L,
|
||||
-62714L, -62476L, -62228L, -61971L, -61705L, -61429L, -61145L, -60851L,
|
||||
-60547L, -60235L, -59914L, -59583L, -59244L, -58896L, -58538L, -58172L,
|
||||
-57798L, -57414L, -57022L, -56621L, -56212L, -55794L, -55368L, -54934L,
|
||||
-54491L, -54040L, -53581L, -53114L, -52639L, -52156L, -51665L, -51166L,
|
||||
-50660L, -50146L, -49624L, -49095L, -48559L, -48015L, -47464L, -46906L,
|
||||
-46341L, -45769L, -45190L, -44604L, -44011L, -43412L, -42806L, -42194L,
|
||||
-41576L, -40951L, -40320L, -39683L, -39040L, -38391L, -37736L, -37076L,
|
||||
-36410L, -35738L, -35062L, -34380L, -33692L, -33000L, -32303L, -31600L,
|
||||
-30893L, -30182L, -29466L, -28745L, -28020L, -27291L, -26558L, -25821L,
|
||||
-25080L, -24335L, -23586L, -22834L, -22078L, -21320L, -20557L, -19792L,
|
||||
-19024L, -18253L, -17479L, -16703L, -15924L, -15143L, -14359L, -13573L,
|
||||
-12785L, -11996L, -11204L, -10411L, -9616L, -8820L, -8022L, -7224L,
|
||||
-6424L, -5623L, -4821L, -4019L, -3216L, -2412L, -1608L, -804L,
|
||||
0L, 804L, 1608L, 2412L, 3216L, 4019L, 4821L, 5623L,
|
||||
6424L, 7224L, 8022L, 8820L, 9616L, 10411L, 11204L, 11996L,
|
||||
12785L, 13573L, 14359L, 15143L, 15924L, 16703L, 17479L, 18253L,
|
||||
19024L, 19792L, 20557L, 21320L, 22078L, 22834L, 23586L, 24335L,
|
||||
25080L, 25821L, 26558L, 27291L, 28020L, 28745L, 29466L, 30182L,
|
||||
30893L, 31600L, 32303L, 33000L, 33692L, 34380L, 35062L, 35738L,
|
||||
36410L, 37076L, 37736L, 38391L, 39040L, 39683L, 40320L, 40951L,
|
||||
41576L, 42194L, 42806L, 43412L, 44011L, 44604L, 45190L, 45769L,
|
||||
46341L, 46906L, 47464L, 48015L, 48559L, 49095L, 49624L, 50146L,
|
||||
50660L, 51166L, 51665L, 52156L, 52639L, 53114L, 53581L, 54040L,
|
||||
54491L, 54934L, 55368L, 55794L, 56212L, 56621L, 57022L, 57414L,
|
||||
57798L, 58172L, 58538L, 58896L, 59244L, 59583L, 59914L, 60235L,
|
||||
60547L, 60851L, 61145L, 61429L, 61705L, 61971L, 62228L, 62476L,
|
||||
62714L, 62943L, 63162L, 63372L, 63572L, 63763L, 63944L, 64115L,
|
||||
64277L, 64429L, 64571L, 64704L, 64827L, 64940L, 65043L, 65137L,
|
||||
65220L, 65294L, 65358L, 65413L, 65457L, 65492L, 65516L, 65531L
|
||||
};
|
||||
|
||||
const fixed _tan_tbl[256] = {
|
||||
/* precalculated fixed point (16.16) tangents for a half circle (0-127) */
|
||||
|
||||
0L, 804L, 1609L, 2414L, 3220L, 4026L, 4834L, 5644L,
|
||||
6455L, 7268L, 8083L, 8901L, 9721L, 10545L, 11372L, 12202L,
|
||||
13036L, 13874L, 14717L, 15564L, 16416L, 17273L, 18136L, 19005L,
|
||||
19880L, 20762L, 21650L, 22546L, 23449L, 24360L, 25280L, 26208L,
|
||||
27146L, 28093L, 29050L, 30018L, 30996L, 31986L, 32988L, 34002L,
|
||||
35030L, 36071L, 37126L, 38196L, 39281L, 40382L, 41500L, 42636L,
|
||||
43790L, 44963L, 46156L, 47369L, 48605L, 49863L, 51145L, 52451L,
|
||||
53784L, 55144L, 56532L, 57950L, 59398L, 60880L, 62395L, 63947L,
|
||||
65536L, 67165L, 68835L, 70548L, 72308L, 74116L, 75974L, 77887L,
|
||||
79856L, 81885L, 83977L, 86135L, 88365L, 90670L, 93054L, 95523L,
|
||||
98082L, 100736L, 103493L, 106358L, 109340L, 112447L, 115687L, 119071L,
|
||||
122609L, 126314L, 130198L, 134276L, 138564L, 143081L, 147847L, 152884L,
|
||||
158218L, 163878L, 169896L, 176309L, 183161L, 190499L, 198380L, 206870L,
|
||||
216043L, 225990L, 236817L, 248648L, 261634L, 275959L, 291845L, 309568L,
|
||||
329472L, 351993L, 377693L, 407305L, 441808L, 482534L, 531352L, 590958L,
|
||||
665398L, 761030L, 888450L, 1066730L, 1334016L, 1779314L, 2669641L, 5340086L,
|
||||
-2147483647L, -5340086L, -2669641L, -1779314L, -1334016L, -1066730L, -888450L, -761030L,
|
||||
-665398L, -590958L, -531352L, -482534L, -441808L, -407305L, -377693L, -351993L,
|
||||
-329472L, -309568L, -291845L, -275959L, -261634L, -248648L, -236817L, -225990L,
|
||||
-216043L, -206870L, -198380L, -190499L, -183161L, -176309L, -169896L, -163878L,
|
||||
-158218L, -152884L, -147847L, -143081L, -138564L, -134276L, -130198L, -126314L,
|
||||
-122609L, -119071L, -115687L, -112447L, -109340L, -106358L, -103493L, -100736L,
|
||||
-98082L, -95523L, -93054L, -90670L, -88365L, -86135L, -83977L, -81885L,
|
||||
-79856L, -77887L, -75974L, -74116L, -72308L, -70548L, -68835L, -67165L,
|
||||
-65536L, -63947L, -62395L, -60880L, -59398L, -57950L, -56532L, -55144L,
|
||||
-53784L, -52451L, -51145L, -49863L, -48605L, -47369L, -46156L, -44963L,
|
||||
-43790L, -42636L, -41500L, -40382L, -39281L, -38196L, -37126L, -36071L,
|
||||
-35030L, -34002L, -32988L, -31986L, -30996L, -30018L, -29050L, -28093L,
|
||||
-27146L, -26208L, -25280L, -24360L, -23449L, -22546L, -21650L, -20762L,
|
||||
-19880L, -19005L, -18136L, -17273L, -16416L, -15564L, -14717L, -13874L,
|
||||
-13036L, -12202L, -11372L, -10545L, -9721L, -8901L, -8083L, -7268L,
|
||||
-6455L, -5644L, -4834L, -4026L, -3220L, -2414L, -1609L, -804L
|
||||
};
|
||||
|
||||
const fixed _acos_tbl[513] = {
|
||||
/* precalculated fixed point (16.16) inverse cosines (-1 to 1) */
|
||||
|
||||
0x800000L, 0x7C65C7L, 0x7AE75AL, 0x79C19EL, 0x78C9BEL, 0x77EF25L, 0x772953L, 0x76733AL,
|
||||
0x75C991L, 0x752A10L, 0x74930CL, 0x740345L, 0x7379C1L, 0x72F5BAL, 0x72768FL, 0x71FBBCL,
|
||||
0x7184D3L, 0x711174L, 0x70A152L, 0x703426L, 0x6FC9B5L, 0x6F61C9L, 0x6EFC36L, 0x6E98D1L,
|
||||
0x6E3777L, 0x6DD805L, 0x6D7A5EL, 0x6D1E68L, 0x6CC40BL, 0x6C6B2FL, 0x6C13C1L, 0x6BBDAFL,
|
||||
0x6B68E6L, 0x6B1558L, 0x6AC2F5L, 0x6A71B1L, 0x6A217EL, 0x69D251L, 0x698420L, 0x6936DFL,
|
||||
0x68EA85L, 0x689F0AL, 0x685465L, 0x680A8DL, 0x67C17DL, 0x67792CL, 0x673194L, 0x66EAAFL,
|
||||
0x66A476L, 0x665EE5L, 0x6619F5L, 0x65D5A2L, 0x6591E7L, 0x654EBFL, 0x650C26L, 0x64CA18L,
|
||||
0x648890L, 0x64478CL, 0x640706L, 0x63C6FCL, 0x63876BL, 0x63484FL, 0x6309A5L, 0x62CB6AL,
|
||||
0x628D9CL, 0x625037L, 0x621339L, 0x61D69FL, 0x619A68L, 0x615E90L, 0x612316L, 0x60E7F7L,
|
||||
0x60AD31L, 0x6072C3L, 0x6038A9L, 0x5FFEE3L, 0x5FC56EL, 0x5F8C49L, 0x5F5372L, 0x5F1AE7L,
|
||||
0x5EE2A7L, 0x5EAAB0L, 0x5E7301L, 0x5E3B98L, 0x5E0473L, 0x5DCD92L, 0x5D96F3L, 0x5D6095L,
|
||||
0x5D2A76L, 0x5CF496L, 0x5CBEF2L, 0x5C898BL, 0x5C545EL, 0x5C1F6BL, 0x5BEAB0L, 0x5BB62DL,
|
||||
0x5B81E1L, 0x5B4DCAL, 0x5B19E7L, 0x5AE638L, 0x5AB2BCL, 0x5A7F72L, 0x5A4C59L, 0x5A1970L,
|
||||
0x59E6B6L, 0x59B42AL, 0x5981CCL, 0x594F9BL, 0x591D96L, 0x58EBBDL, 0x58BA0EL, 0x588889L,
|
||||
0x58572DL, 0x5825FAL, 0x57F4EEL, 0x57C40AL, 0x57934DL, 0x5762B5L, 0x573243L, 0x5701F5L,
|
||||
0x56D1CCL, 0x56A1C6L, 0x5671E4L, 0x564224L, 0x561285L, 0x55E309L, 0x55B3ADL, 0x558471L,
|
||||
0x555555L, 0x552659L, 0x54F77BL, 0x54C8BCL, 0x549A1BL, 0x546B98L, 0x543D31L, 0x540EE7L,
|
||||
0x53E0B9L, 0x53B2A7L, 0x5384B0L, 0x5356D4L, 0x532912L, 0x52FB6BL, 0x52CDDDL, 0x52A068L,
|
||||
0x52730CL, 0x5245C9L, 0x52189EL, 0x51EB8BL, 0x51BE8FL, 0x5191AAL, 0x5164DCL, 0x513825L,
|
||||
0x510B83L, 0x50DEF7L, 0x50B280L, 0x50861FL, 0x5059D2L, 0x502D99L, 0x500175L, 0x4FD564L,
|
||||
0x4FA967L, 0x4F7D7DL, 0x4F51A6L, 0x4F25E2L, 0x4EFA30L, 0x4ECE90L, 0x4EA301L, 0x4E7784L,
|
||||
0x4E4C19L, 0x4E20BEL, 0x4DF574L, 0x4DCA3AL, 0x4D9F10L, 0x4D73F6L, 0x4D48ECL, 0x4D1DF1L,
|
||||
0x4CF305L, 0x4CC829L, 0x4C9D5AL, 0x4C729AL, 0x4C47E9L, 0x4C1D45L, 0x4BF2AEL, 0x4BC826L,
|
||||
0x4B9DAAL, 0x4B733BL, 0x4B48D9L, 0x4B1E84L, 0x4AF43BL, 0x4AC9FEL, 0x4A9FCDL, 0x4A75A7L,
|
||||
0x4A4B8DL, 0x4A217EL, 0x49F77AL, 0x49CD81L, 0x49A393L, 0x4979AFL, 0x494FD5L, 0x492605L,
|
||||
0x48FC3FL, 0x48D282L, 0x48A8CFL, 0x487F25L, 0x485584L, 0x482BECL, 0x48025DL, 0x47D8D6L,
|
||||
0x47AF57L, 0x4785E0L, 0x475C72L, 0x47330AL, 0x4709ABL, 0x46E052L, 0x46B701L, 0x468DB7L,
|
||||
0x466474L, 0x463B37L, 0x461201L, 0x45E8D0L, 0x45BFA6L, 0x459682L, 0x456D64L, 0x45444BL,
|
||||
0x451B37L, 0x44F229L, 0x44C920L, 0x44A01CL, 0x44771CL, 0x444E21L, 0x44252AL, 0x43FC38L,
|
||||
0x43D349L, 0x43AA5FL, 0x438178L, 0x435894L, 0x432FB4L, 0x4306D8L, 0x42DDFEL, 0x42B527L,
|
||||
0x428C53L, 0x426381L, 0x423AB2L, 0x4211E5L, 0x41E91AL, 0x41C051L, 0x41978AL, 0x416EC5L,
|
||||
0x414601L, 0x411D3EL, 0x40F47CL, 0x40CBBBL, 0x40A2FBL, 0x407A3CL, 0x40517DL, 0x4028BEL,
|
||||
0x400000L, 0x3FD742L, 0x3FAE83L, 0x3F85C4L, 0x3F5D05L, 0x3F3445L, 0x3F0B84L, 0x3EE2C2L,
|
||||
0x3EB9FFL, 0x3E913BL, 0x3E6876L, 0x3E3FAFL, 0x3E16E6L, 0x3DEE1BL, 0x3DC54EL, 0x3D9C7FL,
|
||||
0x3D73ADL, 0x3D4AD9L, 0x3D2202L, 0x3CF928L, 0x3CD04CL, 0x3CA76CL, 0x3C7E88L, 0x3C55A1L,
|
||||
0x3C2CB7L, 0x3C03C8L, 0x3BDAD6L, 0x3BB1DFL, 0x3B88E4L, 0x3B5FE4L, 0x3B36E0L, 0x3B0DD7L,
|
||||
0x3AE4C9L, 0x3ABBB5L, 0x3A929CL, 0x3A697EL, 0x3A405AL, 0x3A1730L, 0x39EDFFL, 0x39C4C9L,
|
||||
0x399B8CL, 0x397249L, 0x3948FFL, 0x391FAEL, 0x38F655L, 0x38CCF6L, 0x38A38EL, 0x387A20L,
|
||||
0x3850A9L, 0x38272AL, 0x37FDA3L, 0x37D414L, 0x37AA7CL, 0x3780DBL, 0x375731L, 0x372D7EL,
|
||||
0x3703C1L, 0x36D9FBL, 0x36B02BL, 0x368651L, 0x365C6DL, 0x36327FL, 0x360886L, 0x35DE82L,
|
||||
0x35B473L, 0x358A59L, 0x356033L, 0x353602L, 0x350BC5L, 0x34E17CL, 0x34B727L, 0x348CC5L,
|
||||
0x346256L, 0x3437DAL, 0x340D52L, 0x33E2BBL, 0x33B817L, 0x338D66L, 0x3362A6L, 0x3337D7L,
|
||||
0x330CFBL, 0x32E20FL, 0x32B714L, 0x328C0AL, 0x3260F0L, 0x3235C6L, 0x320A8CL, 0x31DF42L,
|
||||
0x31B3E7L, 0x31887CL, 0x315CFFL, 0x313170L, 0x3105D0L, 0x30DA1EL, 0x30AE5AL, 0x308283L,
|
||||
0x305699L, 0x302A9CL, 0x2FFE8BL, 0x2FD267L, 0x2FA62EL, 0x2F79E1L, 0x2F4D80L, 0x2F2109L,
|
||||
0x2EF47DL, 0x2EC7DBL, 0x2E9B24L, 0x2E6E56L, 0x2E4171L, 0x2E1475L, 0x2DE762L, 0x2DBA37L,
|
||||
0x2D8CF4L, 0x2D5F98L, 0x2D3223L, 0x2D0495L, 0x2CD6EEL, 0x2CA92CL, 0x2C7B50L, 0x2C4D59L,
|
||||
0x2C1F47L, 0x2BF119L, 0x2BC2CFL, 0x2B9468L, 0x2B65E5L, 0x2B3744L, 0x2B0885L, 0x2AD9A7L,
|
||||
0x2AAAABL, 0x2A7B8FL, 0x2A4C53L, 0x2A1CF7L, 0x29ED7BL, 0x29BDDCL, 0x298E1CL, 0x295E3AL,
|
||||
0x292E34L, 0x28FE0BL, 0x28CDBDL, 0x289D4BL, 0x286CB3L, 0x283BF6L, 0x280B12L, 0x27DA06L,
|
||||
0x27A8D3L, 0x277777L, 0x2745F2L, 0x271443L, 0x26E26AL, 0x26B065L, 0x267E34L, 0x264BD6L,
|
||||
0x26194AL, 0x25E690L, 0x25B3A7L, 0x25808EL, 0x254D44L, 0x2519C8L, 0x24E619L, 0x24B236L,
|
||||
0x247E1FL, 0x2449D3L, 0x241550L, 0x23E095L, 0x23ABA2L, 0x237675L, 0x23410EL, 0x230B6AL,
|
||||
0x22D58AL, 0x229F6BL, 0x22690DL, 0x22326EL, 0x21FB8DL, 0x21C468L, 0x218CFFL, 0x215550L,
|
||||
0x211D59L, 0x20E519L, 0x20AC8EL, 0x2073B7L, 0x203A92L, 0x20011DL, 0x1FC757L, 0x1F8D3DL,
|
||||
0x1F52CFL, 0x1F1809L, 0x1EDCEAL, 0x1EA170L, 0x1E6598L, 0x1E2961L, 0x1DECC7L, 0x1DAFC9L,
|
||||
0x1D7264L, 0x1D3496L, 0x1CF65BL, 0x1CB7B1L, 0x1C7895L, 0x1C3904L, 0x1BF8FAL, 0x1BB874L,
|
||||
0x1B7770L, 0x1B35E8L, 0x1AF3DAL, 0x1AB141L, 0x1A6E19L, 0x1A2A5EL, 0x19E60BL, 0x19A11BL,
|
||||
0x195B8AL, 0x191551L, 0x18CE6CL, 0x1886D4L, 0x183E83L, 0x17F573L, 0x17AB9BL, 0x1760F6L,
|
||||
0x17157BL, 0x16C921L, 0x167BE0L, 0x162DAFL, 0x15DE82L, 0x158E4FL, 0x153D0BL, 0x14EAA8L,
|
||||
0x14971AL, 0x144251L, 0x13EC3FL, 0x1394D1L, 0x133BF5L, 0x12E198L, 0x1285A2L, 0x1227FBL,
|
||||
0x11C889L, 0x11672FL, 0x1103CAL, 0x109E37L, 0x10364BL, 0xFCBDAL, 0xF5EAEL, 0xEEE8CL,
|
||||
0xE7B2DL, 0xE0444L, 0xD8971L, 0xD0A46L, 0xC863FL, 0xBFCBBL, 0xB6CF4L, 0xAD5F0L,
|
||||
0xA366FL, 0x98CC6L, 0x8D6ADL, 0x810DBL, 0x73642L, 0x63E62L, 0x518A6L, 0x39A39L,
|
||||
0x0L
|
||||
};
|
||||
|
||||
|
||||
/* fixatan:
|
||||
* Fixed point inverse tangent. Does a binary search on the tan table.
|
||||
*/
|
||||
fixed fixatan(fixed x) {
|
||||
int a, b, c; /* for binary search */
|
||||
fixed d; /* difference value for search */
|
||||
|
||||
if (x >= 0) { /* search the first part of tan table */
|
||||
a = 0;
|
||||
b = 127;
|
||||
} else { /* search the second half instead */
|
||||
a = 128;
|
||||
b = 255;
|
||||
}
|
||||
|
||||
do {
|
||||
c = (a + b) >> 1;
|
||||
d = x - _tan_tbl[c];
|
||||
|
||||
if (d > 0)
|
||||
a = c + 1;
|
||||
else if (d < 0)
|
||||
b = c - 1;
|
||||
|
||||
} while ((a <= b) && (d));
|
||||
|
||||
if (x >= 0)
|
||||
return ((long)c) << 15;
|
||||
|
||||
return (-0x00800000L + (((long)c) << 15));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* fixatan2:
|
||||
* Like the libc atan2, but for fixed point numbers.
|
||||
*/
|
||||
fixed fixatan2(fixed y, fixed x) {
|
||||
fixed r;
|
||||
|
||||
if (x == 0) {
|
||||
if (y == 0) {
|
||||
*_G(allegro_errno) = AL_EDOM;
|
||||
return 0L;
|
||||
} else
|
||||
return ((y < 0) ? -0x00400000L : 0x00400000L);
|
||||
}
|
||||
|
||||
*_G(allegro_errno) = AL_NOERROR;
|
||||
r = fixdiv(y, x);
|
||||
|
||||
if (*_G(allegro_errno)) {
|
||||
*_G(allegro_errno) = AL_NOERROR;
|
||||
return ((y < 0) ? -0x00400000L : 0x00400000L);
|
||||
}
|
||||
|
||||
r = fixatan(r);
|
||||
|
||||
if (x >= 0)
|
||||
return r;
|
||||
|
||||
if (y >= 0)
|
||||
return 0x00800000L + r;
|
||||
|
||||
return r - 0x00800000L;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
374
engines/ags/lib/allegro/rotate.cpp
Normal file
374
engines/ags/lib/allegro/rotate.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
#include "ags/lib/allegro/rotate.h"
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
/* rotate_scale_coordinates:
|
||||
* Calculates the coordinates for the rotated, scaled and flipped sprite,
|
||||
* and passes them on to the given function.
|
||||
*/
|
||||
void rotate_scale_coordinates(fixed w, fixed h,
|
||||
fixed x, fixed y, fixed cx, fixed cy,
|
||||
fixed angle,
|
||||
fixed scale_x, fixed scale_y,
|
||||
fixed xs[4], fixed ys[4])
|
||||
{
|
||||
// Setting angle to the range -180...180 degrees makes sin & cos more numerically stable.
|
||||
// (Yes, this does have an effect for big angles!)
|
||||
// Note that using "real" sin() and cos() gives much better precision than fixsin() and fixcos().
|
||||
angle = angle & 0xffffff;
|
||||
if (angle >= 0x800000)
|
||||
angle -= 0x1000000;
|
||||
|
||||
double angle_radian = angle * (M_PI / (double)0x800000);
|
||||
double sin_angle = sin(angle_radian);
|
||||
double cos_angle = cos(angle_radian);
|
||||
|
||||
fixed fix_cos, fix_sin;
|
||||
if (cos_angle >= 0)
|
||||
fix_cos = (int)(cos_angle * 0x10000 + 0.5);
|
||||
else
|
||||
fix_cos = (int)(cos_angle * 0x10000 - 0.5);
|
||||
if (sin_angle >= 0)
|
||||
fix_sin = (int)(sin_angle * 0x10000 + 0.5);
|
||||
else
|
||||
fix_sin = (int)(sin_angle * 0x10000 - 0.5);
|
||||
|
||||
/* Decide what order to take corners in. */
|
||||
int tl = 0, tr = 1, bl = 3, br = 2;
|
||||
|
||||
/* Calculate new coordinates of all corners. */
|
||||
w = fixmul(w, scale_x);
|
||||
h = fixmul(h, scale_y);
|
||||
cx = fixmul(cx, scale_x);
|
||||
cy = fixmul(cy, scale_y);
|
||||
|
||||
fixed xofs = x - fixmul(cx, fix_cos) + fixmul(cy, fix_sin);
|
||||
fixed yofs = y - fixmul(cx, fix_sin) - fixmul(cy, fix_cos);
|
||||
|
||||
xs[tl] = xofs;
|
||||
ys[tl] = yofs;
|
||||
xs[tr] = xofs + fixmul(w, fix_cos);
|
||||
ys[tr] = yofs + fixmul(w, fix_sin);
|
||||
xs[bl] = xofs - fixmul(h, fix_sin);
|
||||
ys[bl] = yofs + fixmul(h, fix_cos);
|
||||
|
||||
xs[br] = xs[tr] + xs[bl] - xs[tl];
|
||||
ys[br] = ys[tr] + ys[bl] - ys[tl];
|
||||
}
|
||||
|
||||
/* parallelogram_map:
|
||||
* Worker routine for drawing rotated and/or scaled and/or flipped sprites:
|
||||
* It actually maps the sprite to any parallelogram-shaped area of the
|
||||
* bitmap. The top left corner is mapped to (xs[0], ys[0]), the top right to
|
||||
* (xs[1], ys[1]), the bottom right to x (xs[2], ys[2]), and the bottom left
|
||||
* to (xs[3], ys[3]). The corners are assumed to form a perfect
|
||||
* parallelogram, i.e. xs[0]+xs[2] = xs[1]+xs[3]. The corners are given in
|
||||
* fixed point format, so xs[] and ys[] are coordinates of the outer corners
|
||||
* of corner pixels in clockwise order beginning with top left.
|
||||
* All coordinates begin with 0 in top left corner of pixel (0, 0). So a
|
||||
* rotation by 0 degrees of a sprite to the top left of a bitmap can be
|
||||
* specified with coordinates (0, 0) for the top left pixel in source
|
||||
* bitmap. With the default scanline drawer, a pixel in the destination
|
||||
* bitmap is drawn if and only if its center is covered by any pixel in the
|
||||
* sprite. The color of this covering sprite pixel is used to draw.
|
||||
*/
|
||||
void parallelogram_map(BITMAP *bmp, const BITMAP *spr, fixed xs[4], fixed ys[4]) {
|
||||
// Get index of topmost point.
|
||||
int top_index = 0;
|
||||
if (ys[1] < ys[0])
|
||||
top_index = 1;
|
||||
if (ys[2] < ys[top_index])
|
||||
top_index = 2;
|
||||
if (ys[3] < ys[top_index])
|
||||
top_index = 3;
|
||||
|
||||
// Get direction of points: clockwise or anti-clockwise.
|
||||
int right_index = (double)(xs[(top_index+1) & 3] - xs[top_index]) *
|
||||
(double)(ys[(top_index-1) & 3] - ys[top_index]) >
|
||||
(double)(xs[(top_index-1) & 3] - xs[top_index]) *
|
||||
(double)(ys[(top_index+1) & 3] - ys[top_index]) ? 1 : -1;
|
||||
|
||||
// Get coordinates of the corners.
|
||||
// Coordinates in bmp and sprite ordered as top-right-bottom-left.
|
||||
fixed corner_bmp_x[4], corner_bmp_y[4];
|
||||
fixed corner_spr_x[4], corner_spr_y[4];
|
||||
int index = top_index;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
corner_bmp_x[i] = xs[index];
|
||||
corner_bmp_y[i] = ys[index];
|
||||
if (index < 2)
|
||||
corner_spr_y[i] = 0;
|
||||
else
|
||||
// Need `- 1' since otherwise it would be outside sprite.
|
||||
corner_spr_y[i] = (spr->h << 16) - 1;
|
||||
if ((index == 0) || (index == 3))
|
||||
corner_spr_x[i] = 0;
|
||||
else
|
||||
corner_spr_x[i] = (spr->w << 16) - 1;
|
||||
index = (index + right_index) & 3;
|
||||
}
|
||||
|
||||
// Get scanline starts, ends and deltas, and clipping coordinates.
|
||||
#define top_bmp_y corner_bmp_y[0]
|
||||
#define right_bmp_y corner_bmp_y[1]
|
||||
#define bottom_bmp_y corner_bmp_y[2]
|
||||
#define left_bmp_y corner_bmp_y[3]
|
||||
#define top_bmp_x corner_bmp_x[0]
|
||||
#define right_bmp_x corner_bmp_x[1]
|
||||
#define bottom_bmp_x corner_bmp_x[2]
|
||||
#define left_bmp_x corner_bmp_x[3]
|
||||
#define top_spr_y corner_spr_y[0]
|
||||
#define right_spr_y corner_spr_y[1]
|
||||
#define bottom_spr_y corner_spr_y[2]
|
||||
#define left_spr_y corner_spr_y[3]
|
||||
#define top_spr_x corner_spr_x[0]
|
||||
#define right_spr_x corner_spr_x[1]
|
||||
#define bottom_spr_x corner_spr_x[2]
|
||||
#define left_spr_x corner_spr_x[3]
|
||||
|
||||
// Calculate left and right clipping.
|
||||
fixed clip_left, clip_right;
|
||||
if (bmp->clip) {
|
||||
clip_left = bmp->cl << 16;
|
||||
clip_right = (bmp->cr << 16) - 1;
|
||||
} else {
|
||||
clip_left = 0;
|
||||
clip_right = (bmp->w << 16) - 1;
|
||||
}
|
||||
|
||||
// Stop if we're totally outside.
|
||||
if ((left_bmp_x > clip_right) && (top_bmp_x > clip_right) && (bottom_bmp_x > clip_right))
|
||||
return;
|
||||
if ((right_bmp_x < clip_left) && (top_bmp_x < clip_left) && (bottom_bmp_x < clip_left))
|
||||
return;
|
||||
|
||||
// Bottom clipping.
|
||||
int clip_bottom_i = (bottom_bmp_y + 0x8000) >> 16;
|
||||
if (bmp->clip) {
|
||||
if (clip_bottom_i > bmp->cb)
|
||||
clip_bottom_i = bmp->cb;
|
||||
}
|
||||
|
||||
// Calculate y coordinate of first scanline.
|
||||
int bmp_y_i = (top_bmp_y + 0x8000) >> 16;
|
||||
if (bmp->clip) {
|
||||
if (bmp_y_i < bmp->ct)
|
||||
bmp_y_i = bmp->ct;
|
||||
}
|
||||
|
||||
// Sprite is above or below bottom clipping area.
|
||||
if (bmp_y_i >= clip_bottom_i)
|
||||
return;
|
||||
|
||||
// Vertical gap between top corner and centre of topmost scanline.
|
||||
fixed extra_scanline_fraction = (bmp_y_i << 16) + 0x8000 - top_bmp_y;
|
||||
// Calculate x coordinate of beginning of scanline in bmp.
|
||||
fixed l_bmp_dx = fixdiv(left_bmp_x - top_bmp_x, left_bmp_y - top_bmp_y);
|
||||
fixed l_bmp_x = top_bmp_x + fixmul(extra_scanline_fraction, l_bmp_dx);
|
||||
// Calculate x coordinate of beginning of scanline in spr.
|
||||
// note: all these are rounded down which is probably a Good Thing (tm)
|
||||
fixed l_spr_dx = fixdiv(left_spr_x - top_spr_x, left_bmp_y - top_bmp_y);
|
||||
fixed l_spr_x = top_spr_x + fixmul(extra_scanline_fraction, l_spr_dx);
|
||||
// Calculate y coordinate of beginning of scanline in spr.
|
||||
fixed l_spr_dy = fixdiv(left_spr_y - top_spr_y, left_bmp_y - top_bmp_y);
|
||||
fixed l_spr_y = top_spr_y + fixmul(extra_scanline_fraction, l_spr_dy);
|
||||
|
||||
// Calculate left loop bound.
|
||||
int l_bmp_y_bottom_i = (left_bmp_y + 0x8000) >> 16;
|
||||
if (l_bmp_y_bottom_i > clip_bottom_i)
|
||||
l_bmp_y_bottom_i = clip_bottom_i;
|
||||
|
||||
// Calculate x coordinate of end of scanline in bmp.
|
||||
fixed r_bmp_dx = fixdiv(right_bmp_x - top_bmp_x, right_bmp_y - top_bmp_y);
|
||||
fixed r_bmp_x = top_bmp_x + fixmul(extra_scanline_fraction, r_bmp_dx);
|
||||
|
||||
// Calculate right loop bound.
|
||||
int r_bmp_y_bottom_i = (right_bmp_y + 0x8000) >> 16;
|
||||
|
||||
// Get dx and dy, the offsets to add to the source coordinates as we move
|
||||
// one pixel rightwards along a scanline. This formula can be derived by
|
||||
// considering the 2x2 matrix that transforms the sprite to the
|
||||
// parallelogram.
|
||||
// We'd better use double to get this as exact as possible, since any
|
||||
// errors will be accumulated along the scanline.
|
||||
fixed spr_dx = (fixed)((ys[3] - ys[0]) * 65536.0 * (65536.0 * spr->w) /
|
||||
((xs[1] - xs[0]) * (double)(ys[3] - ys[0]) - (xs[3] - xs[0]) * (double)(ys[1] - ys[0])));
|
||||
fixed spr_dy = (fixed)((ys[1] - ys[0]) * 65536.0 * (65536.0 * spr->h) /
|
||||
((xs[3] - xs[0]) * (double)(ys[1] - ys[0]) - (xs[1] - xs[0]) * (double)(ys[3] - ys[0])));
|
||||
|
||||
bool sameFormat = (spr->format == bmp->format);
|
||||
uint32 transColor = 0, alphaMask = 0xff;
|
||||
if (spr->format.bytesPerPixel != 1) {
|
||||
transColor = spr->format.ARGBToColor(0, 255, 0, 255);
|
||||
alphaMask = spr->format.ARGBToColor(255, 0, 0, 0);
|
||||
alphaMask = ~alphaMask;
|
||||
}
|
||||
|
||||
// Loop through scanlines.
|
||||
while (1) {
|
||||
// Has beginning of scanline passed a corner?
|
||||
if (bmp_y_i >= l_bmp_y_bottom_i) {
|
||||
// Are we done?
|
||||
if (bmp_y_i >= clip_bottom_i)
|
||||
break;
|
||||
|
||||
// Vertical gap between left corner and centre of scanline.
|
||||
extra_scanline_fraction = (bmp_y_i << 16) + 0x8000 - left_bmp_y;
|
||||
// Update x coordinate of beginning of scanline in bmp.
|
||||
l_bmp_dx = fixdiv(bottom_bmp_x - left_bmp_x, bottom_bmp_y - left_bmp_y);
|
||||
l_bmp_x = left_bmp_x + fixmul(extra_scanline_fraction, l_bmp_dx);
|
||||
// Update x coordinate of beginning of scanline in spr.
|
||||
l_spr_dx = fixdiv(bottom_spr_x - left_spr_x, bottom_bmp_y - left_bmp_y);
|
||||
l_spr_x = left_spr_x + fixmul(extra_scanline_fraction, l_spr_dx);
|
||||
// Update y coordinate of beginning of scanline in spr.
|
||||
l_spr_dy = fixdiv(bottom_spr_y - left_spr_y, bottom_bmp_y - left_bmp_y);
|
||||
l_spr_y = left_spr_y + fixmul(extra_scanline_fraction, l_spr_dy);
|
||||
|
||||
// Update loop bound.
|
||||
l_bmp_y_bottom_i = (bottom_bmp_y + 0x8000) >> 16;
|
||||
if (l_bmp_y_bottom_i > clip_bottom_i)
|
||||
l_bmp_y_bottom_i = clip_bottom_i;
|
||||
}
|
||||
|
||||
// Has end of scanline passed a corner?
|
||||
if (bmp_y_i >= r_bmp_y_bottom_i) {
|
||||
// Vertical gap between right corner and centre of scanline.
|
||||
extra_scanline_fraction = (bmp_y_i << 16) + 0x8000 - right_bmp_y;
|
||||
// Update x coordinate of end of scanline in bmp.
|
||||
r_bmp_dx = fixdiv(bottom_bmp_x - right_bmp_x, bottom_bmp_y - right_bmp_y);
|
||||
r_bmp_x = right_bmp_x + fixmul(extra_scanline_fraction, r_bmp_dx);
|
||||
|
||||
// Update loop bound: We aren't supposed to use this any more, so
|
||||
// just set it to some big enough value.
|
||||
r_bmp_y_bottom_i = clip_bottom_i;
|
||||
}
|
||||
|
||||
// Make left bmp coordinate be an integer and clip it.
|
||||
fixed l_bmp_x_rounded;
|
||||
l_bmp_x_rounded = (l_bmp_x + 0x8000) & ~0xffff;
|
||||
if (l_bmp_x_rounded < clip_left)
|
||||
l_bmp_x_rounded = clip_left;
|
||||
|
||||
// ... and move starting point in sprite accordingly.
|
||||
fixed l_spr_x_rounded = l_spr_x + fixmul(l_bmp_x_rounded + 0x7fff - l_bmp_x, spr_dx);
|
||||
fixed l_spr_y_rounded = l_spr_y + fixmul(l_bmp_x_rounded + 0x7fff - l_bmp_x, spr_dy);
|
||||
|
||||
// Make right bmp coordinate be an integer and clip it.
|
||||
fixed r_bmp_x_rounded = (r_bmp_x - 0x8000) & ~0xffff;
|
||||
if (r_bmp_x_rounded > clip_right)
|
||||
r_bmp_x_rounded = clip_right;
|
||||
|
||||
// Draw!
|
||||
if (l_bmp_x_rounded <= r_bmp_x_rounded) {
|
||||
/* The bodies of these ifs are only reached extremely seldom,
|
||||
it's an ugly hack to avoid reading outside the sprite when
|
||||
the rounding errors are accumulated the wrong way. It would
|
||||
be nicer if we could ensure that this never happens by making
|
||||
all multiplications and divisions be rounded up or down at
|
||||
the correct places.
|
||||
I did try another approach: recalculate the edges of the
|
||||
scanline from scratch each scanline rather than incrementally.
|
||||
Drawing a sprite with that routine took about 25% longer time
|
||||
though.
|
||||
*/
|
||||
if ((unsigned)(l_spr_x_rounded >> 16) >= (unsigned)spr->w) {
|
||||
if (((l_spr_x_rounded < 0) && (spr_dx <= 0)) || ((l_spr_x_rounded > 0) && (spr_dx >= 0))) {
|
||||
// This can happen.
|
||||
goto skip_draw;
|
||||
} else {
|
||||
// I don't think this can happen, but I can't prove it.
|
||||
do {
|
||||
l_spr_x_rounded += spr_dx;
|
||||
l_bmp_x_rounded += 65536;
|
||||
if (l_bmp_x_rounded > r_bmp_x_rounded)
|
||||
goto skip_draw;
|
||||
} while ((unsigned)(l_spr_x_rounded >> 16) >= (unsigned)spr->w);
|
||||
}
|
||||
}
|
||||
int right_edge_test = l_spr_x_rounded + ((r_bmp_x_rounded - l_bmp_x_rounded) >> 16) * spr_dx;
|
||||
if ((unsigned)(right_edge_test >> 16) >= (unsigned)spr->w) {
|
||||
if (((right_edge_test < 0) && (spr_dx <= 0)) || ((right_edge_test > 0) && (spr_dx >= 0))) {
|
||||
// This can happen.
|
||||
do {
|
||||
r_bmp_x_rounded -= 65536;
|
||||
right_edge_test -= spr_dx;
|
||||
if (l_bmp_x_rounded > r_bmp_x_rounded)
|
||||
goto skip_draw;
|
||||
} while ((unsigned)(right_edge_test >> 16) >= (unsigned)spr->w);
|
||||
} else {
|
||||
// I don't think this can happen, but I can't prove it.
|
||||
goto skip_draw;
|
||||
}
|
||||
}
|
||||
if ((unsigned)(l_spr_y_rounded >> 16) >= (unsigned)spr->h) {
|
||||
if (((l_spr_y_rounded < 0) && (spr_dy <= 0)) || ((l_spr_y_rounded > 0) && (spr_dy >= 0))) {
|
||||
// This can happen.
|
||||
goto skip_draw;
|
||||
} else {
|
||||
// I don't think this can happen, but I can't prove it.
|
||||
do {
|
||||
l_spr_y_rounded += spr_dy;
|
||||
l_bmp_x_rounded += 65536;
|
||||
if (l_bmp_x_rounded > r_bmp_x_rounded)
|
||||
goto skip_draw;
|
||||
} while (((unsigned)l_spr_y_rounded >> 16) >= (unsigned)spr->h);
|
||||
}
|
||||
}
|
||||
right_edge_test = l_spr_y_rounded + ((r_bmp_x_rounded - l_bmp_x_rounded) >> 16) * spr_dy;
|
||||
if ((unsigned)(right_edge_test >> 16) >= (unsigned)spr->h) {
|
||||
if (((right_edge_test < 0) && (spr_dy <= 0)) || ((right_edge_test > 0) && (spr_dy >= 0))) {
|
||||
// This can happen.
|
||||
do {
|
||||
r_bmp_x_rounded -= 65536;
|
||||
right_edge_test -= spr_dy;
|
||||
if (l_bmp_x_rounded > r_bmp_x_rounded)
|
||||
goto skip_draw;
|
||||
} while ((unsigned)(right_edge_test >> 16) >= (unsigned)spr->h);
|
||||
} else {
|
||||
// I don't think this can happen, but I can't prove it.
|
||||
goto skip_draw;
|
||||
}
|
||||
}
|
||||
|
||||
// draw scanline
|
||||
int r_bmp_x_i = (r_bmp_x_rounded >> 16);
|
||||
int l_bmp_x_i = (l_bmp_x_rounded >> 16);
|
||||
for (; l_bmp_x_i <= r_bmp_x_i; ++l_bmp_x_i) {
|
||||
uint32 c = (uint32)getpixel(spr, l_spr_x_rounded >> 16, l_spr_y_rounded >> 16);
|
||||
if ((c & alphaMask) != transColor) {
|
||||
if (!sameFormat) {
|
||||
uint8 a, r, g, b;
|
||||
spr->format.colorToARGB(c, a, r, g, b);
|
||||
c = bmp->format.ARGBToColor(a, r, g, b);
|
||||
}
|
||||
putpixel(bmp, l_bmp_x_i, bmp_y_i, c);
|
||||
}
|
||||
l_spr_x_rounded += spr_dx;
|
||||
l_spr_y_rounded += spr_dy;
|
||||
}
|
||||
}
|
||||
// I'm not going to apoligize for this label and its gotos.
|
||||
// to get rid of it would just make the code look worse.
|
||||
skip_draw:
|
||||
|
||||
// Jump to next scanline.
|
||||
bmp_y_i++;
|
||||
// Update beginning of scanline.
|
||||
l_bmp_x += l_bmp_dx;
|
||||
l_spr_x += l_spr_dx;
|
||||
l_spr_y += l_spr_dy;
|
||||
// Update end of scanline.
|
||||
r_bmp_x += r_bmp_dx;
|
||||
}
|
||||
}
|
||||
|
||||
void pivot_scaled_sprite(BITMAP *bmp, const BITMAP *sprite, fixed x, fixed y, fixed cx, fixed cy, fixed angle, fixed scale) {
|
||||
fixed xs[4], ys[4];
|
||||
rotate_scale_coordinates(sprite->w << 16, sprite->h << 16,
|
||||
x, y, cx, cy, angle, scale, scale, xs, ys);
|
||||
parallelogram_map(bmp, sprite, xs, ys);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
35
engines/ags/lib/allegro/rotate.h
Normal file
35
engines/ags/lib/allegro/rotate.h
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_ROTATE_H
|
||||
#define AGS_LIB_ALLEGRO_ROTATE_H
|
||||
|
||||
#include "ags/lib/allegro/surface.h"
|
||||
#include "ags/lib/allegro/fixed.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
extern void pivot_scaled_sprite(BITMAP *bmp, const BITMAP *sprite, fixed x, fixed y, fixed cx, fixed cy, fixed angle, fixed scale);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
398
engines/ags/lib/allegro/surface.cpp
Normal file
398
engines/ags/lib/allegro/surface.cpp
Normal file
@@ -0,0 +1,398 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/lib/allegro/flood.h"
|
||||
#include "ags/ags.h"
|
||||
#include "ags/globals.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/screen.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
BITMAP::BITMAP(Graphics::ManagedSurface *owner) : _owner(owner),
|
||||
w(owner->w), h(owner->h), pitch(owner->pitch), format(owner->format),
|
||||
clip(true), ct(0), cl(0), cr(owner->w), cb(owner->h) {
|
||||
line.resize(h);
|
||||
for (int y = 0; y < h; ++y)
|
||||
line[y] = (byte *)_owner->getBasePtr(0, y);
|
||||
}
|
||||
|
||||
int BITMAP::getpixel(int x, int y) const {
|
||||
if (x < 0 || y < 0 || x >= w || y >= h)
|
||||
return -1;
|
||||
|
||||
const byte *pixel = (const byte *)getBasePtr(x, y);
|
||||
if (format.bytesPerPixel == 1)
|
||||
return *pixel;
|
||||
else if (format.bytesPerPixel == 2)
|
||||
return *(const uint16 *)pixel;
|
||||
else
|
||||
return *(const uint32 *)pixel;
|
||||
}
|
||||
|
||||
void BITMAP::makeOpaque() {
|
||||
if (format.aBits() == 0)
|
||||
return;
|
||||
assert(format.bytesPerPixel == 4);
|
||||
uint32 alphaMask = format.ARGBToColor(0xff, 0, 0, 0);
|
||||
|
||||
unsigned char *pixels = getPixels();
|
||||
for (int y = 0 ; y < h ; ++y, pixels += pitch) {
|
||||
uint32 *data = (uint32 *)pixels;
|
||||
for (int x = 0 ; x < w ; ++x, ++data)
|
||||
(*data) |= alphaMask;
|
||||
}
|
||||
}
|
||||
|
||||
void BITMAP::circlefill(int x, int y, int radius, int color) {
|
||||
int cx = 0;
|
||||
int cy = radius;
|
||||
int df = 1 - radius;
|
||||
int d_e = 3;
|
||||
int d_se = -2 * radius + 5;
|
||||
|
||||
do {
|
||||
_owner->hLine(x - cy, y - cx, x + cy, color);
|
||||
|
||||
if (cx)
|
||||
_owner->hLine(x - cy, y + cx, x + cy, color);
|
||||
|
||||
if (df < 0) {
|
||||
df += d_e;
|
||||
d_e += 2;
|
||||
d_se += 2;
|
||||
} else {
|
||||
if (cx != cy) {
|
||||
_owner->hLine(x - cx, y - cy, x + cx, color);
|
||||
|
||||
if (cy)
|
||||
_owner->hLine(x - cx, y + cy, x + cx, color);
|
||||
}
|
||||
|
||||
df += d_se;
|
||||
d_e += 2;
|
||||
d_se += 4;
|
||||
cy--;
|
||||
}
|
||||
|
||||
cx++;
|
||||
|
||||
} while (cx <= cy);
|
||||
}
|
||||
|
||||
void BITMAP::floodfill(int x, int y, int color) {
|
||||
AGS3::floodfill(this, x, y, color);
|
||||
}
|
||||
|
||||
#define VGA_COLOR_TRANS(x) ((x) * 255 / 63)
|
||||
|
||||
BITMAP::DrawInnerArgs::DrawInnerArgs(BITMAP *_dstBitmap, const BITMAP *srcBitmap,
|
||||
const Common::Rect &srcRect, const Common::Rect &_dstRect, bool _skipTrans,
|
||||
int _srcAlpha, bool _horizFlip, bool _vertFlip, int _tintRed,
|
||||
int _tintGreen, int _tintBlue, bool doScale) : skipTrans(_skipTrans),
|
||||
srcAlpha(_srcAlpha), horizFlip(_horizFlip), vertFlip(_vertFlip),
|
||||
tintRed(_tintRed), tintGreen(_tintGreen), tintBlue(_tintBlue),
|
||||
src(**srcBitmap), shouldDraw(false), dstBitmap(*_dstBitmap),
|
||||
useTint(_tintRed >= 0 && _tintGreen >= 0 && _tintBlue >= 0),
|
||||
blenderMode(_G(_blender_mode)), dstRect(_dstRect) {
|
||||
// Allegro disables draw when the clipping rect has negative width/height.
|
||||
// Common::Rect instead asserts, which we don't want.
|
||||
if (dstBitmap.cr <= dstBitmap.cl || dstBitmap.cb <= dstBitmap.ct)
|
||||
return;
|
||||
|
||||
// Figure out the dest area that will be updated
|
||||
srcArea = srcRect;
|
||||
srcArea.clip(Common::Rect(0, 0, srcBitmap->w, srcBitmap->h));
|
||||
if (srcArea.isEmpty())
|
||||
return;
|
||||
|
||||
if (!doScale) {
|
||||
// Ensure the src rect is constrained to the source bitmap
|
||||
dstRect.setWidth(srcArea.width());
|
||||
dstRect.setHeight(srcArea.height());
|
||||
}
|
||||
Common::Rect destRect = dstRect.findIntersectingRect(
|
||||
Common::Rect(dstBitmap.cl, dstBitmap.ct, dstBitmap.cr, dstBitmap.cb));
|
||||
if (destRect.isEmpty())
|
||||
// Area is entirely outside the clipping area, so nothing to draw
|
||||
return;
|
||||
|
||||
// Get source and dest surface. Note that for the destination we create
|
||||
// a temporary sub-surface based on the allowed clipping area
|
||||
Graphics::ManagedSurface &dest = *dstBitmap._owner;
|
||||
destArea = dest.getSubArea(destRect);
|
||||
|
||||
// Define scaling and other stuff used by the drawing loops
|
||||
scaleX = SCALE_THRESHOLD * srcRect.width() / dstRect.width();
|
||||
scaleY = SCALE_THRESHOLD * srcRect.height() / dstRect.height();
|
||||
sameFormat = (src.format == dstBitmap.format);
|
||||
|
||||
if (src.format.bytesPerPixel == 1 && dstBitmap.format.bytesPerPixel != 1) {
|
||||
for (int i = 0; i < PAL_SIZE; ++i) {
|
||||
palette[i].r = VGA_COLOR_TRANS(_G(current_palette)[i].r);
|
||||
palette[i].g = VGA_COLOR_TRANS(_G(current_palette)[i].g);
|
||||
palette[i].b = VGA_COLOR_TRANS(_G(current_palette)[i].b);
|
||||
}
|
||||
}
|
||||
|
||||
transColor = 0, alphaMask = 0xff;
|
||||
if (skipTrans && src.format.bytesPerPixel != 1) {
|
||||
transColor = src.format.ARGBToColor(0, 255, 0, 255);
|
||||
alphaMask = src.format.ARGBToColor(255, 0, 0, 0);
|
||||
alphaMask = ~alphaMask;
|
||||
}
|
||||
|
||||
xStart = (dstRect.left < destRect.left) ? dstRect.left - destRect.left : 0;
|
||||
yStart = (dstRect.top < destRect.top) ? dstRect.top - destRect.top : 0;
|
||||
shouldDraw = true;
|
||||
}
|
||||
|
||||
void BITMAP::draw(const BITMAP *srcBitmap, const Common::Rect &srcRect,
|
||||
int dstX, int dstY, bool horizFlip, bool vertFlip,
|
||||
bool skipTrans, int srcAlpha, int tintRed, int tintGreen,
|
||||
int tintBlue) {
|
||||
|
||||
// A restricted number of 8bit games (e.g. Snow Problem) contain (leftover?) 32bit resources.
|
||||
// We can ignore these to prevent conversion on load (and triggering the assertion)
|
||||
if (format.bytesPerPixel == 1 && srcBitmap->format.bytesPerPixel != 1) {
|
||||
warning("Attempt to draw >1BPP surface onto 1BPP surface, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(format.bytesPerPixel == 2 || format.bytesPerPixel == 4 ||
|
||||
(format.bytesPerPixel == 1 && srcBitmap->format.bytesPerPixel == 1));
|
||||
|
||||
Graphics::ManagedSurface flipped;
|
||||
if (horizFlip || vertFlip) {
|
||||
// Horizontal flipping produces errors in the optimized paths, while vertical
|
||||
// may result in crashes. For now, we pre-flip to a temporary surface
|
||||
Graphics::ManagedSurface cropped(const_cast<BITMAP *>(srcBitmap)->getSurface(), srcRect);
|
||||
flipped.copyFrom(cropped);
|
||||
|
||||
if (horizFlip) {
|
||||
flipped.surfacePtr()->flipHorizontal(flipped.getBounds());
|
||||
}
|
||||
|
||||
if (vertFlip) {
|
||||
flipped.surfacePtr()->flipVertical(flipped.getBounds());
|
||||
}
|
||||
}
|
||||
BITMAP temp(&flipped);
|
||||
|
||||
auto args = DrawInnerArgs(this, (horizFlip || vertFlip) ? &temp : srcBitmap, (horizFlip || vertFlip) ? flipped.getBounds() : srcRect, Common::Rect(dstX, dstY, dstX + 1, dstY + 1), skipTrans, srcAlpha, false, false, tintRed, tintGreen, tintBlue, false);
|
||||
if (!args.shouldDraw) return;
|
||||
if (!args.sameFormat && args.src.format.bytesPerPixel == 1) {
|
||||
if (format.bytesPerPixel == 4)
|
||||
drawInnerGeneric<4, 1, false>(args);
|
||||
else
|
||||
drawInnerGeneric<2, 1, false>(args);
|
||||
return;
|
||||
}
|
||||
#ifdef SCUMMVM_NEON
|
||||
if (_G(simd_flags) & AGS3::Globals::SIMD_NEON) {
|
||||
drawNEON<false>(args);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef SCUMMVM_AVX2
|
||||
if (_G(simd_flags) & AGS3::Globals::SIMD_AVX2) {
|
||||
drawAVX2<false>(args);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef SCUMMVM_SSE2
|
||||
if (_G(simd_flags) & AGS3::Globals::SIMD_SSE2) {
|
||||
drawSSE2<false>(args);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
drawGeneric<false>(args);
|
||||
}
|
||||
|
||||
void BITMAP::stretchDraw(const BITMAP *srcBitmap, const Common::Rect &srcRect,
|
||||
const Common::Rect &dstRect, bool skipTrans, int srcAlpha) {
|
||||
assert(format.bytesPerPixel == 2 || format.bytesPerPixel == 4 ||
|
||||
(format.bytesPerPixel == 1 && srcBitmap->format.bytesPerPixel == 1));
|
||||
auto args = DrawInnerArgs(this, srcBitmap, srcRect, dstRect, skipTrans, srcAlpha, false, false, -1, -1, -1, true);
|
||||
if (!args.shouldDraw) return;
|
||||
if (!args.sameFormat && args.src.format.bytesPerPixel == 1) {
|
||||
if (format.bytesPerPixel == 4)
|
||||
drawInnerGeneric<4, 1, true>(args);
|
||||
else
|
||||
drawInnerGeneric<2, 1, true>(args);
|
||||
return;
|
||||
}
|
||||
|
||||
// Stretching at the same time as blitting produces errors when
|
||||
// using the optimized paths; for now, we pre-stretch to a temporary surface
|
||||
Graphics::ManagedSurface cropped(const_cast<BITMAP *>(srcBitmap)->getSurface(), srcRect);
|
||||
// We need to use Surface::scale, since ManagedSurface _always_ respects the source alpha, and thus skips transparent pixels
|
||||
Graphics::ManagedSurface *stretched = cropped.scale(dstRect.width(), dstRect.height());
|
||||
BITMAP temp(stretched);
|
||||
auto optimizedArgs = DrawInnerArgs(this, &temp, stretched->getBounds(), dstRect, skipTrans, srcAlpha, false, false, -1, -1, -1, false);
|
||||
|
||||
#ifdef SCUMMVM_NEON
|
||||
if (_G(simd_flags) & AGS3::Globals::SIMD_NEON) {
|
||||
drawNEON<false>(optimizedArgs);
|
||||
} else
|
||||
#endif
|
||||
#ifdef SCUMMVM_AVX2
|
||||
if (_G(simd_flags) & AGS3::Globals::SIMD_AVX2) {
|
||||
drawAVX2<false>(optimizedArgs);
|
||||
} else
|
||||
#endif
|
||||
#ifdef SCUMMVM_SSE2
|
||||
if (_G(simd_flags) & AGS3::Globals::SIMD_SSE2) {
|
||||
drawSSE2<false>(optimizedArgs);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
drawGeneric<true>(optimizedArgs);
|
||||
}
|
||||
|
||||
delete stretched;
|
||||
}
|
||||
void BITMAP::blendPixel(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha, bool useTint, byte *destVal) const {
|
||||
switch (_G(_blender_mode)) {
|
||||
case kSourceAlphaBlender:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendSourceAlpha(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kArgbToArgbBlender:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendArgbToArgb(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kArgbToRgbBlender:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendArgbToRgb(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kRgbToArgbBlender:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendRgbToArgb(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kRgbToRgbBlender:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendRgbToRgb(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kAlphaPreservedBlenderMode:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendPreserveAlpha(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kOpaqueBlenderMode:
|
||||
blendOpaque(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kAdditiveBlenderMode:
|
||||
if (!useTint) format.colorToARGB(getColor(destVal, format.bytesPerPixel), aDest, rDest, gDest, bDest);
|
||||
blendAdditiveAlpha(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha);
|
||||
break;
|
||||
case kTintBlenderMode:
|
||||
blendTintSprite(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha, false);
|
||||
break;
|
||||
case kTintLightBlenderMode:
|
||||
blendTintSprite(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, alpha, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BITMAP::blendTintSprite(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha, bool light) const {
|
||||
// Used from draw_lit_sprite after set_blender_mode(kTintBlenderMode or kTintLightBlenderMode)
|
||||
// Original blender function: _myblender_color32 and _myblender_color32_light
|
||||
float xh, xs, xv;
|
||||
float yh, ys, yv;
|
||||
int r, g, b;
|
||||
rgb_to_hsv(rSrc, gSrc, bSrc, &xh, &xs, &xv);
|
||||
rgb_to_hsv(rDest, gDest, bDest, &yh, &ys, &yv);
|
||||
if (light) {
|
||||
// adjust luminance
|
||||
// (I think the writer meant value, since they are using hsV)
|
||||
yv -= (1.0 - ((float)alpha / 250.0));
|
||||
if (yv < 0.0)
|
||||
yv = 0.0;
|
||||
}
|
||||
hsv_to_rgb(xh, xs, yv, &r, &g, &b);
|
||||
rDest = static_cast<uint8>(r & 0xff);
|
||||
gDest = static_cast<uint8>(g & 0xff);
|
||||
bDest = static_cast<uint8>(b & 0xff);
|
||||
// Preserve value in aDest
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Dervied screen surface
|
||||
*/
|
||||
class Screen : public Graphics::Screen, public BITMAP {
|
||||
public:
|
||||
Screen() : Graphics::Screen(), BITMAP(this) {}
|
||||
Screen(int width, int height) : Graphics::Screen(width, height), BITMAP(this) {}
|
||||
Screen(int width, int height, const Graphics::PixelFormat &pixelFormat) :
|
||||
Graphics::Screen(width, height, pixelFormat), BITMAP(this) {}
|
||||
~Screen() override {}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
BITMAP *create_bitmap(int width, int height) {
|
||||
return create_bitmap_ex(get_color_depth(), width, height);
|
||||
}
|
||||
|
||||
BITMAP *create_bitmap_ex(int color_depth, int width, int height) {
|
||||
Graphics::PixelFormat format;
|
||||
|
||||
switch (color_depth) {
|
||||
case 8:
|
||||
format = Graphics::PixelFormat::createFormatCLUT8();
|
||||
break;
|
||||
case 16:
|
||||
format = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
|
||||
break;
|
||||
case 32:
|
||||
format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
|
||||
break;
|
||||
default:
|
||||
error("Invalid color depth");
|
||||
}
|
||||
width = MAX(width, 0);
|
||||
height = MAX(height, 0);
|
||||
BITMAP *bitmap = new Surface(width, height, format);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
BITMAP *create_sub_bitmap(BITMAP *parent, int x, int y, int width, int height) {
|
||||
Graphics::ManagedSurface &surf = **parent;
|
||||
return new Surface(surf, Common::Rect(x, y, x + width, y + height));
|
||||
}
|
||||
|
||||
BITMAP *create_video_bitmap(int width, int height) {
|
||||
return new Screen(width, height);
|
||||
}
|
||||
|
||||
BITMAP *create_system_bitmap(int width, int height) {
|
||||
return create_bitmap(width, height);
|
||||
}
|
||||
|
||||
void destroy_bitmap(BITMAP *bitmap) {
|
||||
delete bitmap;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
356
engines/ags/lib/allegro/surface.h
Normal file
356
engines/ags/lib/allegro/surface.h
Normal file
@@ -0,0 +1,356 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_SURFACE_H
|
||||
#define AGS_LIB_ALLEGRO_SURFACE_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "ags/lib/allegro/base.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
class BITMAP {
|
||||
private:
|
||||
Graphics::ManagedSurface *_owner;
|
||||
public:
|
||||
int16 &w, &h;
|
||||
int32 &pitch;
|
||||
Graphics::PixelFormat &format;
|
||||
bool clip;
|
||||
int ct, cb, cl, cr;
|
||||
Common::Array<byte *> line;
|
||||
public:
|
||||
BITMAP(Graphics::ManagedSurface *owner);
|
||||
virtual ~BITMAP() {
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface &operator*() const {
|
||||
return *_owner;
|
||||
}
|
||||
Graphics::ManagedSurface &getSurface() {
|
||||
return *_owner;
|
||||
}
|
||||
const Graphics::ManagedSurface &getSurface() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
||||
unsigned char *getPixels() const {
|
||||
return (unsigned char *)_owner->getPixels();
|
||||
}
|
||||
|
||||
unsigned char *getBasePtr(uint16 x, uint16 y) const {
|
||||
return (unsigned char *)_owner->getBasePtr(x, y);
|
||||
}
|
||||
|
||||
uint getTransparentColor() const {
|
||||
// See allegro bitmap_mask_color
|
||||
// For paletted sprites this is 0.
|
||||
// For other color depths this is bright pink (RGB 255, 0, 255) with alpha set to 0.
|
||||
if (format.bytesPerPixel == 1)
|
||||
return 0;
|
||||
return format.ARGBToColor(0, 255, 0, 255);
|
||||
}
|
||||
|
||||
inline const Common::Point getOffsetFromOwner() const {
|
||||
return _owner->getOffsetFromOwner();
|
||||
}
|
||||
|
||||
int getpixel(int x, int y) const;
|
||||
|
||||
void clear() {
|
||||
_owner->clear();
|
||||
}
|
||||
|
||||
void makeOpaque();
|
||||
|
||||
/**
|
||||
* Draws a solid filled in circle
|
||||
*/
|
||||
void circlefill(int x, int y, int radius, int color);
|
||||
|
||||
/**
|
||||
* Fills an enclosed area starting at a given point
|
||||
*/
|
||||
void floodfill(int x, int y, int color);
|
||||
|
||||
/**
|
||||
* Draw a horizontal line
|
||||
*/
|
||||
void hLine(int x, int y, int x2, uint32 color) {
|
||||
_owner->hLine(x, y, x2, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a vertical line.
|
||||
*/
|
||||
void vLine(int x, int y, int y2, uint32 color) {
|
||||
_owner->vLine(x, y, y2, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the passed surface onto this one
|
||||
*/
|
||||
void draw(const BITMAP *srcBitmap, const Common::Rect &srcRect,
|
||||
int dstX, int dstY, bool horizFlip, bool vertFlip,
|
||||
bool skipTrans, int srcAlpha, int tintRed = -1, int tintGreen = -1,
|
||||
int tintBlue = -1);
|
||||
|
||||
/**
|
||||
* Stretches and draws the passed surface onto this one
|
||||
*/
|
||||
void stretchDraw(const BITMAP *srcBitmap, const Common::Rect &srcRect,
|
||||
const Common::Rect &destRect, bool skipTrans, int srcAlpha);
|
||||
|
||||
inline bool isSubBitmap() const {
|
||||
return _owner->disposeAfterUse() == DisposeAfterUse::NO;
|
||||
}
|
||||
|
||||
private:
|
||||
// True color blender functions
|
||||
// In Allegro all the blender functions are of the form
|
||||
// unsigned int blender_func(unsigned long x, unsigned long y, unsigned long n)
|
||||
// when x is the sprite color, y the destination color, and n an alpha value
|
||||
|
||||
void blendPixel(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha, bool useTint, byte *destVal) const;
|
||||
|
||||
inline void rgbBlend(uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Note: the original's handling varies slightly for R & B vs G.
|
||||
// We need to exactly replicate it to ensure Lamplight City's
|
||||
// calendar puzzle works correctly
|
||||
if (alpha)
|
||||
alpha++;
|
||||
|
||||
uint32 x = ((uint32)rSrc << 16) | ((uint32)gSrc << 8) | (uint32)bSrc;
|
||||
uint32 y = ((uint32)rDest << 16) | ((uint32)gDest << 8) | (uint32)bDest;
|
||||
|
||||
uint32 res = ((x & 0xFF00FF) - (y & 0xFF00FF)) * alpha / 256 + y;
|
||||
y &= 0xFF00;
|
||||
x &= 0xFF00;
|
||||
uint32 g = (x - y) * alpha / 256 + y;
|
||||
|
||||
rDest = (res >> 16) & 0xff;
|
||||
gDest = (g >> 8) & 0xff;
|
||||
bDest = res & 0xff;
|
||||
}
|
||||
|
||||
inline void argbBlend(uint32 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest) const {
|
||||
// Original logic has uint32 src and dst colors as ARGB8888
|
||||
// ++src_alpha;
|
||||
// uint32 dst_alpha = geta32(dst);
|
||||
// if (dst_alpha)
|
||||
// ++dst_alpha;
|
||||
// uint32 dst_g = (dst & 0x00FF00) * dst_alpha / 256;
|
||||
// dst = (dst & 0xFF00FF) * dst_alpha / 256;
|
||||
// dst_g = (((src & 0x00FF00) - (dst_g & 0x00FF00)) * src_alpha / 256 + dst_g) & 0x00FF00;
|
||||
// dst = (((src & 0xFF00FF) - (dst & 0xFF00FF)) * src_alpha / 256 + dst) & 0xFF00FF;
|
||||
// dst_alpha = 256 - (256 - src_alpha) * (256 - dst_alpha) / 256;
|
||||
// src_alpha = /* 256 * 256 == */ 0x10000 / dst_alpha;
|
||||
// dst_g = (dst_g * src_alpha / 256) & 0x00FF00;
|
||||
// dst = (dst * src_alpha / 256) & 0xFF00FF;
|
||||
// return dst | dst_g | (--dst_alpha << 24);
|
||||
double sAlpha = (double)(aSrc & 0xff) / 255.0;
|
||||
double dAlpha = (double)aDest / 255.0;
|
||||
dAlpha *= (1.0 - sAlpha);
|
||||
rDest = static_cast<uint8>((rSrc * sAlpha + rDest * dAlpha) / (sAlpha + dAlpha));
|
||||
gDest = static_cast<uint8>((gSrc * sAlpha + gDest * dAlpha) / (sAlpha + dAlpha));
|
||||
bDest = static_cast<uint8>((bSrc * sAlpha + bDest * dAlpha) / (sAlpha + dAlpha));
|
||||
aDest = static_cast<uint8>(255. * (sAlpha + dAlpha));
|
||||
}
|
||||
|
||||
// kRgbToRgbBlender
|
||||
inline void blendRgbToRgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Default mode for set_trans_blender
|
||||
rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, alpha);
|
||||
// Original doesn't set alpha (so it is 0), but the function is not meant to be used
|
||||
// on bitmap with transparency. Should we set alpha to 0xff?
|
||||
aDest = 0;
|
||||
}
|
||||
|
||||
// kAlphaPreservedBlenderMode
|
||||
inline void blendPreserveAlpha(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Original blender function: _myblender_alpha_trans24
|
||||
// Like blendRgbToRgb, but result as the same alpha as destColor
|
||||
rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, alpha);
|
||||
// Preserve value in aDest
|
||||
}
|
||||
|
||||
// kArgbToArgbBlender
|
||||
inline void blendArgbToArgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Original blender functions: _argb2argb_blender
|
||||
if (alpha == 0)
|
||||
alpha = aSrc;
|
||||
else
|
||||
alpha = aSrc * ((alpha & 0xff) + 1) / 256;
|
||||
if (alpha != 0)
|
||||
argbBlend(alpha, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest);
|
||||
}
|
||||
|
||||
// kRgbToArgbBlender
|
||||
inline void blendRgbToArgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Original blender function: _rgb2argb_blenders
|
||||
if (alpha == 0 || alpha == 0xff) {
|
||||
aDest = 0xff;
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
} else
|
||||
argbBlend(alpha, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest);
|
||||
}
|
||||
|
||||
// kArgbToRgbBlender
|
||||
inline void blendArgbToRgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Original blender function: _argb2rgb_blender
|
||||
if (alpha == 0)
|
||||
alpha = aSrc;
|
||||
else
|
||||
alpha = aSrc * ((alpha & 0xff) + 1) / 256;
|
||||
rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, alpha);
|
||||
// Original doesn't set alpha (so it is 0), but the function is not meant to be used
|
||||
// on bitmap with transparency. Should we set alpha to 0xff?
|
||||
aDest = 0;
|
||||
}
|
||||
|
||||
// kOpaqueBlenderMode
|
||||
inline void blendOpaque(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Original blender function: _opaque_alpha_blender
|
||||
aDest = 0xff;
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
}
|
||||
|
||||
// kSourceAlphaBlender
|
||||
inline void blendSourceAlpha(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Used after set_alpha_blender
|
||||
// Uses alpha from source. Result is fully opaque
|
||||
rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, aSrc);
|
||||
// Original doesn't set alpha (so it is 0), but the function is not meant to be used
|
||||
// on bitmap with transparency. Should we set alpha to 0xff?
|
||||
aDest = 0;
|
||||
}
|
||||
|
||||
// kAdditiveBlenderMode
|
||||
inline void blendAdditiveAlpha(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
|
||||
// Original blender function: _additive_alpha_copysrc_blender
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
uint32 a = (uint32)aSrc + (uint32)aDest;
|
||||
if (a > 0xff)
|
||||
aDest = 0xff;
|
||||
else
|
||||
aDest = static_cast<uint8>(a);
|
||||
}
|
||||
|
||||
// kTintBlenderMode and kTintLightBlenderMode
|
||||
void blendTintSprite(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha, bool light) const;
|
||||
|
||||
friend class DrawInnerImpl_AVX2;
|
||||
friend class DrawInnerImpl_SSE2;
|
||||
friend class DrawInnerImpl_NEON;
|
||||
|
||||
constexpr static int SCALE_THRESHOLD_BITS = 8;
|
||||
constexpr static int SCALE_THRESHOLD = 1 << SCALE_THRESHOLD_BITS;
|
||||
struct DrawInnerArgs {
|
||||
const bool useTint, horizFlip, vertFlip, skipTrans;
|
||||
bool sameFormat, shouldDraw;
|
||||
int xStart, yStart, srcAlpha, tintRed, tintGreen, tintBlue, scaleX, scaleY;
|
||||
uint32 transColor, alphaMask;
|
||||
PALETTE palette;
|
||||
|
||||
BlenderMode blenderMode;
|
||||
Common::Rect dstRect, srcArea;
|
||||
|
||||
BITMAP &dstBitmap;
|
||||
const ::Graphics::ManagedSurface &src;
|
||||
::Graphics::Surface destArea;
|
||||
|
||||
DrawInnerArgs(BITMAP *dstBitmap, const BITMAP *srcBitmap,
|
||||
const Common::Rect &srcRect, const Common::Rect &dstRect,
|
||||
bool skipTrans, int srcAlpha, bool horizFlip,
|
||||
bool vertFlip, int tintRed, int tintGreen, int tintBlue,
|
||||
bool doScale);
|
||||
};
|
||||
|
||||
template<bool Scale>
|
||||
void drawGeneric(DrawInnerArgs &args);
|
||||
#ifdef SCUMMVM_NEON
|
||||
template<bool Scale>
|
||||
void drawNEON(DrawInnerArgs &args);
|
||||
#endif
|
||||
#ifdef SCUMMVM_SSE2
|
||||
template<bool Scale>
|
||||
void drawSSE2(DrawInnerArgs &args);
|
||||
#endif
|
||||
#ifdef SCUMMVM_AVX2
|
||||
template<bool Scale>
|
||||
void drawAVX2(DrawInnerArgs &args);
|
||||
#endif
|
||||
template<int DestBytesPerPixel, int SrcBytesPerPixel, bool Scale>
|
||||
void drawInnerGeneric(DrawInnerArgs &args);
|
||||
|
||||
inline uint32 getColor(const byte *data, byte bpp) const {
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
return *data;
|
||||
case 2:
|
||||
return *(const uint16 *)data;
|
||||
case 4:
|
||||
return *(const uint32 *)data;
|
||||
default:
|
||||
error("Unsupported format in BITMAP::getColor");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Derived surface class
|
||||
*/
|
||||
class Surface : public Graphics::ManagedSurface, public BITMAP {
|
||||
public:
|
||||
Surface(int width, int height, const Graphics::PixelFormat &pixelFormat) :
|
||||
Graphics::ManagedSurface(width, height, pixelFormat), BITMAP(this) {
|
||||
// Allegro uses 255, 0, 255 RGB as the transparent color
|
||||
if (pixelFormat.bytesPerPixel == 2 || pixelFormat.bytesPerPixel == 4)
|
||||
setTransparentColor(pixelFormat.RGBToColor(255, 0, 255));
|
||||
}
|
||||
Surface(Graphics::ManagedSurface &surf, const Common::Rect &bounds) :
|
||||
Graphics::ManagedSurface(surf, bounds), BITMAP(this) {
|
||||
// Allegro uses 255, 0, 255 RGB as the transparent color
|
||||
if (surf.format.bytesPerPixel == 2 || surf.format.bytesPerPixel == 4)
|
||||
setTransparentColor(surf.format.RGBToColor(255, 0, 255));
|
||||
}
|
||||
~Surface() override {
|
||||
}
|
||||
};
|
||||
|
||||
BITMAP *create_bitmap(int width, int height);
|
||||
BITMAP *create_bitmap_ex(int color_depth, int width, int height);
|
||||
BITMAP *create_sub_bitmap(BITMAP *parent, int x, int y, int width, int height);
|
||||
BITMAP *create_video_bitmap(int width, int height);
|
||||
BITMAP *create_system_bitmap(int width, int height);
|
||||
void destroy_bitmap(BITMAP *bitmap);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
1019
engines/ags/lib/allegro/surface_avx2.cpp
Normal file
1019
engines/ags/lib/allegro/surface_avx2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
212
engines/ags/lib/allegro/surface_generic.cpp
Normal file
212
engines/ags/lib/allegro/surface_generic.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/lib/allegro/surface.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
template<int DestBytesPerPixel, int SrcBytesPerPixel, bool Scale>
|
||||
void BITMAP::drawInnerGeneric(DrawInnerArgs &args) {
|
||||
const int xDir = args.horizFlip ? -1 : 1;
|
||||
byte rSrc, gSrc, bSrc, aSrc;
|
||||
byte rDest = 0, gDest = 0, bDest = 0, aDest = 0;
|
||||
|
||||
// Instead of skipping pixels outside our boundary here, we just clip
|
||||
// our area instead.
|
||||
int xCtrStart = 0, xCtrBppStart = 0, xCtrWidth = args.dstRect.width();
|
||||
if (args.xStart + xCtrWidth > args.destArea.w) { // Clip the right
|
||||
xCtrWidth = args.destArea.w - args.xStart;
|
||||
}
|
||||
if (args.xStart < 0) { // Clip the left
|
||||
xCtrStart = -args.xStart;
|
||||
xCtrBppStart = xCtrStart * SrcBytesPerPixel;
|
||||
args.xStart = 0;
|
||||
}
|
||||
int destY = args.yStart, yCtr = 0, srcYCtr = 0, scaleYCtr = 0, yCtrHeight = args.dstRect.height();
|
||||
if (args.yStart < 0) { // Clip the top
|
||||
yCtr = -args.yStart;
|
||||
destY = 0;
|
||||
if (Scale) {
|
||||
scaleYCtr = yCtr * args.scaleY;
|
||||
srcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
if (args.yStart + yCtrHeight > args.destArea.h) { // Clip the bottom
|
||||
yCtrHeight = args.destArea.h - args.yStart;
|
||||
}
|
||||
|
||||
byte *destP = (byte *)args.destArea.getBasePtr(0, destY);
|
||||
const byte *srcP = (const byte *)args.src.getBasePtr(
|
||||
args.horizFlip ? args.srcArea.right - 1 : args.srcArea.left,
|
||||
args.vertFlip ? args.srcArea.bottom - 1 - yCtr :
|
||||
args.srcArea.top + yCtr);
|
||||
for (; yCtr < yCtrHeight; ++destY, ++yCtr, scaleYCtr += args.scaleY) {
|
||||
if (Scale) {
|
||||
int newSrcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
if (srcYCtr != newSrcYCtr) {
|
||||
int diffSrcYCtr = newSrcYCtr - srcYCtr;
|
||||
srcP += args.src.pitch * diffSrcYCtr;
|
||||
srcYCtr = newSrcYCtr;
|
||||
}
|
||||
}
|
||||
// Loop through the pixels of the row
|
||||
for (int destX = args.xStart, xCtr = xCtrStart, xCtrBpp = xCtrBppStart, scaleXCtr = xCtr * args.scaleX; xCtr < xCtrWidth; ++destX, ++xCtr, xCtrBpp += SrcBytesPerPixel, scaleXCtr += args.scaleX) {
|
||||
const byte *srcVal = srcP + xDir * xCtrBpp;
|
||||
if (Scale) {
|
||||
srcVal = srcP + (scaleXCtr / BITMAP::SCALE_THRESHOLD) * SrcBytesPerPixel;
|
||||
}
|
||||
uint32 srcCol = getColor(srcVal, SrcBytesPerPixel);
|
||||
|
||||
// Check if this is a transparent color we should skip
|
||||
if (args.skipTrans && ((srcCol & args.alphaMask) == args.transColor))
|
||||
continue;
|
||||
|
||||
byte *destVal = (byte *)&destP[destX * DestBytesPerPixel];
|
||||
|
||||
// When blitting to the same format we can just copy the color
|
||||
if (DestBytesPerPixel == 1) {
|
||||
*destVal = srcCol;
|
||||
continue;
|
||||
} else if ((DestBytesPerPixel == SrcBytesPerPixel) && args.srcAlpha == -1) {
|
||||
if (DestBytesPerPixel == 4)
|
||||
*(uint32 *)destVal = srcCol;
|
||||
else
|
||||
*(uint16 *)destVal = srcCol;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need the rgb values to do blending and/or convert between formats
|
||||
if (SrcBytesPerPixel == 1) {
|
||||
const RGB &rgb = args.palette[srcCol];
|
||||
aSrc = 0xff;
|
||||
rSrc = rgb.r;
|
||||
gSrc = rgb.g;
|
||||
bSrc = rgb.b;
|
||||
} else {
|
||||
if (SrcBytesPerPixel == 4) {
|
||||
aSrc = srcCol >> 24;
|
||||
rSrc = (srcCol >> 16) & 0xff;
|
||||
gSrc = (srcCol >> 8) & 0xff;
|
||||
bSrc = srcCol & 0xff;
|
||||
} else { // SrcBytesPerPixel == 2
|
||||
aSrc = 0xff;
|
||||
rSrc = (srcCol >> 11) & 0x1f;
|
||||
rSrc = (rSrc << 3) | (rSrc >> 2);
|
||||
gSrc = (srcCol >> 5) & 0x3f;
|
||||
gSrc = (gSrc << 2) | (gSrc >> 4);
|
||||
bSrc = srcCol & 0x1f;
|
||||
bSrc = (bSrc << 3) | (bSrc >> 2);
|
||||
}
|
||||
//src.format.colorToARGB(srcCol, aSrc, rSrc, gSrc, bSrc);
|
||||
}
|
||||
|
||||
if (args.srcAlpha == -1) {
|
||||
// This means we don't use blending.
|
||||
aDest = aSrc;
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
} else {
|
||||
if (args.useTint) {
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
aDest = aSrc;
|
||||
rSrc = args.tintRed;
|
||||
gSrc = args.tintGreen;
|
||||
bSrc = args.tintBlue;
|
||||
aSrc = args.srcAlpha;
|
||||
} else {
|
||||
uint32 destCol = getColor(destVal, DestBytesPerPixel);
|
||||
if (DestBytesPerPixel == 1) {
|
||||
const RGB &rgb = args.palette[destCol];
|
||||
aDest = 0xff;
|
||||
rDest = rgb.r;
|
||||
gDest = rgb.g;
|
||||
bDest = rgb.b;
|
||||
} else {
|
||||
if (DestBytesPerPixel == 4) {
|
||||
aDest = destCol >> 24;
|
||||
rDest = (destCol >> 16) & 0xff;
|
||||
gDest = (destCol >> 8) & 0xff;
|
||||
bDest = destCol & 0xff;
|
||||
} else { // DestBytesPerPixel == 2
|
||||
aDest = 0xff;
|
||||
rDest = (destCol >> 11) & 0x1f;
|
||||
rDest = (rDest << 3) | (rDest >> 2);
|
||||
gDest = (destCol >> 5) & 0x3f;
|
||||
gDest = (gDest << 2) | (gDest >> 4);
|
||||
bDest = destCol & 0x1f;
|
||||
bDest = (bDest << 3) | (bDest >> 2);
|
||||
}
|
||||
//src.format.colorToARGB(srcCol, aSrc, rSrc, gSrc, bSrc);
|
||||
}
|
||||
}
|
||||
blendPixel(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, args.srcAlpha, args.useTint, destVal);
|
||||
}
|
||||
|
||||
uint32 pixel;// = format.ARGBToColor(aDest, rDest, gDest, bDest);
|
||||
if (DestBytesPerPixel == 4) {
|
||||
pixel = (aDest << 24) | (rDest << 16) | (gDest << 8) | (bDest);
|
||||
*(uint32 *)destVal = pixel;
|
||||
}
|
||||
else {
|
||||
pixel = ((rDest >> 3) << 11) | ((gDest >> 2) << 5) | (bDest >> 3);
|
||||
*(uint16 *)destVal = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
destP += args.destArea.pitch;
|
||||
if (!Scale) srcP += args.vertFlip ? -args.src.pitch : args.src.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool Scale>
|
||||
void BITMAP::drawGeneric(DrawInnerArgs &args) {
|
||||
if (args.sameFormat) {
|
||||
switch (format.bytesPerPixel) {
|
||||
case 1: drawInnerGeneric<1, 1, Scale>(args); break;
|
||||
case 2: drawInnerGeneric<2, 2, Scale>(args); break;
|
||||
case 4: drawInnerGeneric<4, 4, Scale>(args); break;
|
||||
}
|
||||
} else if (format.bytesPerPixel == 4 && args.src.format.bytesPerPixel == 2) {
|
||||
drawInnerGeneric<4, 2, Scale>(args);
|
||||
} else if (format.bytesPerPixel == 2 && args.src.format.bytesPerPixel == 4) {
|
||||
drawInnerGeneric<2, 4, Scale>(args);
|
||||
}
|
||||
}
|
||||
|
||||
template void BITMAP::drawGeneric<false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawGeneric<true>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<4, 4, false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<4, 4, true>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<4, 2, false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<4, 2, true>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<2, 4, false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<2, 4, true>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<4, 1, false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<4, 1, true>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<2, 1, false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawInnerGeneric<2, 1, true>(DrawInnerArgs &);
|
||||
|
||||
} // end of namespace AGS3
|
||||
989
engines/ags/lib/allegro/surface_neon.cpp
Normal file
989
engines/ags/lib/allegro/surface_neon.cpp
Normal file
@@ -0,0 +1,989 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/ags.h"
|
||||
|
||||
// Without this ifdef the iOS backend breaks, please do not remove
|
||||
#ifdef SCUMMVM_NEON
|
||||
|
||||
#include "ags/globals.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/lib/allegro/flood.h"
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/screen.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
#if !defined(__aarch64__) && !defined(__ARM_NEON)
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute push (__attribute__((target("neon"))), apply_to=function)
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC push_options
|
||||
#pragma GCC target("fpu=neon")
|
||||
#endif
|
||||
|
||||
#endif // !defined(__aarch64__) && !defined(__ARM_NEON)
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
class DrawInnerImpl_NEON {
|
||||
|
||||
static inline uint32x4_t simd2BppTo4Bpp(uint16x4_t pixels) {
|
||||
uint32x4_t x = vmovl_u16(pixels);
|
||||
|
||||
// c is the extracted 5/6 bit color from the image
|
||||
uint32x4_t c = vshrq_n_u32(x, 11);
|
||||
|
||||
// We convert it back to normal by shifting it thrice over, naturally, and then using the 2 most
|
||||
// sinificant bits in the original color for the least significant bits in the new one
|
||||
uint32x4_t r = vshlq_n_u32(vorrq_u32(vshlq_n_u32(c, 3), vshrq_n_u32(c, 2)), 16);
|
||||
c = vshrq_n_u32(vandq_u32(x, vmovq_n_u32(0x07e0)), 5);
|
||||
uint32x4_t g = vshlq_n_u32(vorrq_u32(vshlq_n_u32(c, 2), vshrq_n_u32(c, 4)), 8);
|
||||
c = vandq_u32(x, vmovq_n_u32(0x001f));
|
||||
uint32x4_t b = vorrq_u32(vshlq_n_u32(c, 3), vshrq_n_u32(c, 2));
|
||||
|
||||
// By default 2bpp to 4bpp makes the alpha channel 255
|
||||
return vorrq_u32(vorrq_u32(vorrq_u32(r, g), b), vmovq_n_u32(0xff000000));
|
||||
}
|
||||
|
||||
static inline uint16x4_t simd4BppTo2Bpp(uint32x4_t pixels) {
|
||||
// x is the final 16 bit rgb pixel
|
||||
uint32x4_t x = vshrq_n_u32(vandq_u32(pixels, vmovq_n_u32(0x000000ff)), 3);
|
||||
x = vorrq_u32(x, vshlq_n_u32(vshrq_n_u32(vandq_u32(pixels, vmovq_n_u32(0x0000ff00)), 8+2), 5));
|
||||
x = vorrq_u32(x, vshlq_n_u32(vshrq_n_u32(vandq_u32(pixels, vmovq_n_u32(0x00ff0000)), 16+3), 11));
|
||||
return vmovn_u32(x);
|
||||
}
|
||||
|
||||
static inline uint16x8_t rgbBlendSIMD2Bpp(uint16x8_t srcCols, uint16x8_t destCols, uint16x8_t alphas) {
|
||||
// Here we add 1 to alphas if its 0. This is what the original blender function did
|
||||
alphas = vaddq_u16(alphas, vandq_u16(vceqq_u16(alphas, vmovq_n_u16(0)), vmovq_n_u16(1)));
|
||||
|
||||
// Split the components into rgb
|
||||
uint16x8_t srcComps[] = {
|
||||
vandq_u16(srcCols, vmovq_n_u16(0x1f)), // B
|
||||
vandq_u16(vshrq_n_u16(srcCols, 5), vmovq_n_u16(0x3f)), // G
|
||||
vshrq_n_u16(srcCols, 11), // R
|
||||
}, destComps[] = {
|
||||
vandq_u16(destCols, vmovq_n_u16(0x1f)), // B
|
||||
vandq_u16(vshrq_n_u16(destCols, 5), vmovq_n_u16(0x3f)), // G
|
||||
vshrq_n_u16(destCols, 11), // R
|
||||
};
|
||||
|
||||
// At some point I made it so that it would put them into their 8bit depth format
|
||||
// to keep the function as 1-1 with the original, but it didn't seem to help much
|
||||
//srcComps[0] = vorrq_u16(vshlq_n_u16(srcComps[0], 3), vshrq_n_u16(srcComps[0], 2));
|
||||
//srcComps[1] = vorrq_u16(vshlq_n_u16(srcComps[1], 2), vshrq_n_u16(srcComps[1], 4));
|
||||
//srcComps[2] = vorrq_u16(vshlq_n_u16(srcComps[2], 3), vshrq_n_u16(srcComps[2], 2));
|
||||
//destComps[0] = vorrq_u16(vshlq_n_u16(destComps[0], 3), vshrq_n_u16(destComps[0], 2));
|
||||
//destComps[1] = vorrq_u16(vshlq_n_u16(destComps[1], 2), vshrq_n_u16(destComps[1], 4));
|
||||
//destComps[2] = vorrq_u16(vshlq_n_u16(destComps[2], 3), vshrq_n_u16(destComps[2], 2));
|
||||
|
||||
// Calculate the differences between the colors
|
||||
uint16x8_t diffs[] = {
|
||||
vsubq_u16(srcComps[0], destComps[0]), // B
|
||||
vsubq_u16(srcComps[1], destComps[1]), // G
|
||||
vsubq_u16(srcComps[2], destComps[2]), // R
|
||||
};
|
||||
|
||||
// Multiply by alpha and shift depth bits to the right
|
||||
// pretty much the same as (int)(((float)component / 255.0f) * ((float)alpha / 255.0f) * 255.0f)
|
||||
alphas = vshrq_n_u16(alphas, 2);
|
||||
diffs[1] = vshrq_n_u16(vmulq_u16(diffs[1], alphas), 6);
|
||||
alphas = vshrq_n_u16(alphas, 1);
|
||||
diffs[0] = vshrq_n_u16(vmulq_u16(diffs[0], alphas), 5);
|
||||
diffs[2] = vshrq_n_u16(vmulq_u16(diffs[2], alphas), 5);
|
||||
|
||||
// Originally, I converted it back to normal here from the 8bpp form, but don't need to do that anymore
|
||||
//diffs[0] = vandq_u16(vshrq_n_u16(vaddq_u16(diffs[0], destComps[0]), 3), vmovq_n_u16(0x1f));
|
||||
//diffs[1] = vandq_u16(vshrq_n_u16(vaddq_u16(diffs[1], destComps[1]), 2), vmovq_n_u16(0x3f));
|
||||
//diffs[2] = vandq_u16(vshrq_n_u16(vaddq_u16(diffs[2], destComps[2]), 3), vmovq_n_u16(0x1f));
|
||||
|
||||
// Here we add the difference between the 2 colors times alpha onto the destination
|
||||
diffs[0] = vandq_u16(vaddq_u16(diffs[0], destComps[0]), vmovq_n_u16(0x1f));
|
||||
diffs[1] = vandq_u16(vaddq_u16(diffs[1], destComps[1]), vmovq_n_u16(0x3f));
|
||||
diffs[2] = vandq_u16(vaddq_u16(diffs[2], destComps[2]), vmovq_n_u16(0x1f));
|
||||
|
||||
// We compile all the colors into diffs[0] as a 16 bit rgb pixel
|
||||
diffs[0] = vorrq_u16(diffs[0], vshlq_n_u16(diffs[1], 5));
|
||||
return vorrq_u16(diffs[0], vshlq_n_u16(diffs[2], 11));
|
||||
}
|
||||
|
||||
// preserveAlpha:
|
||||
// false => set destCols's alpha to 0
|
||||
// true => keep destCols's alpha
|
||||
static inline uint32x4_t rgbBlendSIMD(uint32x4_t srcCols, uint32x4_t destCols, uint32x4_t alphas, bool preserveAlpha) {
|
||||
// Here we add 1 to alphas if its 0. This is what the original blender function did
|
||||
alphas = vaddq_u32(alphas, vandq_u32(vcgtq_u32(alphas, vmovq_n_u32(0)), vmovq_n_u32(1)));
|
||||
|
||||
// Get the alpha from the destination
|
||||
uint32x4_t alpha = vandq_u32(destCols, vmovq_n_u32(0xff000000));
|
||||
|
||||
// Get red and blue components
|
||||
uint32x4_t srcColsCopy = srcCols;
|
||||
srcColsCopy = vandq_u32(srcColsCopy, vmovq_n_u32(0xff00ff));
|
||||
uint32x4_t destColsCopy = destCols;
|
||||
destColsCopy = vandq_u32(destColsCopy, vmovq_n_u32(0xff00ff));
|
||||
|
||||
// compute the difference, then multiply by alpha and divide by 255
|
||||
srcColsCopy = vsubq_u32(srcColsCopy, destColsCopy);
|
||||
srcColsCopy = vmulq_u32(srcColsCopy, alphas);
|
||||
srcColsCopy = vshrq_n_u32(srcColsCopy, 8);
|
||||
srcColsCopy = vaddq_u32(srcColsCopy, destCols); // Add the new red/blue to the old ones
|
||||
|
||||
// do the same for the green component
|
||||
srcCols = vandq_u32(srcCols, vmovq_n_u32(0xff00));
|
||||
destCols = vandq_u32(destCols, vmovq_n_u32(0xff00));
|
||||
srcCols = vsubq_u32(srcCols, destCols);
|
||||
srcCols = vmulq_u32(srcCols, alphas);
|
||||
srcCols = vshrq_n_u32(srcCols, 8);
|
||||
srcCols = vaddq_u32(srcCols, destCols); // Add the new green to the old green
|
||||
|
||||
// keep values in 8bit range and glue red/blue and green together
|
||||
srcColsCopy = vandq_u32(srcColsCopy, vmovq_n_u32(0xff00ff));
|
||||
srcCols = vandq_u32(srcCols, vmovq_n_u32(0xff00));
|
||||
srcCols = vorrq_u32(srcCols, srcColsCopy);
|
||||
|
||||
// Remember that alpha is not alphas, but rather the alpha of destCols
|
||||
if (preserveAlpha) {
|
||||
srcCols = vandq_u32(srcCols, vmovq_n_u32(0x00ffffff));
|
||||
srcCols = vorrq_u32(srcCols, alpha);
|
||||
}
|
||||
return srcCols;
|
||||
}
|
||||
|
||||
// uses the alpha from srcCols and destCols
|
||||
static inline uint32x4_t argbBlendSIMD(uint32x4_t srcCols, uint32x4_t destCols) {
|
||||
float32x4_t srcA = vcvtq_f32_u32(vshrq_n_u32(srcCols, 24));
|
||||
srcA = vmulq_n_f32(srcA, 1.0f / 255.0f);
|
||||
float32x4_t srcR = vcvtq_f32_u32(vandq_u32(vshrq_n_u32(srcCols, 16), vmovq_n_u32(0xff)));
|
||||
float32x4_t srcG = vcvtq_f32_u32(vandq_u32(vshrq_n_u32(srcCols, 8), vmovq_n_u32(0xff)));
|
||||
float32x4_t srcB = vcvtq_f32_u32(vandq_u32(srcCols, vmovq_n_u32(0xff)));
|
||||
|
||||
float32x4_t destA = vcvtq_f32_u32(vshrq_n_u32(destCols, 24));
|
||||
destA = vmulq_n_f32(destA, 1.0f / 255.0f);
|
||||
float32x4_t destR = vcvtq_f32_u32(vandq_u32(vshrq_n_u32(destCols, 16), vmovq_n_u32(0xff)));
|
||||
float32x4_t destG = vcvtq_f32_u32(vandq_u32(vshrq_n_u32(destCols, 8), vmovq_n_u32(0xff)));
|
||||
float32x4_t destB = vcvtq_f32_u32(vandq_u32(destCols, vmovq_n_u32(0xff)));
|
||||
|
||||
// the destination alpha gets multiplied by 255 - source alpha
|
||||
destA = vmulq_f32(destA, vsubq_f32(vmovq_n_f32(1.0f), srcA));
|
||||
|
||||
// ((src * sAlpha) + (dest * dAlpha)) / (sAlpha + dAlpha)
|
||||
float32x4_t combA = vaddq_f32(srcA, destA);
|
||||
float32x4_t combArcp = vrecpeq_f32(combA);
|
||||
destR = vmulq_f32(vaddq_f32(vmulq_f32(srcR, srcA), vmulq_f32(destR, destA)), combArcp);
|
||||
destG = vmulq_f32(vaddq_f32(vmulq_f32(srcG, srcA), vmulq_f32(destG, destA)), combArcp);
|
||||
destB = vmulq_f32(vaddq_f32(vmulq_f32(srcB, srcA), vmulq_f32(destB, destA)), combArcp);
|
||||
combA = vmulq_n_f32(combA, 255.0);
|
||||
|
||||
// Now put it back together
|
||||
return vorrq_u32(vshlq_n_u32(vcvtq_u32_f32(combA), 24),
|
||||
vorrq_u32(vshlq_n_u32(vcvtq_u32_f32(destR), 16),
|
||||
vorrq_u32(vshlq_n_u32(vcvtq_u32_f32(destG), 8),
|
||||
vcvtq_u32_f32(destB))));
|
||||
}
|
||||
|
||||
static inline uint32x4_t blendTintSpriteSIMD(uint32x4_t srcCols, uint32x4_t destCols, uint32x4_t alphas, bool light) {
|
||||
// This function is NOT 1 to 1 with the original... It just approximates it
|
||||
// It gets the value of the HSV of the dest color
|
||||
// Then it gets the HSV of the srcCols
|
||||
|
||||
// how the values are transformed
|
||||
// from 1 uint32x4_t srcCols with each lane being ARGB uint32
|
||||
// srcCols[0] = A | R | G | B
|
||||
// srcCols[1] = A | R | G | B
|
||||
// srcCols[2] = A | R | G | B
|
||||
// srcCols[3] = A | R | G | B
|
||||
// ->
|
||||
// to 4 float32x4_t's each being a separate channel with each lane
|
||||
// corresponding to their respective srcCols lane
|
||||
// dda = { A[0], A[1], A[2], A[3] }
|
||||
// ddr = { R[0], R[1], R[2], R[3] }
|
||||
// ddg = { G[0], G[1], G[2], G[3] }
|
||||
// ddb = { B[0], B[1], B[2], B[3] }
|
||||
|
||||
// do the transformation (we don't actually need alpha at all)
|
||||
float32x4_t ddr, ddg, ddb;
|
||||
ddr = vmulq_n_f32(vcvtq_f32_u32(vandq_u32(vshrq_n_u32(destCols, 16), vmovq_n_u32(0xff))), 1.0 / 255.0);
|
||||
ddg = vmulq_n_f32(vcvtq_f32_u32(vandq_u32(vshrq_n_u32(destCols, 8), vmovq_n_u32(0xff))), 1.0 / 255.0);
|
||||
ddb = vmulq_n_f32(vcvtq_f32_u32(vandq_u32(destCols, vmovq_n_u32(0xff))), 1.0 / 255.0);
|
||||
float32x4_t ssr, ssg, ssb;
|
||||
ssr = vmulq_n_f32(vcvtq_f32_u32(vandq_u32(vshrq_n_u32(srcCols, 16), vmovq_n_u32(0xff))), 1.0 / 255.0);
|
||||
ssg = vmulq_n_f32(vcvtq_f32_u32(vandq_u32(vshrq_n_u32(srcCols, 8), vmovq_n_u32(0xff))), 1.0 / 255.0);
|
||||
ssb = vmulq_n_f32(vcvtq_f32_u32(vandq_u32(srcCols, vmovq_n_u32(0xff))), 1.0 / 255.0);
|
||||
|
||||
// Get the maxes and mins (needed for HSV->RGB and vice-versa)
|
||||
float32x4_t dmaxes = vmaxq_f32(ddr, vmaxq_f32(ddg, ddb));
|
||||
float32x4_t smaxes = vmaxq_f32(ssr, vmaxq_f32(ssg, ssb));
|
||||
float32x4_t smins = vminq_f32(ssr, vminq_f32(ssg, ssb));
|
||||
|
||||
// This is here to stop from dividing by 0
|
||||
const float32x4_t eplison0 = vmovq_n_f32(0.0000001);
|
||||
|
||||
float32x4_t chroma = vmaxq_f32(vsubq_f32(smaxes, smins), eplison0);
|
||||
|
||||
// RGB to HSV is a piecewise function, so we compute each part of the function first...
|
||||
float32x4_t hr, hg, hb, hue, chromaReq;
|
||||
chromaReq = vrecpeq_f32(chroma);
|
||||
hr = vmulq_f32(vsubq_f32(ssg, ssb), chromaReq);
|
||||
float32x4_t hrDiv6 = vmulq_n_f32(hr, 1.0 / 6.0);
|
||||
hrDiv6 = vsubq_f32(hrDiv6, vcvtq_f32_u32(vandq_u32(vcltq_f32(hrDiv6, vmovq_n_f32(0.0)), vmovq_n_u32(1))));
|
||||
hr = vsubq_f32(hr, vmulq_n_f32(vcvtq_f32_s32(vcvtq_s32_f32(hrDiv6)), 6.0));
|
||||
hg = vaddq_f32(vmulq_f32(vsubq_f32(ssb, ssr), chromaReq), vmovq_n_f32(2.0));
|
||||
hb = vaddq_f32(vmulq_f32(vsubq_f32(ssr, ssg), chromaReq), vmovq_n_f32(4.0));
|
||||
|
||||
// And then compute which one will be used based on criteria
|
||||
float32x4_t hrfactors = vcvtq_f32_u32(vandq_u32(vandq_u32(vceqq_f32(ssr, smaxes), vmvnq_u32(vceqq_f32(ssr, ssb))), vmovq_n_u32(1)));
|
||||
float32x4_t hgfactors = vcvtq_f32_u32(vandq_u32(vandq_u32(vceqq_f32(ssg, smaxes), vmvnq_u32(vceqq_f32(ssg, ssr))), vmovq_n_u32(1)));
|
||||
float32x4_t hbfactors = vcvtq_f32_u32(vandq_u32(vandq_u32(vceqq_f32(ssb, smaxes), vmvnq_u32(vceqq_f32(ssb, ssg))), vmovq_n_u32(1)));
|
||||
hue = vmulq_f32(hr, hrfactors);
|
||||
hue = vaddq_f32(hue, vmulq_f32(hg, hgfactors));
|
||||
hue = vaddq_f32(hue, vmulq_f32(hb, hbfactors));
|
||||
|
||||
// Mess with the light like the original function
|
||||
float32x4_t val = dmaxes;
|
||||
if (light) {
|
||||
val = vsubq_f32(val, vsubq_f32(vmovq_n_f32(1.0), vmulq_n_f32(vcvtq_f32_u32(alphas), 1.0 / 250.0)));
|
||||
val = vmaxq_f32(val, vmovq_n_f32(0.0));
|
||||
}
|
||||
|
||||
// then it stitches the HSV back together
|
||||
// the hue and saturation come from the source (tint) color, and the value comes from
|
||||
// the destination (real source) color
|
||||
chroma = vmulq_f32(val, vmulq_f32(vsubq_f32(smaxes, smins), vrecpeq_f32(vaddq_f32(smaxes, eplison0))));
|
||||
float32x4_t hprime_mod2 = vmulq_n_f32(hue, 1.0 / 2.0);
|
||||
hprime_mod2 = vmulq_n_f32(vsubq_f32(hprime_mod2, vcvtq_f32_s32(vcvtq_s32_f32(hprime_mod2))), 2.0);
|
||||
float32x4_t x = vmulq_f32(chroma, vsubq_f32(vmovq_n_f32(1.0), vabsq_f32(vsubq_f32(hprime_mod2, vmovq_n_f32(1.0)))));
|
||||
uint32x4_t hprime_rounded = vcvtq_u32_f32(hue);
|
||||
uint32x4_t x_int = vcvtq_u32_f32(vmulq_n_f32(x, 255.0));
|
||||
uint32x4_t c_int = vcvtq_u32_f32(vmulq_n_f32(chroma, 255.0));
|
||||
|
||||
// Again HSV->RGB is also a piecewise function
|
||||
uint32x4_t val0 = vorrq_u32(vshlq_n_u32(x_int, 8), vshlq_n_u32(c_int, 16));
|
||||
val0 = vandq_u32(val0, vorrq_u32(vceqq_u32(hprime_rounded, vmovq_n_u32(0)), vceqq_u32(hprime_rounded, vmovq_n_u32(6))));
|
||||
uint32x4_t val1 = vorrq_u32(vshlq_n_u32(c_int, 8), vshlq_n_u32(x_int, 16));
|
||||
val1 = vandq_u32(val1, vceqq_u32(hprime_rounded, vmovq_n_u32(1)));
|
||||
uint32x4_t val2 = vorrq_u32(vshlq_n_u32(c_int, 8), x_int);
|
||||
val2 = vandq_u32(val2, vceqq_u32(hprime_rounded, vmovq_n_u32(2)));
|
||||
uint32x4_t val3 = vorrq_u32(vshlq_n_u32(x_int, 8), c_int);
|
||||
val3 = vandq_u32(val3, vceqq_u32(hprime_rounded, vmovq_n_u32(3)));
|
||||
uint32x4_t val4 = vorrq_u32(vshlq_n_u32(x_int, 16), c_int);
|
||||
val4 = vandq_u32(val4, vceqq_u32(hprime_rounded, vmovq_n_u32(4)));
|
||||
uint32x4_t val5 = vorrq_u32(vshlq_n_u32(c_int, 16), x_int);
|
||||
val5 = vandq_u32(val5, vceqq_u32(hprime_rounded, vmovq_n_u32(5)));
|
||||
|
||||
// or the values together
|
||||
uint32x4_t final = vorrq_u32(val0, vorrq_u32(val1, vorrq_u32(val2, vorrq_u32(val3, vorrq_u32(val4, val5)))));
|
||||
|
||||
// add the minimums back in
|
||||
uint32x4_t val_add = vcvtq_u32_f32(vmulq_n_f32(vsubq_f32(val, chroma), 255.0));
|
||||
val_add = vorrq_u32(val_add, vorrq_u32(vshlq_n_u32(val_add, 8), vorrq_u32(vshlq_n_u32(val_add, 16), vandq_u32(destCols, vmovq_n_u32(0xff000000)))));
|
||||
final = vaddq_u32(final, val_add);
|
||||
return final;
|
||||
}
|
||||
|
||||
static inline uint32x4_t blendPixelSIMD(uint32x4_t srcCols, uint32x4_t destCols, uint32x4_t alphas) {
|
||||
uint32x4_t srcAlphas, difAlphas, mask, ch1, ch2;
|
||||
auto setupArgbAlphas = [&]() {
|
||||
// This acts the same as this in the normal blender functions
|
||||
// if (alpha == 0)
|
||||
// alpha = aSrc;
|
||||
// else
|
||||
// alpha = aSrc * ((alpha & 0xff) + 1) / 256;
|
||||
// where alpha is the alpha byte of the srcCols
|
||||
srcAlphas = vshrq_n_u32(srcCols, 24);
|
||||
difAlphas = vaddq_u32(vandq_u32(alphas, vmovq_n_u32(0xff)), vmovq_n_u32(1));
|
||||
difAlphas = vshrq_n_u32(vmulq_u32(srcAlphas, difAlphas), 8);
|
||||
difAlphas = vshlq_n_u32(difAlphas, 24);
|
||||
srcAlphas = vshlq_n_u32(srcAlphas, 24);
|
||||
mask = vceqq_u32(alphas, vmovq_n_u32(0));
|
||||
srcAlphas = vandq_u32(srcAlphas, mask);
|
||||
difAlphas = vandq_u32(difAlphas, vmvnq_u32(mask));
|
||||
srcCols = vandq_u32(srcCols, vmovq_n_u32(0x00ffffff));
|
||||
srcCols = vorrq_u32(srcCols, vorrq_u32(srcAlphas, difAlphas));
|
||||
};
|
||||
switch (_G(_blender_mode)) {
|
||||
case kSourceAlphaBlender: // see BITMAP member function blendSourceAlpha
|
||||
alphas = vshrq_n_u32(srcCols, 24);
|
||||
return rgbBlendSIMD(srcCols, destCols, alphas, false);
|
||||
case kArgbToArgbBlender: // see BITMAP member function blendArgbToArgb
|
||||
setupArgbAlphas();
|
||||
// only blend if alpha isn't 0, otherwise use destCols
|
||||
mask = vcgtq_u32(vshrq_n_u32(srcCols, 24), vmovq_n_u32(0));
|
||||
ch1 = vandq_u32(argbBlendSIMD(srcCols, destCols), mask);
|
||||
ch2 = vandq_u32(destCols, vmvnq_u32(mask));
|
||||
return vorrq_u32(ch1, ch2);
|
||||
case kArgbToRgbBlender: // see BITMAP member function blendArgbToRgb
|
||||
setupArgbAlphas();
|
||||
return rgbBlendSIMD(srcCols, destCols, vshrq_n_u32(srcCols, 24), false);
|
||||
case kRgbToArgbBlender: // see BITMAP member function blendRgbToArgb
|
||||
// if alpha is NOT 0 or 255
|
||||
ch2 = vandq_u32(srcCols, vmovq_n_u32(0x00ffffff));
|
||||
ch2 = vorrq_u32(ch2, vshlq_n_u32(alphas, 24));
|
||||
ch2 = argbBlendSIMD(ch2, destCols);
|
||||
// if alpha is 0 or 255
|
||||
ch1 = vorrq_u32(srcCols, vmovq_n_u32(0xff000000));
|
||||
// mask and or them together
|
||||
mask = vorrq_u32(vceqq_u32(alphas, vmovq_n_u32(0)), vceqq_u32(alphas, vmovq_n_u32(0xff)));
|
||||
ch1 = vandq_u32(ch1, mask);
|
||||
ch2 = vandq_u32(ch2, vmvnq_u32(mask));
|
||||
return vorrq_u32(ch1, ch2);
|
||||
case kRgbToRgbBlender: // see BITMAP member function blendRgbToRgb
|
||||
return rgbBlendSIMD(srcCols, destCols, alphas, false);
|
||||
case kAlphaPreservedBlenderMode: // see BITMAP member function blendPreserveAlpha
|
||||
return rgbBlendSIMD(srcCols, destCols, alphas, true);
|
||||
case kOpaqueBlenderMode: // see BITMAP member function blendOpaque
|
||||
return vorrq_u32(srcCols, vmovq_n_u32(0xff000000));
|
||||
case kAdditiveBlenderMode: // see BITMAP member function blendAdditiveAlpha
|
||||
srcAlphas = vaddq_u32(vshrq_n_u32(srcCols, 24), vshrq_n_u32(destCols, 24));
|
||||
srcAlphas = vminq_u32(srcAlphas, vmovq_n_u32(0xff));
|
||||
srcCols = vandq_u32(srcCols, vmovq_n_u32(0x00ffffff));
|
||||
return vorrq_u32(srcCols, vshlq_n_u32(srcAlphas, 24));
|
||||
case kTintBlenderMode: // see BITMAP member function blendTintSprite
|
||||
return blendTintSpriteSIMD(srcCols, destCols, alphas, false);
|
||||
case kTintLightBlenderMode: // see BITMAP member function blendTintSprite
|
||||
return blendTintSpriteSIMD(srcCols, destCols, alphas, true);
|
||||
}
|
||||
return srcCols;
|
||||
}
|
||||
|
||||
static inline uint16x8_t blendPixelSIMD2Bpp(uint16x8_t srcCols, uint16x8_t destCols, uint16x8_t alphas) {
|
||||
uint16x8_t mask, ch1, ch2;
|
||||
switch (_G(_blender_mode)) {
|
||||
case kSourceAlphaBlender:
|
||||
case kOpaqueBlenderMode:
|
||||
case kAdditiveBlenderMode:
|
||||
return srcCols;
|
||||
case kArgbToArgbBlender:
|
||||
case kArgbToRgbBlender:
|
||||
ch1 = vandq_u16(vmovq_n_u16(0xff), vceqq_u16(alphas, vmovq_n_u16(0)));
|
||||
ch2 = vandq_u16(alphas, vcgtq_u16(alphas, vmovq_n_u16(0)));
|
||||
alphas = vorrq_u16(ch1, ch2);
|
||||
// fall through
|
||||
case kRgbToRgbBlender:
|
||||
case kAlphaPreservedBlenderMode:
|
||||
return rgbBlendSIMD2Bpp(srcCols, destCols, alphas);
|
||||
case kRgbToArgbBlender:
|
||||
mask = vorrq_u16(vceqq_u16(alphas, vmovq_n_u16(0)), vceqq_u16(alphas, vmovq_n_u16(255)));
|
||||
ch1 = vandq_u16(srcCols, mask);
|
||||
ch2 = vandq_u16(rgbBlendSIMD2Bpp(srcCols, destCols, alphas), vmvnq_u16(mask));
|
||||
return vorrq_u16(ch1, ch2);
|
||||
case kTintBlenderMode:
|
||||
case kTintLightBlenderMode:
|
||||
uint32x4_t srcColsLo = simd2BppTo4Bpp(vget_low_u16(srcCols));
|
||||
uint32x4_t srcColsHi = simd2BppTo4Bpp(vget_high_u16(srcCols));
|
||||
uint32x4_t destColsLo = simd2BppTo4Bpp(vget_low_u16(destCols));
|
||||
uint32x4_t destColsHi = simd2BppTo4Bpp(vget_high_u16(destCols));
|
||||
uint32x4_t alphasLo = vmovl_u16(vget_low_u16(alphas));
|
||||
uint32x4_t alphasHi = vmovl_u16(vget_high_u16(alphas));
|
||||
uint16x4_t lo = simd4BppTo2Bpp(blendTintSpriteSIMD(srcColsLo, destColsLo, alphasLo, _G(_blender_mode) == kTintLightBlenderMode));
|
||||
uint16x4_t hi = simd4BppTo2Bpp(blendTintSpriteSIMD(srcColsHi, destColsHi, alphasHi, _G(_blender_mode) == kTintLightBlenderMode));
|
||||
return vcombine_u16(lo, hi);
|
||||
}
|
||||
return srcCols;
|
||||
}
|
||||
|
||||
template<int DestBytesPerPixel, int SrcBytesPerPixel>
|
||||
static inline void drawPixelSIMD(byte *destPtr, const byte *srcP2, uint32x4_t tint, uint32x4_t alphas, uint32x4_t maskedAlphas, uint32x4_t transColors, int xDir, int xCtrBpp, int srcAlpha, int skipTrans, bool horizFlip, bool useTint, uint32x4_t skipMask) {
|
||||
uint32x4_t srcCols, destCol;
|
||||
|
||||
if (DestBytesPerPixel == 4)
|
||||
destCol = vld1q_u32((uint32 *)destPtr);
|
||||
else
|
||||
destCol = simd2BppTo4Bpp(vld1_u16((uint16 *)destPtr));
|
||||
if (SrcBytesPerPixel == 4)
|
||||
srcCols = vld1q_u32((const uint32 *)(srcP2 + xDir * xCtrBpp));
|
||||
else
|
||||
srcCols = simd2BppTo4Bpp(vld1_u16((const uint16 *)(srcP2 + xDir * xCtrBpp)));
|
||||
// we do this here because we need to check if we should skip the pixel before we blend it
|
||||
uint32x4_t mask1 = skipTrans ? vceqq_u32(vandq_u32(srcCols, maskedAlphas), transColors) : vmovq_n_u32(0);
|
||||
mask1 = vorrq_u32(mask1, skipMask);
|
||||
if (srcAlpha != -1) {
|
||||
// take into account for useTint
|
||||
if (useTint) {
|
||||
srcCols = blendPixelSIMD(tint, srcCols, alphas);
|
||||
} else {
|
||||
srcCols = blendPixelSIMD(srcCols, destCol, alphas);
|
||||
}
|
||||
}
|
||||
uint32x4_t destCols2 = vandq_u32(destCol, mask1);
|
||||
uint32x4_t srcCols2 = vandq_u32(srcCols, vmvnq_u32(mask1));
|
||||
uint32x4_t final = vorrq_u32(destCols2, srcCols2);
|
||||
if (horizFlip) {
|
||||
final = vrev64q_u32(final);
|
||||
final = vcombine_u32(vget_high_u32(final), vget_low_u32(final));
|
||||
}
|
||||
if (DestBytesPerPixel == 4) {
|
||||
vst1q_u32((uint32 *)destPtr, final);
|
||||
} else {
|
||||
vst1_u16((uint16 *)destPtr, simd4BppTo2Bpp(final));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void drawPixelSIMD2Bpp(byte *destPtr, const byte *srcP2, uint16x8_t tint, uint16x8_t alphas, uint16x8_t transColors, int xDir, int xCtrBpp, int srcAlpha, int skipTrans, bool horizFlip, bool useTint, uint16x8_t skipMask) {
|
||||
uint16x8_t destCol = vld1q_u16((uint16 *)destPtr);
|
||||
uint16x8_t srcCols = vld1q_u16((const uint16 *)(srcP2 + xDir * xCtrBpp));
|
||||
uint16x8_t mask1 = skipTrans ? vceqq_u16(srcCols, transColors) : vmovq_n_u16(0);
|
||||
mask1 = vorrq_u16(mask1, skipMask);
|
||||
if (srcAlpha != -1) {
|
||||
// take into account for useTint
|
||||
if (useTint) {
|
||||
srcCols = blendPixelSIMD2Bpp(tint, srcCols, alphas);
|
||||
} else {
|
||||
srcCols = blendPixelSIMD2Bpp(srcCols, destCol, alphas);
|
||||
}
|
||||
}
|
||||
uint16x8_t destCols2 = vandq_u16(destCol, mask1);
|
||||
uint16x8_t srcCols2 = vandq_u16(srcCols, vmvnq_u16(mask1));
|
||||
uint16x8_t final = vorrq_u16(destCols2, srcCols2);
|
||||
if (horizFlip) {
|
||||
final = vrev64q_u16(final);
|
||||
final = vcombine_u16(vget_high_u16(final), vget_low_u16(final));
|
||||
}
|
||||
vst1q_u16((uint16 *)destPtr, final);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// This template handles 2bpp and 4bpp, the other specializations handle 1bpp and format conversion blits
|
||||
template<int DestBytesPerPixel, int SrcBytesPerPixel, bool Scale>
|
||||
static void drawInner4BppWithConv(BITMAP::DrawInnerArgs &args) {
|
||||
const int xDir = args.horizFlip ? -1 : 1;
|
||||
byte rSrc, gSrc, bSrc, aSrc;
|
||||
byte rDest = 0, gDest = 0, bDest = 0, aDest = 0;
|
||||
uint32x4_t tint = vshlq_n_u32(vdupq_n_u32(args.srcAlpha), 24);
|
||||
tint = vorrq_u32(tint, vshlq_n_u32(vdupq_n_u32(args.tintRed), 16));
|
||||
tint = vorrq_u32(tint, vshlq_n_u32(vdupq_n_u32(args.tintGreen), 8));
|
||||
tint = vorrq_u32(tint, vdupq_n_u32(args.tintBlue));
|
||||
uint32x4_t maskedAlphas = vmovq_n_u32(args.alphaMask);
|
||||
uint32x4_t transColors = vmovq_n_u32(args.transColor);
|
||||
uint32x4_t alphas = vmovq_n_u32(args.srcAlpha);
|
||||
|
||||
// This is so that we can calculate what pixels to crop off in a vectorized way
|
||||
const uint32x4_t addIndexesNormal = {0, 1, 2, 3};
|
||||
const uint32x4_t addIndexesFlipped = {3, 2, 1, 0};
|
||||
uint32x4_t addIndexes = args.horizFlip ? addIndexesFlipped : addIndexesNormal;
|
||||
|
||||
// This is so that we can calculate in parallel the pixel indexes for scaled drawing
|
||||
uint32x4_t scaleAdds = {0, (uint32)args.scaleX, (uint32)args.scaleX*2, (uint32)args.scaleX*3};
|
||||
|
||||
// Clip the bounds ahead of time (so we don't waste time checking if we are in bounds when
|
||||
// we are in the inner loop)
|
||||
int xCtrStart = 0, xCtrBppStart = 0, xCtrWidth = args.dstRect.width();
|
||||
if (args.xStart + xCtrWidth > args.destArea.w) {
|
||||
xCtrWidth = args.destArea.w - args.xStart;
|
||||
}
|
||||
if (args.xStart < 0) {
|
||||
xCtrStart = -args.xStart;
|
||||
xCtrBppStart = xCtrStart * SrcBytesPerPixel;
|
||||
args.xStart = 0;
|
||||
}
|
||||
int destY = args.yStart, srcYCtr = 0, yCtr = 0, scaleYCtr = 0, yCtrHeight = args.dstRect.height();
|
||||
if (Scale) yCtrHeight = args.dstRect.height();
|
||||
if (args.yStart < 0) {
|
||||
yCtr = -args.yStart;
|
||||
destY = 0;
|
||||
if (Scale) {
|
||||
scaleYCtr = yCtr * args.scaleY;
|
||||
srcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
if (args.yStart + yCtrHeight > args.destArea.h) {
|
||||
yCtrHeight = args.destArea.h - args.yStart;
|
||||
}
|
||||
/*if (!Scale && xCtrWidth % 4 != 0) {
|
||||
--yCtrHeight;
|
||||
}*/
|
||||
|
||||
const int secondToLast = xCtrWidth - 4;
|
||||
|
||||
byte *destP = (byte *)args.destArea.getBasePtr(0, destY);
|
||||
const byte *srcP = (const byte *)args.src.getBasePtr(
|
||||
args.horizFlip ? args.srcArea.right - 4 : args.srcArea.left,
|
||||
args.vertFlip ? args.srcArea.bottom - 1 - yCtr : args.srcArea.top + yCtr);
|
||||
for (; yCtr < yCtrHeight; ++destY, ++yCtr, scaleYCtr += args.scaleY) {
|
||||
uint32x4_t xCtrWidthSIMD = vdupq_n_u32(xCtrWidth); // This is the width of the row
|
||||
|
||||
if (!Scale) {
|
||||
int xCtr = xCtrStart, xCtrBpp = xCtrBppStart, destX = args.xStart;
|
||||
for (; xCtr < secondToLast; destX += 4, xCtr += 4, xCtrBpp += SrcBytesPerPixel*4) {
|
||||
byte *destPtr = &destP[destX * DestBytesPerPixel];
|
||||
drawPixelSIMD<DestBytesPerPixel, SrcBytesPerPixel>(destPtr, srcP, tint, alphas, maskedAlphas, transColors, xDir, xCtrBpp, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, vmovq_n_u32(0));
|
||||
}
|
||||
|
||||
byte *destPtr = &destP[destX * DestBytesPerPixel];
|
||||
uint32x4_t srcCols = vmovq_n_u32(0);
|
||||
uint32x4_t destCols = vmovq_n_u32(0);
|
||||
memcpy(&srcCols, srcP + xDir * xCtrBpp, (xCtrWidth - xCtr) * SrcBytesPerPixel);
|
||||
memcpy(&destCols, destPtr, (xCtrWidth - xCtr) * DestBytesPerPixel);
|
||||
|
||||
// Skip pixels that are beyond the row
|
||||
// uint32x4_t skipMask = vcgeq_u32(vaddq_u32(vdupq_n_u32(xCtr), addIndexes), xCtrWidthSIMD);
|
||||
drawPixelSIMD<DestBytesPerPixel, SrcBytesPerPixel>((byte *)&destCols, (byte *)&srcCols, tint, alphas, maskedAlphas, transColors, xDir, 0, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, vmovq_n_u32(0));
|
||||
memcpy(destPtr, &destCols, (xCtrWidth - xCtr) * DestBytesPerPixel);
|
||||
|
||||
// Goto next row in source and destination image
|
||||
destP += args.destArea.pitch;
|
||||
srcP += args.vertFlip ? -args.src.pitch : args.src.pitch;
|
||||
} else {
|
||||
// Here we are scaling the image
|
||||
int newSrcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
// Since the source yctr might not update every row of the destination, we have
|
||||
// to see if we are on a new row...
|
||||
if (srcYCtr != newSrcYCtr) {
|
||||
int diffSrcYCtr = newSrcYCtr - srcYCtr; // Have we moved yet
|
||||
srcP += args.src.pitch * diffSrcYCtr;
|
||||
srcYCtr = newSrcYCtr;
|
||||
}
|
||||
|
||||
// Now also since we might skip a pixel or 2 or duplicate one to reach the desired
|
||||
// scaling size, we create a small dummy buffer that we copy the pixels into and then
|
||||
// call the drawPixelsSIMD function
|
||||
byte srcBuffer[4*4];
|
||||
for (int xCtr = xCtrStart, xCtrBpp = xCtrBppStart, destX = args.xStart, scaleXCtr = xCtrStart * args.scaleX; xCtr < xCtrWidth; destX += 4, xCtr += 4, xCtrBpp += SrcBytesPerPixel*4) {
|
||||
if (yCtr + 1 == yCtrHeight && xCtr + 4 > xCtrWidth) break; // Don't go past the last 4 pixels
|
||||
uint32x4_t indexes = vdupq_n_u32(scaleXCtr);
|
||||
// Calculate in parallel the indexes of the pixels
|
||||
indexes = vmulq_n_u32(vshrq_n_u32(vaddq_u32(indexes, scaleAdds), BITMAP::SCALE_THRESHOLD_BITS), SrcBytesPerPixel);
|
||||
// Simply memcpy them in. memcpy has no real performance overhead here
|
||||
memcpy(&srcBuffer[0*(uintptr_t)SrcBytesPerPixel], srcP + vgetq_lane_u32(indexes, 0), SrcBytesPerPixel);
|
||||
memcpy(&srcBuffer[1*(uintptr_t)SrcBytesPerPixel], srcP + vgetq_lane_u32(indexes, 1), SrcBytesPerPixel);
|
||||
memcpy(&srcBuffer[2*(uintptr_t)SrcBytesPerPixel], srcP + vgetq_lane_u32(indexes, 2), SrcBytesPerPixel);
|
||||
memcpy(&srcBuffer[3*(uintptr_t)SrcBytesPerPixel], srcP + vgetq_lane_u32(indexes, 3), SrcBytesPerPixel);
|
||||
scaleXCtr += args.scaleX*4;
|
||||
|
||||
// Now this is pretty much the same as before with non-scaled code, except that we use
|
||||
// our dummy source buffer instead of the actual source bitmap
|
||||
byte *destPtr = &destP[destX * (uintptr_t)DestBytesPerPixel];
|
||||
uint32x4_t skipMask = vcgeq_u32(vaddq_u32(vdupq_n_u32(xCtr), addIndexes), xCtrWidthSIMD);
|
||||
drawPixelSIMD<DestBytesPerPixel, SrcBytesPerPixel>(destPtr, (const byte *)srcBuffer, tint, alphas, maskedAlphas, transColors, 1, 0, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, skipMask);
|
||||
}
|
||||
// We calculate every row here except the last (because then we need to
|
||||
// check for if we fall off the edge of the row)
|
||||
// The only exception here is scaling drawing this is because:
|
||||
// 1) if statements are costly, and the less we do the faster this loop is
|
||||
// 2) with this, the only branch in the normal drawing loop is the width check
|
||||
// 3) the scaling code will actually draw until the last 4 pixels of the image
|
||||
// and do the extra if checks because the scaling code is already much slower
|
||||
// than the normal drawing loop, and the less duplicate code helps here.
|
||||
if (yCtr + 1 != yCtrHeight) destP += args.destArea.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the last x values of the last row
|
||||
int xCtr = xCtrStart, xCtrBpp = xCtrBppStart, destX = args.xStart;
|
||||
// We have a picture that is a multiple of 4, so no extra pixels to draw
|
||||
/*if (xCtrWidth % 4 == 0)*/ return;
|
||||
// Drawing the last few not scaled pixels here.
|
||||
// Same as the loop above but now we check if we are going to overflow,
|
||||
// and thus we don't need to mask out pixels that go over the row.
|
||||
if (!Scale) {
|
||||
for (; xCtr + 4 < xCtrWidth; destX += 4, xCtr += 4, xCtrBpp += SrcBytesPerPixel*4) {
|
||||
byte *destPtr = &destP[(ptrdiff_t)destX * DestBytesPerPixel];
|
||||
drawPixelSIMD<DestBytesPerPixel, SrcBytesPerPixel>(destPtr, srcP, tint, alphas, maskedAlphas, transColors, xDir, xCtrBpp, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, vmovq_n_u32(0));
|
||||
}
|
||||
// Because we move in 4 pixel units, and horizFlip moves in 1, we have to move
|
||||
// 1 pixel past the last pixel we did not blit, meaning going forward 3 pixels.
|
||||
if (args.horizFlip) srcP += SrcBytesPerPixel * 3;
|
||||
} else {
|
||||
// So if we are scaling, set up the xCtr to what it was before (AKA the last 4 or so pixels of the image)
|
||||
xCtr = xCtrWidth - xCtrWidth % 4;
|
||||
xCtrBpp = xCtr * SrcBytesPerPixel;
|
||||
destX = args.xStart+xCtr;
|
||||
}
|
||||
|
||||
// For the last 4 pixels, we just do them in serial, nothing special
|
||||
for (; xCtr < xCtrWidth; ++destX, ++xCtr, xCtrBpp += SrcBytesPerPixel) {
|
||||
const byte *srcColPtr = (const byte *)(srcP + xDir * xCtrBpp);
|
||||
if (Scale) {
|
||||
srcColPtr = (const byte *)(srcP + (xCtr * args.scaleX) / BITMAP::SCALE_THRESHOLD * SrcBytesPerPixel);
|
||||
}
|
||||
byte *destVal = (byte *)&destP[destX * DestBytesPerPixel];
|
||||
uint32 srcCol = args.dstBitmap.getColor(srcColPtr, SrcBytesPerPixel);
|
||||
|
||||
// Check if this is a transparent color we should skip
|
||||
if (args.skipTrans && ((srcCol & args.alphaMask) == args.transColor))
|
||||
continue;
|
||||
|
||||
args.src.format.colorToARGB(srcCol, aSrc, rSrc, gSrc, bSrc);
|
||||
if (args.srcAlpha != -1) {
|
||||
if (args.useTint) {
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
aDest = aSrc;
|
||||
rSrc = args.tintRed;
|
||||
gSrc = args.tintGreen;
|
||||
bSrc = args.tintBlue;
|
||||
aSrc = args.srcAlpha;
|
||||
}
|
||||
args.dstBitmap.blendPixel(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, args.srcAlpha, args.useTint, destVal);
|
||||
srcCol = args.dstBitmap.format.ARGBToColor(aDest, rDest, gDest, bDest);
|
||||
} else {
|
||||
srcCol = args.dstBitmap.format.ARGBToColor(aSrc, rSrc, gSrc, bSrc);
|
||||
}
|
||||
if (DestBytesPerPixel == 4)
|
||||
*(uint32 *)destVal = srcCol;
|
||||
else
|
||||
*(uint16 *)destVal = srcCol;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool Scale>
|
||||
static void drawInner2Bpp(BITMAP::DrawInnerArgs &args) {
|
||||
const int xDir = args.horizFlip ? -1 : 1;
|
||||
byte rSrc, gSrc, bSrc, aSrc;
|
||||
byte rDest = 0, gDest = 0, bDest = 0, aDest = 0;
|
||||
uint16x8_t tint = vdupq_n_u16(args.src.format.ARGBToColor(args.srcAlpha, args.tintRed, args.tintGreen, args.tintBlue));
|
||||
uint16x8_t transColors = vdupq_n_u16(args.transColor);
|
||||
uint16x8_t alphas = vdupq_n_u16(args.srcAlpha);
|
||||
|
||||
// This is so that we can calculate what pixels to crop off in a vectorized way
|
||||
uint16x8_t addIndexesNormal = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
uint16x8_t addIndexesFlipped = {7, 6, 5, 4, 3, 2, 1, 0};
|
||||
uint16x8_t addIndexes = args.horizFlip ? addIndexesFlipped : addIndexesNormal;
|
||||
|
||||
// This is so that we can calculate in parallel the pixel indices for scaled drawing
|
||||
uint32x4_t scaleAdds = {0, (uint32)args.scaleX, (uint32)args.scaleX*2, (uint32)args.scaleX*3};
|
||||
uint32x4_t scaleAdds2 = {(uint32)args.scaleX*4, (uint32)args.scaleX*5, (uint32)args.scaleX*6, (uint32)args.scaleX*7};
|
||||
|
||||
// Clip the bounds ahead of time (so we don't waste time checking if we are in bounds when
|
||||
// we are in the inner loop)
|
||||
int xCtrStart = 0, xCtrBppStart = 0, xCtrWidth = args.dstRect.width();
|
||||
if (args.xStart + xCtrWidth > args.destArea.w) {
|
||||
xCtrWidth = args.destArea.w - args.xStart;
|
||||
}
|
||||
if (args.xStart < 0) {
|
||||
xCtrStart = -args.xStart;
|
||||
xCtrBppStart = xCtrStart * 2;
|
||||
args.xStart = 0;
|
||||
}
|
||||
int destY = args.yStart, yCtr = 0, srcYCtr = 0, scaleYCtr = 0, yCtrHeight = args.dstRect.height();
|
||||
if (Scale) yCtrHeight = args.dstRect.height();
|
||||
if (args.yStart < 0) {
|
||||
yCtr = -args.yStart;
|
||||
destY = 0;
|
||||
if (Scale) {
|
||||
scaleYCtr = yCtr * args.scaleY;
|
||||
srcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
if (args.yStart + yCtrHeight > args.destArea.h) {
|
||||
yCtrHeight = args.destArea.h - args.yStart;
|
||||
}
|
||||
/*if (!Scale && xCtrWidth % 8 != 0) {
|
||||
--yCtrHeight;
|
||||
}*/
|
||||
|
||||
const int secondToLast = xCtrWidth - 8;
|
||||
|
||||
byte *destP = (byte *)args.destArea.getBasePtr(0, destY);
|
||||
const byte *srcP = (const byte *)args.src.getBasePtr(
|
||||
args.horizFlip ? args.srcArea.right - 8 : args.srcArea.left,
|
||||
args.vertFlip ? args.srcArea.bottom - 1 - yCtr : args.srcArea.top + yCtr);
|
||||
for (; yCtr < yCtrHeight; ++destY, ++yCtr, scaleYCtr += args.scaleY) {
|
||||
uint16x8_t xCtrWidthSIMD = vmovq_n_u16(xCtrWidth); // This is the width of the row
|
||||
if (!Scale) {
|
||||
// If we are not scaling the image
|
||||
int xCtr = xCtrStart, xCtrBpp = xCtrBppStart, destX = args.xStart;
|
||||
for (; xCtr < secondToLast; destX += 8, xCtr += 8, xCtrBpp += 16) {
|
||||
byte *destPtr = &destP[destX * 2];
|
||||
drawPixelSIMD2Bpp(destPtr, srcP, tint, alphas, transColors, xDir, xCtrBpp, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, vmovq_n_u16(0));
|
||||
}
|
||||
|
||||
byte *destPtr = &destP[destX * 2];
|
||||
uint16x8_t srcCols = vmovq_n_u16(0);
|
||||
uint16x8_t destCols = vmovq_n_u16(0);
|
||||
const int copySize = (xCtrWidth - xCtr) * 2;
|
||||
memcpy(&srcCols, srcP + xDir * xCtrBpp, copySize);
|
||||
memcpy(&destCols, destPtr, copySize);
|
||||
|
||||
// Skip pixels that are beyond the row
|
||||
// uint16x8_t skipMask = vcgeq_u16(vaddq_u16(vdupq_n_u16(xCtr), addIndexes), xCtrWidthSIMD);
|
||||
drawPixelSIMD2Bpp((byte *)&destCols, (byte *)&srcCols, tint, alphas, transColors, xDir, 0, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, vmovq_n_u16(0));
|
||||
memcpy(destPtr, &destCols, copySize);
|
||||
|
||||
// Goto next row in source and destination image
|
||||
destP += args.destArea.pitch;
|
||||
srcP += args.vertFlip ? -args.src.pitch : args.src.pitch;
|
||||
} else {
|
||||
// Here we are scaling the image
|
||||
int newSrcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
// Since the source yctr might not update every row of the destination, we have
|
||||
// to see if we are on a new row...
|
||||
if (srcYCtr != newSrcYCtr) {
|
||||
int diffSrcYCtr = newSrcYCtr - srcYCtr;
|
||||
srcP += args.src.pitch * diffSrcYCtr;
|
||||
srcYCtr = newSrcYCtr;
|
||||
}
|
||||
|
||||
// Now also since we might skip a pixel or 2 or duplicate one to reach the desired
|
||||
// scaling size, we create a small dummy buffer that we copy the pixels into and then
|
||||
// call the drawPixelsSIMD function
|
||||
uint16 srcBuffer[8];
|
||||
for (int xCtr = xCtrStart, xCtrBpp = xCtrBppStart, destX = args.xStart, scaleXCtr = xCtrStart * args.scaleX; xCtr < xCtrWidth; destX += 8, xCtr += 8, xCtrBpp += 16) {
|
||||
if (yCtr + 1 == yCtrHeight && xCtr + 8 > xCtrWidth) break;
|
||||
uint32x4_t indexes = vdupq_n_u32(scaleXCtr), indexes2 = vdupq_n_u32(scaleXCtr);
|
||||
// Calculate in parallel the indices of the pixels
|
||||
indexes = vmulq_n_u32(vshrq_n_u32(vaddq_u32(indexes, scaleAdds), BITMAP::SCALE_THRESHOLD_BITS), 2);
|
||||
indexes2 = vmulq_n_u32(vshrq_n_u32(vaddq_u32(indexes2, scaleAdds2), BITMAP::SCALE_THRESHOLD_BITS), 2);
|
||||
// Simply memcpy them in. memcpy has no real performance overhead here
|
||||
srcBuffer[0] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes, 0));
|
||||
srcBuffer[1] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes, 1));
|
||||
srcBuffer[2] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes, 2));
|
||||
srcBuffer[3] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes, 3));
|
||||
srcBuffer[4] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes2, 0));
|
||||
srcBuffer[5] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes2, 1));
|
||||
srcBuffer[6] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes2, 2));
|
||||
srcBuffer[7] = *(const uint16 *)(srcP + vgetq_lane_u32(indexes2, 3));
|
||||
scaleXCtr += args.scaleX*8;
|
||||
|
||||
// Now this is pretty much the same as before with non-scaled code, except that we use
|
||||
// our dummy source buffer instead of the actual source bitmap
|
||||
byte *destPtr = &destP[destX * 2];
|
||||
uint16x8_t skipMask = vcgeq_u16(vaddq_u16(vdupq_n_u16(xCtr), addIndexes), xCtrWidthSIMD);
|
||||
drawPixelSIMD2Bpp(destPtr, (const byte *)srcBuffer, tint, alphas, transColors, 1, 0, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, skipMask);
|
||||
}
|
||||
// We calculate every row here except the last (because then we need to
|
||||
// check for if we fall off the edge of the row)
|
||||
// The only exception here is scaling drawing this is because:
|
||||
// 1) if statements are costly, and the less we do the faster this loop is
|
||||
// 2) with this, the only branch in the normal drawing loop is the width check
|
||||
// 3) the scaling code will actually draw until the last 4 pixels of the image
|
||||
// and do the extra if checks because the scaling code is already much slower
|
||||
// than the normal drawing loop, and the less duplicate code helps here.
|
||||
if (yCtr + 1 != yCtrHeight) destP += args.destArea.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// We have a picture that is a multiple of 8, so no extra pixels to draw
|
||||
/*if (xCtrWidth % 8 == 0)*/ return;
|
||||
// Get the last x values of the last row
|
||||
int xCtr = xCtrStart, xCtrBpp = xCtrBppStart, destX = args.xStart;
|
||||
// Drawing the last few not scaled pixels here.
|
||||
// Same as the loop above but now we check if we are going to overflow,
|
||||
// and thus we don't need to mask out pixels that go over the row.
|
||||
if (!Scale) {
|
||||
for (; xCtr + 8 < xCtrWidth; destX += 8, xCtr += 8, xCtrBpp += 16) {
|
||||
byte *destPtr = &destP[destX * 2];
|
||||
drawPixelSIMD2Bpp(destPtr, srcP, tint, alphas, transColors, xDir, xCtrBpp, args.srcAlpha, args.skipTrans, args.horizFlip, args.useTint, vmovq_n_u16(0));
|
||||
}
|
||||
// Because we move in 8 pixel units, and horizFlip moves in 1, we have to move
|
||||
// 1 pixel past the last pixel we did not blit, meaning going forward 7 pixels.
|
||||
if (args.horizFlip) srcP += 2 * 7;
|
||||
} else {
|
||||
// So if we are scaling, set up the xCtr to what it was before (AKA the last 8 or so pixels of the image)
|
||||
xCtr = xCtrWidth - xCtrWidth % 8;
|
||||
xCtrBpp = xCtr * 2;
|
||||
destX = args.xStart+xCtr;
|
||||
}
|
||||
|
||||
// For the last 4 pixels, we just do them in serial, nothing special
|
||||
for (; xCtr < xCtrWidth; ++destX, ++xCtr, xCtrBpp += 2) {
|
||||
const byte *srcColPtr = (const byte *)(srcP + xDir * xCtrBpp);
|
||||
if (Scale) {
|
||||
srcColPtr = (const byte *)(srcP + (xCtr * args.scaleX) / BITMAP::SCALE_THRESHOLD * 2);
|
||||
}
|
||||
byte *destVal = (byte *)&destP[destX * 2];
|
||||
uint32 srcCol = (uint32)(*(const uint16 *)srcColPtr);
|
||||
|
||||
// Check if this is a transparent color we should skip
|
||||
if (args.skipTrans && srcCol == args.transColor)
|
||||
continue;
|
||||
|
||||
args.src.format.colorToARGB(srcCol, aSrc, rSrc, gSrc, bSrc);
|
||||
if (args.srcAlpha != -1) {
|
||||
if (args.useTint) {
|
||||
rDest = rSrc;
|
||||
gDest = gSrc;
|
||||
bDest = bSrc;
|
||||
aDest = aSrc;
|
||||
rSrc = args.tintRed;
|
||||
gSrc = args.tintGreen;
|
||||
bSrc = args.tintBlue;
|
||||
aSrc = args.srcAlpha;
|
||||
}/* else {
|
||||
format.colorToARGB((uint32)(*(uint16 *)destVal), aDest, rDest, gDest, bDest);
|
||||
}*/
|
||||
args.dstBitmap.blendPixel(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, args.srcAlpha, args.useTint, destVal);
|
||||
srcCol = args.dstBitmap.format.ARGBToColor(aDest, rDest, gDest, bDest);
|
||||
} else {
|
||||
srcCol = args.dstBitmap.format.ARGBToColor(aSrc, rSrc, gSrc, bSrc);
|
||||
}
|
||||
*(uint16 *)destVal = srcCol;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool Scale>
|
||||
static void drawInner1Bpp(BITMAP::DrawInnerArgs &args) {
|
||||
const int xDir = args.horizFlip ? -1 : 1;
|
||||
uint8x16_t transColors = vmovq_n_u8(args.transColor);
|
||||
|
||||
// This is so that we can calculate in parallel the pixel indices for scaled drawing
|
||||
uint32x4_t scaleAdds1 = {0, (uint32)args.scaleX, (uint32)args.scaleX*2, (uint32)args.scaleX*3};
|
||||
uint32x4_t scaleAdds2 = {(uint32)args.scaleX*4, (uint32)args.scaleX*5, (uint32)args.scaleX*6, (uint32)args.scaleX*7};
|
||||
uint32x4_t scaleAdds3 = {(uint32)args.scaleX*8, (uint32)args.scaleX*9, (uint32)args.scaleX*10, (uint32)args.scaleX*11};
|
||||
uint32x4_t scaleAdds4 = {(uint32)args.scaleX*12, (uint32)args.scaleX*13, (uint32)args.scaleX*14, (uint32)args.scaleX*15};
|
||||
|
||||
// Clip the bounds ahead of time (so we don't waste time checking if we are in bounds when
|
||||
// we are in the inner loop)
|
||||
int xCtrStart = 0, xCtrWidth = args.dstRect.width();
|
||||
if (args.xStart + xCtrWidth > args.destArea.w) {
|
||||
xCtrWidth = args.destArea.w - args.xStart;
|
||||
}
|
||||
if (args.xStart < 0) {
|
||||
xCtrStart = -args.xStart;
|
||||
args.xStart = 0;
|
||||
}
|
||||
int destY = args.yStart, yCtr = 0, srcYCtr = 0, scaleYCtr = 0, yCtrHeight = args.dstRect.height();
|
||||
if (Scale) yCtrHeight = args.dstRect.height();
|
||||
if (args.yStart < 0) {
|
||||
yCtr = -args.yStart;
|
||||
destY = 0;
|
||||
if (Scale) {
|
||||
scaleYCtr = yCtr * args.scaleY;
|
||||
srcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
if (args.yStart + yCtrHeight > args.destArea.h) {
|
||||
yCtrHeight = args.destArea.h - args.yStart;
|
||||
}
|
||||
|
||||
byte *destP = (byte *)args.destArea.getBasePtr(0, destY);
|
||||
const byte *srcP = (const byte *)args.src.getBasePtr(
|
||||
args.horizFlip ? args.srcArea.right - 16 : args.srcArea.left,
|
||||
args.vertFlip ? args.srcArea.bottom - 1 - yCtr : args.srcArea.top + yCtr);
|
||||
for (; yCtr < yCtrHeight; ++destY, ++yCtr, scaleYCtr += args.scaleY) {
|
||||
if (Scale) {
|
||||
// So here we update the srcYCtr differently due to this being for
|
||||
// scaling
|
||||
int newSrcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD;
|
||||
if (srcYCtr != newSrcYCtr) {
|
||||
// Since the source yctr might not update every row of the destination, we have
|
||||
// to see if we are on a new row...
|
||||
int diffSrcYCtr = newSrcYCtr - srcYCtr;
|
||||
srcP += args.src.pitch * diffSrcYCtr;
|
||||
srcYCtr = newSrcYCtr;
|
||||
}
|
||||
}
|
||||
int xCtr = xCtrStart, destX = args.xStart, scaleXCtr = xCtrStart * args.scaleX;
|
||||
for (; xCtr + 16 < xCtrWidth; destX += 16, xCtr += 16) {
|
||||
byte *destPtr = &destP[destX];
|
||||
|
||||
// Here we don't use the drawPixelSIMD function because 1bpp bitmaps in allegro
|
||||
// can't have any blending applied to them
|
||||
uint8x16_t destCols = vld1q_u8(destPtr);
|
||||
uint8x16_t srcCols = vld1q_u8(srcP + xDir * xCtr);
|
||||
if (Scale) {
|
||||
// If we are scaling, we have to set each pixel individually
|
||||
uint32x4_t indexes1 = vdupq_n_u32(scaleXCtr), indexes2 = vdupq_n_u32(scaleXCtr);
|
||||
uint32x4_t indexes3 = vdupq_n_u32(scaleXCtr), indexes4 = vdupq_n_u32(scaleXCtr);
|
||||
indexes1 = vshrq_n_u32(vaddq_u32(indexes1, scaleAdds1), BITMAP::SCALE_THRESHOLD_BITS);
|
||||
indexes2 = vshrq_n_u32(vaddq_u32(indexes2, scaleAdds2), BITMAP::SCALE_THRESHOLD_BITS);
|
||||
indexes3 = vshrq_n_u32(vaddq_u32(indexes3, scaleAdds3), BITMAP::SCALE_THRESHOLD_BITS);
|
||||
indexes4 = vshrq_n_u32(vaddq_u32(indexes4, scaleAdds4), BITMAP::SCALE_THRESHOLD_BITS);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes1, 0)], srcCols, 0);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes1, 1)], srcCols, 1);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes1, 2)], srcCols, 2);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes1, 3)], srcCols, 3);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes2, 0)], srcCols, 4);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes2, 1)], srcCols, 5);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes2, 2)], srcCols, 6);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes2, 3)], srcCols, 7);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes3, 0)], srcCols, 8);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes3, 1)], srcCols, 9);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes3, 2)], srcCols, 10);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes3, 3)], srcCols, 11);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes4, 0)], srcCols, 12);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes4, 1)], srcCols, 13);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes4, 2)], srcCols, 14);
|
||||
srcCols = vsetq_lane_u8(srcP[vgetq_lane_u32(indexes4, 3)], srcCols, 15);
|
||||
scaleXCtr += args.scaleX*16;
|
||||
}
|
||||
|
||||
// Mask out transparent pixels
|
||||
uint8x16_t mask1 = args.skipTrans ? vceqq_u8(srcCols, transColors) : vmovq_n_u8(0);
|
||||
uint8x16_t final = vorrq_u8(vandq_u8(srcCols, vmvnq_u8(mask1)), vandq_u8(destCols, mask1));
|
||||
if (args.horizFlip) {
|
||||
final = vrev64q_u8(final);
|
||||
final = vcombine_u8(vget_high_u8(final), vget_low_u8(final));
|
||||
}
|
||||
vst1q_u8(destPtr, final);
|
||||
}
|
||||
// Get the last x values
|
||||
|
||||
// Because we move in 16 pixel units, and horizFlip moves in 1, we have to move
|
||||
// 1 pixel past the last pixel we did not blit, meaning going forward 15 pixels.
|
||||
if (args.horizFlip) srcP += 15;
|
||||
for (; xCtr < xCtrWidth; ++destX, ++xCtr, scaleXCtr += args.scaleX) {
|
||||
const byte *srcCol = (const byte *)(srcP + xDir * xCtr);
|
||||
if (Scale) {
|
||||
srcCol = (const byte *)(srcP + scaleXCtr / BITMAP::SCALE_THRESHOLD);
|
||||
}
|
||||
// Check if this is a transparent color we should skip
|
||||
if (args.skipTrans && *srcCol == args.transColor)
|
||||
continue;
|
||||
|
||||
byte *destVal = (byte *)&destP[destX];
|
||||
*destVal = *srcCol;
|
||||
}
|
||||
if (args.horizFlip) srcP -= 15; // Undo what we did up there
|
||||
destP += args.destArea.pitch; // Go to next row
|
||||
// Only advance the src row by 1 every time like this if we don't scale
|
||||
if (!Scale) srcP += args.vertFlip ? -args.src.pitch : args.src.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
}; // end of class DrawInnerImpl_NEON
|
||||
|
||||
template<bool Scale>
|
||||
void BITMAP::drawNEON(DrawInnerArgs &args) {
|
||||
if (args.sameFormat) {
|
||||
switch (format.bytesPerPixel) {
|
||||
case 1: DrawInnerImpl_NEON::drawInner1Bpp<Scale>(args); break;
|
||||
case 2: DrawInnerImpl_NEON::drawInner2Bpp<Scale>(args); break;
|
||||
case 4: DrawInnerImpl_NEON::drawInner4BppWithConv<4, 4, Scale>(args); break;
|
||||
}
|
||||
} else if (format.bytesPerPixel == 4 && args.src.format.bytesPerPixel == 2) {
|
||||
DrawInnerImpl_NEON::drawInner4BppWithConv<4, 2, Scale>(args);
|
||||
} else if (format.bytesPerPixel == 2 && args.src.format.bytesPerPixel == 4) {
|
||||
DrawInnerImpl_NEON::drawInner4BppWithConv<2, 4, Scale>(args);
|
||||
}
|
||||
}
|
||||
|
||||
template void BITMAP::drawNEON<false>(DrawInnerArgs &);
|
||||
template void BITMAP::drawNEON<true>(DrawInnerArgs &);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#if !defined(__aarch64__) && !defined(__ARM_NEON)
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang attribute pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC pop_options
|
||||
#endif
|
||||
|
||||
#endif // !defined(__aarch64__) && !defined(__ARM_NEON)
|
||||
|
||||
#endif // SCUMMVM_NEON
|
||||
1014
engines/ags/lib/allegro/surface_sse2.cpp
Normal file
1014
engines/ags/lib/allegro/surface_sse2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
74
engines/ags/lib/allegro/system.cpp
Normal file
74
engines/ags/lib/allegro/system.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro/system.h"
|
||||
#include "ags/lib/allegro/aintern.h"
|
||||
#include "ags/globals.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
GFX_MODE_LIST *get_gfx_mode_list(int card) {
|
||||
GFX_MODE_LIST *list = new GFX_MODE_LIST();
|
||||
list->num_modes = 1;
|
||||
list->mode = new GFX_MODE[1];
|
||||
|
||||
GFX_MODE &gm = list->mode[0];
|
||||
gm.width = 320;
|
||||
gm.height = 200;
|
||||
gm.bpp = 32;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void destroy_gfx_mode_list(GFX_MODE_LIST *list) {
|
||||
delete[] list->mode;
|
||||
delete list;
|
||||
}
|
||||
|
||||
void set_color_depth(int depth) {
|
||||
_G(_color_depth) = depth;
|
||||
}
|
||||
|
||||
int get_color_depth() {
|
||||
return _G(_color_depth);
|
||||
}
|
||||
|
||||
int get_desktop_resolution(int32_t *width, int32_t *height) {
|
||||
// TODO: ScummVM has a hardcoded dummy desktop resolution. See if there's any
|
||||
// need to change the values, given we're hardcoded for pretend full-screen
|
||||
if (width)
|
||||
*width = 640;
|
||||
if (height)
|
||||
*height = 480;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void request_refresh_rate(int rate) {
|
||||
// No implementation
|
||||
}
|
||||
|
||||
void set_close_button_callback(void(*proc)()) {
|
||||
// No implementation
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
151
engines/ags/lib/allegro/system.h
Normal file
151
engines/ags/lib/allegro/system.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_SYSTEM_H
|
||||
#define AGS_LIB_ALLEGRO_SYSTEM_H
|
||||
|
||||
#include "ags/lib/allegro/base.h"
|
||||
#include "ags/lib/allegro/color.h"
|
||||
#include "ags/lib/allegro/gfx.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#ifndef AL_METHOD
|
||||
#define AL_METHOD(type, name, args) type (*name) args
|
||||
#endif
|
||||
|
||||
#define SYSTEM_AUTODETECT 0
|
||||
#define SYSTEM_SCUMMVM AL_ID('S','C','V','M')
|
||||
#define SYSTEM_NONE AL_ID('N','O','N','E')
|
||||
|
||||
#define GFX_SCUMMVM AL_ID('S', 'C', 'V', 'M')
|
||||
|
||||
#define SWITCH_NONE 0
|
||||
#define SWITCH_PAUSE 1
|
||||
#define SWITCH_AMNESIA 2
|
||||
#define SWITCH_BACKGROUND 3
|
||||
#define SWITCH_BACKAMNESIA 4
|
||||
|
||||
#define SWITCH_IN 0
|
||||
#define SWITCH_OUT 1
|
||||
|
||||
struct GFX_MODE {
|
||||
int width, height, bpp;
|
||||
};
|
||||
|
||||
struct GFX_MODE_LIST {
|
||||
int num_modes; /* number of gfx modes */
|
||||
GFX_MODE *mode; /* pointer to the actual mode list array */
|
||||
};
|
||||
|
||||
struct SYSTEM_DRIVER {
|
||||
int id;
|
||||
const char *name;
|
||||
const char *desc;
|
||||
const char *ascii_name;
|
||||
AL_METHOD(int, init, (void));
|
||||
AL_METHOD(void, exit, (void));
|
||||
AL_METHOD(void, get_executable_name, (char *output, int size));
|
||||
AL_METHOD(int, find_resource, (char *dest, const char *resource, int size));
|
||||
AL_METHOD(void, set_window_title, (const char *name));
|
||||
AL_METHOD(int, set_close_button_callback, (AL_METHOD(void, proc, (void))));
|
||||
AL_METHOD(void, message, (const char *msg));
|
||||
AL_METHOD(void, assert, (const char *msg));
|
||||
AL_METHOD(void, save_console_state, (void));
|
||||
AL_METHOD(void, restore_console_state, (void));
|
||||
AL_METHOD(BITMAP *, create_bitmap, (int color_depth, int width, int height));
|
||||
AL_METHOD(void, created_bitmap, (BITMAP *bmp));
|
||||
AL_METHOD(BITMAP *, create_sub_bitmap, (BITMAP *parent, int x, int y, int width, int height));
|
||||
AL_METHOD(void, created_sub_bitmap, (BITMAP *bmp, BITMAP *parent));
|
||||
AL_METHOD(int, destroy_bitmap, (BITMAP *bitmap));
|
||||
AL_METHOD(void, read_hardware_palette, (void));
|
||||
AL_METHOD(void, set_palette_range, (const RGB *p, int from, int to, int retracesync));
|
||||
AL_METHOD(struct GFX_VTABLE *, get_vtable, (int color_depth));
|
||||
AL_METHOD(int, set_display_switch_mode, (int mode));
|
||||
AL_METHOD(void, display_switch_lock, (int lock, int foreground));
|
||||
AL_METHOD(int, desktop_color_depth, (void));
|
||||
AL_METHOD(int, get_desktop_resolution, (int *width, int *height));
|
||||
AL_METHOD(void, get_gfx_safe_mode, (int *driver, struct GFX_MODE *mode));
|
||||
AL_METHOD(void, yield_timeslice, (void));
|
||||
AL_METHOD(void *, create_mutex, (void));
|
||||
AL_METHOD(void, destroy_mutex, (void *handle));
|
||||
AL_METHOD(void, lock_mutex, (void *handle));
|
||||
AL_METHOD(void, unlock_mutex, (void *handle));
|
||||
};
|
||||
|
||||
/* creates and manages the screen bitmap */
|
||||
struct GFX_DRIVER {
|
||||
int id;
|
||||
AL_CONST char *name;
|
||||
AL_CONST char *desc;
|
||||
AL_CONST char *ascii_name;
|
||||
AL_METHOD(BITMAP *, init, (int w, int h, int v_w, int v_h, int color_depth));
|
||||
AL_METHOD(void, exit, (BITMAP *b));
|
||||
AL_METHOD(int, scroll, (int x, int y));
|
||||
AL_METHOD(void, vsync, (void));
|
||||
AL_METHOD(void, set_palette, (AL_CONST RGB *p, int from, int to, int retracesync));
|
||||
AL_METHOD(int, request_scroll, (int x, int y));
|
||||
AL_METHOD(int, poll_scroll, (void));
|
||||
AL_METHOD(void, enable_triple_buffer, (void));
|
||||
AL_METHOD(BITMAP *, create_video_bitmap, (int width, int height));
|
||||
AL_METHOD(void, destroy_video_bitmap, (BITMAP *bitmap));
|
||||
AL_METHOD(int, show_video_bitmap, (BITMAP *bitmap));
|
||||
AL_METHOD(int, request_video_bitmap, (BITMAP *bitmap));
|
||||
AL_METHOD(BITMAP *, create_system_bitmap, (int width, int height));
|
||||
AL_METHOD(void, destroy_system_bitmap, (BITMAP *bitmap));
|
||||
AL_METHOD(int, set_mouse_sprite, (BITMAP *sprite, int xfocus, int yfocus));
|
||||
AL_METHOD(int, show_mouse, (BITMAP *bmp, int x, int y));
|
||||
AL_METHOD(void, hide_mouse, (void));
|
||||
AL_METHOD(void, move_mouse, (int x, int y));
|
||||
AL_METHOD(void, save_video_state, (void));
|
||||
AL_METHOD(void, restore_video_state, (void));
|
||||
AL_METHOD(void, set_blender_mode, (int mode, int r, int g, int b, int a));
|
||||
AL_METHOD(GFX_MODE_LIST *, fetch_mode_list, (void));
|
||||
int w, h; /* physical (not virtual!) screen size */
|
||||
int linear; /* true if video memory is linear */
|
||||
long bank_size; /* bank size, in bytes */
|
||||
long bank_gran; /* bank granularity, in bytes */
|
||||
long vid_mem; /* video memory size, in bytes */
|
||||
long vid_phys_base; /* physical address of video memory */
|
||||
int windowed; /* true if driver runs windowed */
|
||||
};
|
||||
|
||||
extern void set_color_depth(int depth);
|
||||
extern int get_color_depth();
|
||||
extern int get_desktop_resolution(int32_t *width, int32_t *height);
|
||||
extern void request_refresh_rate(int rate);
|
||||
extern void set_close_button_callback(void(*proc)());
|
||||
|
||||
extern GFX_MODE_LIST *get_gfx_mode_list(int card);
|
||||
extern void destroy_gfx_mode_list(GFX_MODE_LIST *list);
|
||||
|
||||
inline void vsync() {}
|
||||
inline int set_display_switch_callback(int dir, AL_METHOD(void, cb, (void))) {
|
||||
return 0;
|
||||
}
|
||||
inline int set_display_switch_mode(int v) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
1315
engines/ags/lib/allegro/unicode.cpp
Normal file
1315
engines/ags/lib/allegro/unicode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
151
engines/ags/lib/allegro/unicode.h
Normal file
151
engines/ags/lib/allegro/unicode.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_LIB_ALLEGRO_UNICODE_H
|
||||
#define AGS_LIB_ALLEGRO_UNICODE_H
|
||||
|
||||
#include "ags/lib/allegro/base.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define U_ASCII AL_ID('A','S','C','8')
|
||||
#define U_ASCII_CP AL_ID('A','S','C','P')
|
||||
#define U_UNICODE AL_ID('U','N','I','C')
|
||||
#define U_UTF8 AL_ID('U','T','F','8')
|
||||
#define U_CURRENT AL_ID('c','u','r','.')
|
||||
|
||||
|
||||
/* UTF-8 support functions
|
||||
*/
|
||||
extern int utf8_getc(const char *s);
|
||||
extern int utf8_getx(char **s);
|
||||
extern int utf8_setc(char *s, int c);
|
||||
extern int utf8_width(const char *s);
|
||||
extern int utf8_cwidth(int c);
|
||||
extern int utf8_isok(int c);
|
||||
|
||||
/**
|
||||
* ASCII support functions
|
||||
*/
|
||||
extern int ascii_getc(const char *s);
|
||||
extern int ascii_getx(char **s);
|
||||
extern int ascii_setc(char *s, int c);
|
||||
extern int ascii_width(const char *s);
|
||||
extern int ascii_cwidth(int c);
|
||||
extern int ascii_isok(int c);
|
||||
|
||||
/* ugetc: */
|
||||
extern int (*ugetc)(const char *s);
|
||||
/* ugetxc: */
|
||||
extern int (*ugetx)(char **s);
|
||||
/* ugetxc: */
|
||||
extern int (*ugetxc)(const char * const *s);
|
||||
/* usetc: */
|
||||
extern int (*usetc)(char *s, int c);
|
||||
/* uwidth: */
|
||||
extern int (*uwidth)(const char *s);
|
||||
/* ucwidth: */
|
||||
extern int (*ucwidth)(int c);
|
||||
/* uisok: */
|
||||
extern int (*uisok)(int c);
|
||||
|
||||
/* set_uformat:
|
||||
* Selects a new text encoding format.
|
||||
*/
|
||||
extern void set_uformat(int type);
|
||||
|
||||
enum { LC_CTYPE };
|
||||
extern const char *setlocale(int type, const char *language);
|
||||
|
||||
/* get_uformat:
|
||||
* Returns the current text encoding format.
|
||||
*/
|
||||
extern int get_uformat();
|
||||
extern size_t ustrsize(const char *s);
|
||||
/* &nicode string length
|
||||
*/
|
||||
extern int ustrlen(const char *s);
|
||||
/* utolower:
|
||||
* Unicode-aware version of the ANSI tolower() function.
|
||||
*/
|
||||
extern int utolower(int c);
|
||||
/* utoupper:
|
||||
* Unicode-aware version of the ANSI toupper() function.
|
||||
*/
|
||||
extern int utoupper(int c);
|
||||
/* Unicode string compare
|
||||
*/
|
||||
extern int ustrcmp(const char *s1, const char *s2);
|
||||
/* ustricmp:
|
||||
* Unicode-aware version of the DJGPP stricmp() function.
|
||||
*/
|
||||
extern int ustricmp(const char *s1, const char *s2);
|
||||
/* ustrncmp:
|
||||
* Unicode-aware version of the ANSI strncmp() function.
|
||||
*/
|
||||
extern int ustrncmp(const char *s1, const char *s2, int n);
|
||||
/* ustrnicmp:
|
||||
* Unicode-aware version of the DJGPP strnicmp() function.
|
||||
*/
|
||||
extern int ustrnicmp(const char *s1, const char *s2, int n);
|
||||
/* uoffset:
|
||||
* Returns the offset in bytes from the start of the string to the
|
||||
* character at the specified index. If the index is negative, counts
|
||||
* backward from the end of the string (-1 returns an offset to the
|
||||
* last character).
|
||||
*/
|
||||
extern int uoffset(const char *s, int index);
|
||||
|
||||
/* ugetat:
|
||||
* Returns the character from the specified index within the string.
|
||||
*/
|
||||
extern int ugetat(const char *s, int idx);
|
||||
|
||||
/* ustrlwr:
|
||||
* Unicode-aware version of the ANSI strlwr() function.
|
||||
*/
|
||||
extern char *ustrlwr(char *s);
|
||||
/* ustrupr:
|
||||
* Unicode-aware version of the ANSI strupr() function.
|
||||
*/
|
||||
extern char *ustrupr(char *s);
|
||||
/* ustrstr:
|
||||
* Unicode-aware version of the ANSI strstr() function.
|
||||
*/
|
||||
extern const char *ustrstr(const char *s1, const char *s2);
|
||||
/* usetat:
|
||||
* Modifies the character at the specified index within the string,
|
||||
* handling adjustments for variable width data. Returns how far the
|
||||
* rest of the string was moved.
|
||||
*/
|
||||
int usetat(char *s, int index, int c);
|
||||
/* ustrsizez:
|
||||
* Returns the size of the specified string in bytes, including the
|
||||
* trailing zero.
|
||||
*/
|
||||
extern int ustrsizez(const char *s);
|
||||
|
||||
extern int need_uconvert(const char *s, int type, int newtype);
|
||||
extern int uvszprintf(char *buf, int size, const char *format, va_list args);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user