Import blues from 6d8f0b2a

This commit is contained in:
Gregory Montoir 2021-12-19 08:09:02 +08:00
parent 140d278724
commit 3f2965eaac
11 changed files with 182 additions and 146 deletions

View File

@ -106,30 +106,32 @@ static void init_level() {
if (g_vars.play_demo_flag) { if (g_vars.play_demo_flag) {
g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0; g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0;
} }
const int xoffs = (TILEMAP_SCREEN_W / 16) / 2;
int xpos = g_options.start_xpos16; int xpos = g_options.start_xpos16;
if (xpos < 0) { if (xpos < 0) {
xpos = g_vars.level_xpos[OBJECT_NUM_PLAYER1]; xpos = g_vars.level_xpos[OBJECT_NUM_PLAYER1];
if (!g_vars.two_players_flag && (g_vars.objects[OBJECT_NUM_PLAYER1].unk60 || g_vars.objects[OBJECT_NUM_PLAYER2].unk60)) { if (!g_vars.two_players_flag && (g_vars.objects[OBJECT_NUM_PLAYER1].unk60 || g_vars.objects[OBJECT_NUM_PLAYER2].unk60)) {
xpos = restart_xpos[g_vars.level * 2]; xpos = restart_xpos[g_vars.level * 2];
} }
xpos = (xpos >> 4) - 10; xpos = (xpos >> 4) - xoffs;
} else { } else {
g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + 10; g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + xoffs;
} }
if (xpos < 0) { if (xpos < 0) {
xpos = 0; xpos = 0;
} }
g_vars.screen_tilemap_xorigin = xpos << 4; g_vars.screen_tilemap_xorigin = xpos << 4;
const int yoffs = (TILEMAP_SCREEN_H / 16) / 2 + 1;
int ypos = g_options.start_ypos16; int ypos = g_options.start_ypos16;
if (ypos < 0) { if (ypos < 0) {
ypos = g_vars.level_ypos[OBJECT_NUM_PLAYER1]; ypos = g_vars.level_ypos[OBJECT_NUM_PLAYER1];
if (!g_vars.two_players_flag && (g_vars.objects[OBJECT_NUM_PLAYER1].unk60 || g_vars.objects[OBJECT_NUM_PLAYER2].unk60)) { if (!g_vars.two_players_flag && (g_vars.objects[OBJECT_NUM_PLAYER1].unk60 || g_vars.objects[OBJECT_NUM_PLAYER2].unk60)) {
ypos = restart_ypos[g_vars.level * 2]; ypos = restart_ypos[g_vars.level * 2];
} }
ypos = (ypos >> 4) - 6; ypos = (ypos >> 4) - yoffs;
} else { } else {
g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + 6; g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + yoffs;
} }
if (ypos < 0) { if (ypos < 0) {
ypos = 0; ypos = 0;

View File

@ -272,11 +272,17 @@ static void decode_graphics(int spr_type, int start, int end, const uint8_t *dit
max_h = h; max_h = h;
} }
} }
if (g_res.amiga_data && start == 0) {
for (int i = 0; i < MAX_SPRITESHEET_W * MAX_SPRITESHEET_H; ++i) {
if (data[i] != 0) {
data[i] |= 16;
}
}
}
assert(max_w <= MAX_SPRITESHEET_W); assert(max_w <= MAX_SPRITESHEET_W);
assert(current_y + max_h <= MAX_SPRITESHEET_H); assert(current_y + max_h <= MAX_SPRITESHEET_H);
g_sys.render_unload_sprites(spr_type); g_sys.render_unload_sprites(spr_type);
const int palette_offset = (g_res.amiga_data && start == 0) ? 16 : 0; g_sys.render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h, color_key, false);
g_sys.render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h, palette_offset, color_key);
free(data); free(data);
} }
} }
@ -305,7 +311,7 @@ void screen_load_graphics(const uint8_t *dither_lut_sqv, const uint8_t *dither_l
dither_graphics(data, FG_TILE_W * g_res.avt_count, FG_TILE_W * g_res.avt_count, FG_TILE_H, dither_lut_avt, color_key); dither_graphics(data, FG_TILE_W * g_res.avt_count, FG_TILE_W * g_res.avt_count, FG_TILE_H, dither_lut_avt, color_key);
} }
g_sys.render_unload_sprites(RENDER_SPR_FG); g_sys.render_unload_sprites(RENDER_SPR_FG);
g_sys.render_load_sprites(RENDER_SPR_FG, g_res.avt_count, r, data, g_res.avt_count * FG_TILE_W, FG_TILE_H, 0, color_key); g_sys.render_load_sprites(RENDER_SPR_FG, g_res.avt_count, r, data, g_res.avt_count * FG_TILE_W, FG_TILE_H, color_key, false);
free(data); free(data);
} }
// background tiles (Amiga) - re-arrange to match DOS .ck1/.ck2 layout // background tiles (Amiga) - re-arrange to match DOS .ck1/.ck2 layout

View File

@ -4,50 +4,43 @@
struct unpack_t { struct unpack_t {
uint8_t dict_buf[0x200 * 2]; uint8_t dict_buf[0x200 * 2];
uint8_t rd[0x1000];
}; };
static struct unpack_t g_unpack; static struct unpack_t g_unpack;
int unpack(FILE *in, uint8_t *dst) { int unpack(FILE *in, uint8_t *dst) {
fread(g_unpack.rd, 1, 6, in); uint8_t buf[6];
const int uncompressed_size = (READ_LE_UINT16(g_unpack.rd) << 16) + READ_LE_UINT16(g_unpack.rd + 2); fread(buf, 1, 6, in);
const int dict_len = READ_LE_UINT16(g_unpack.rd + 4); const int uncompressed_size = (READ_LE_UINT16(buf) << 16) + READ_LE_UINT16(buf + 2);
const int dict_len = READ_LE_UINT16(buf + 4);
print_debug(DBG_UNPACK, "SQV uncompressed size %d dict_len %d", uncompressed_size, dict_len); print_debug(DBG_UNPACK, "SQV uncompressed size %d dict_len %d", uncompressed_size, dict_len);
fread(g_unpack.dict_buf, 1, dict_len, in); fread(g_unpack.dict_buf, 1, dict_len, in);
const uint8_t *start = dst; const uint8_t *start = dst;
const uint8_t *src = g_unpack.rd; int bits_count = 1;
int len = 1;
int bytes_count = 2;
uint16_t bits = 0; uint16_t bits = 0;
uint16_t val = 0; uint16_t val = 0;
while ((dst - start) < uncompressed_size) { while ((dst - start) < uncompressed_size) {
--len; --bits_count;
if (len == 0) { if (bits_count == 0) {
bytes_count -= 2; if (fread(buf, 1, 2, in) == 0) {
if (bytes_count == 0) { break;
bytes_count = fread(g_unpack.rd, 1, 0x1000, in);
if (bytes_count == 0) {
break;
}
bytes_count += (bytes_count & 1);
src = g_unpack.rd;
} }
bits = READ_BE_UINT16(src); src += 2; bits = READ_BE_UINT16(buf);
len = 17; bits_count = 16;
continue;
} }
const int carry = (bits & 0x8000) != 0; const bool carry = (bits & 0x8000) != 0;
bits <<= 1; bits <<= 1;
if (carry) { if (carry) {
val += 2; val += 2;
} }
assert(val < 0x400); assert((val & 1) == 0);
assert(val < dict_len);
val = READ_LE_UINT16(g_unpack.dict_buf + val); val = READ_LE_UINT16(g_unpack.dict_buf + val);
if ((val & 0x8000) == 0) { if ((val & 0x8000) == 0) {
continue; continue;
} }
assert((val & 0x7F00) == 0);
*dst++ = val & 255; *dst++ = val & 255;
val = 0; val = 0;
} }

View File

@ -231,7 +231,7 @@ void video_load_sprites() {
assert(max_w <= MAX_SPRITESHEET_W); assert(max_w <= MAX_SPRITESHEET_W);
assert(current_y + max_h <= MAX_SPRITESHEET_H); assert(current_y + max_h <= MAX_SPRITESHEET_H);
g_sys.render_unload_sprites(RENDER_SPR_GAME); g_sys.render_unload_sprites(RENDER_SPR_GAME);
g_sys.render_load_sprites(RENDER_SPR_GAME, count, r, data, MAX_SPRITESHEET_W, current_y + max_h, 0, 0x0); g_sys.render_load_sprites(RENDER_SPR_GAME, count, r, data, MAX_SPRITESHEET_W, current_y + max_h, 0x0, false);
free(data); free(data);
} }
} }

View File

@ -138,23 +138,23 @@ static void level_update_boss_gorilla_init_objects(const uint16_t *p) {
++g_vars.boss.parts[3].y_pos; ++g_vars.boss.parts[3].y_pos;
} }
if (g_vars.boss.hdir) { if (g_vars.boss.hdir) {
g_vars.boss.parts[0].spr_num |= 0x8000; for (int i = 0; i < 5; ++i) {
g_vars.boss.parts[1].spr_num |= 0x8000; g_vars.boss.parts[i].spr_num |= 0x8000;
g_vars.boss.parts[2].spr_num |= 0x8000; }
g_vars.boss.parts[3].spr_num |= 0x8000;
g_vars.boss.parts[4].spr_num |= 0x8000;
} }
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
struct object_t *obj = &g_vars.objects_tbl[103 + i]; struct object_t *obj = &g_vars.objects_tbl[103 + i];
const uint16_t addr = *p++; const uint16_t addr = *p++;
if (addr == 0xA609) { switch (addr) {
case 0xA609:
g_vars.boss.obj1 = obj; g_vars.boss.obj1 = obj;
} break;
if (addr == 0xA60F) { case 0xA60F:
g_vars.boss.obj2 = obj; g_vars.boss.obj2 = obj;
} break;
if (addr == 0xA603) { case 0xA603:
g_vars.boss.obj3 = obj; g_vars.boss.obj3 = obj;
break;
} }
assert(addr == 0xA5F7 || addr == 0xA5FD || addr == 0xA603 || addr == 0xA609 || addr == 0xA60F); assert(addr == 0xA5F7 || addr == 0xA5FD || addr == 0xA603 || addr == 0xA609 || addr == 0xA60F);
const int num = (addr - 0xA5F7) / 6; const int num = (addr - 0xA5F7) / 6;
@ -597,7 +597,7 @@ static void level_update_boss_tree() {
g_vars.boss_level5.spr106_pos = 0; g_vars.boss_level5.spr106_pos = 0;
} }
uint8_t ah = 1; uint8_t ah = 1;
if (g_vars.boss_level5.spr106_pos != 0) { if (g_vars.boss_level5.spr106_pos != 1) {
ah = 3; ah = 3;
g_vars.shake_screen_counter = 4; g_vars.shake_screen_counter = 4;
obj_player->x_pos += 2; obj_player->x_pos += 2;

View File

@ -299,7 +299,7 @@ extern const uint8_t monster_anim_tbl[1100];
extern const uint8_t boss_minotaur_seq_data[86]; extern const uint8_t boss_minotaur_seq_data[86];
extern const uint16_t boss_gorilla_data[19 * 10]; extern const uint16_t boss_gorilla_data[19 * 10];
extern const uint16_t boss_gorilla_spr_tbl[46 * 3]; /* uint16_t: spr1_num, uint16_t: spr2_num, int8_t: dx, int8_t: dy */ extern const uint16_t boss_gorilla_spr_tbl[46 * 3]; /* uint16_t: spr1_num, uint16_t: spr2_num, int8_t: dx, int8_t: dy */
extern const uint16_t snow_pattern1_data[11]; extern const uint16_t snow_pattern1_data[1];
extern const uint16_t snow_pattern2_data[10]; extern const uint16_t snow_pattern2_data[10];
/* game.c */ /* game.c */

View File

@ -944,7 +944,7 @@ static void level_update_tile1(uint16_t offset) {
level_update_tile_type_1(offset); level_update_tile_type_1(offset);
break; break;
case 2: case 2:
level_update_tile_type_2(offset); level_update_tile_type_2();
break; break;
default: default:
print_warning("Unhandled level_update_tile1 type %d", type); print_warning("Unhandled level_update_tile1 type %d", type);
@ -2097,7 +2097,7 @@ static void level_update_player_anim_0(uint8_t al) {
const uint8_t *anim = level_update_player_anim1_num(18, 36); const uint8_t *anim = level_update_player_anim1_num(18, 36);
level_update_object_anim(anim); level_update_object_anim(anim);
if ((g_vars.level_draw_counter & 3) == 0) { if ((g_vars.level_draw_counter & 3) == 0) {
level_init_object_hit_from_player_pos(&g_vars.objects_tbl[1]); level_init_object_hit_from_player_pos();
} }
g_vars.objects_tbl[1].data.p.current_anim_num = 0; g_vars.objects_tbl[1].data.p.current_anim_num = 0;
return; return;

View File

@ -61,6 +61,9 @@ static void convert_planar_tile_4bpp(const uint8_t *src, uint8_t *dst, int dst_p
void video_draw_string(int offset, int hspace, const char *s) { void video_draw_string(int offset, int hspace, const char *s) {
offset += hspace; offset += hspace;
const int y = (offset * 8) / 320 + (GAME_SCREEN_H - 200) / 2;
const int x = (offset * 8) % 320 + (GAME_SCREEN_W - 320) / 2;
uint8_t *dst = g_res.vga + y * GAME_SCREEN_W + x;
while (*s) { while (*s) {
uint8_t code = *s++; uint8_t code = *s++;
if (code != 0x20) { if (code != 0x20) {
@ -68,10 +71,10 @@ void video_draw_string(int offset, int hspace, const char *s) {
if (code > 9) { if (code > 9) {
code -= 2; code -= 2;
} }
decode_planar(g_res.allfonts + code * 48, g_res.vga + offset * 8, 320, 8, 12, 0); decode_planar(g_res.allfonts + code * 48, dst, GAME_SCREEN_W, 8, 12, 0);
} }
++offset; dst += 8;
} }
} }
void video_draw_panel_number(int offset, int num) { void video_draw_panel_number(int offset, int num) {
@ -188,7 +191,7 @@ void video_load_front_tiles() {
decode_planar(g_res.frontdat + tile * 16 * 8, g_res.vga + y * w + x, w, 16, 16, 0); decode_planar(g_res.frontdat + tile * 16 * 8, g_res.vga + y * w + x, w, 16, 16, 0);
++tile; ++tile;
if (tile == count) { if (tile == count) {
g_sys.render_load_sprites(RENDER_SPR_FG, count, r, g_res.vga, w, h, 0, 0x0); g_sys.render_load_sprites(RENDER_SPR_FG, count, r, g_res.vga, w, h, 0x0, true);
return; return;
} }
} }
@ -260,7 +263,7 @@ void video_load_sprites() {
assert(max_w <= MAX_SPRITESHEET_W); assert(max_w <= MAX_SPRITESHEET_W);
assert(current_y + max_h <= MAX_SPRITESHEET_H); assert(current_y + max_h <= MAX_SPRITESHEET_H);
g_sys.render_unload_sprites(RENDER_SPR_GAME); g_sys.render_unload_sprites(RENDER_SPR_GAME);
g_sys.render_load_sprites(RENDER_SPR_GAME, count, r, data, MAX_SPRITESHEET_W, current_y + max_h, 0, 0x0); g_sys.render_load_sprites(RENDER_SPR_GAME, count, r, data, MAX_SPRITESHEET_W, current_y + max_h, 0x0, true);
free(data); free(data);
print_debug(DBG_SCREEN, "sprites total_size %d count %d", offset, count); print_debug(DBG_SCREEN, "sprites total_size %d count %d", offset, count);
} }

View File

@ -250,7 +250,7 @@ static int unpack_sqv(FILE *in, struct unpack_sqv_t *u) {
int bytes_count = 2; int bytes_count = 2;
int state = 0; int state = 0;
int count = 0; int count = 0;
uint8_t code, prev; uint8_t code, prev = 0;
uint16_t bits = 0; uint16_t bits = 0;
uint16_t val = 0; uint16_t val = 0;
while ((dst - output_buffer) < uncompressed_size) { while ((dst - output_buffer) < uncompressed_size) {

2
sys.h
View File

@ -55,7 +55,7 @@ struct sys_t {
void (*stop_audio)(); void (*stop_audio)();
void (*lock_audio)(); void (*lock_audio)();
void (*unlock_audio)(); void (*unlock_audio)();
void (*render_load_sprites)(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h, int palette_offset, uint8_t color_key); void (*render_load_sprites)(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h, uint8_t color_key, bool update_pal);
void (*render_unload_sprites)(int spr_type); void (*render_unload_sprites)(int spr_type);
void (*render_add_sprite)(int spr_type, int frame, int x, int y, int xflip); void (*render_add_sprite)(int spr_type, int frame, int x, int y, int xflip);
void (*render_clear_sprites)(); void (*render_clear_sprites)();

View File

@ -5,16 +5,18 @@
#define COPPER_BARS_H 80 #define COPPER_BARS_H 80
#define MAX_SPRITES 256 #define MAX_SPRITES 256
#define MAX_SPRITESHEETS 3
static const int FADE_STEPS = 16; static const int FADE_STEPS = 16;
struct spritesheet_t { struct spritesheet_t {
int count; int count;
SDL_Rect *r; SDL_Rect *r;
SDL_Surface *surface;
SDL_Texture *texture; SDL_Texture *texture;
}; };
static struct spritesheet_t _spritesheets[3]; static struct spritesheet_t _spritesheets[MAX_SPRITESHEETS];
struct sprite_t { struct sprite_t {
int sheet; int sheet;
@ -33,11 +35,12 @@ static SDL_Window *_window;
static SDL_Renderer *_renderer; static SDL_Renderer *_renderer;
static SDL_Texture *_texture; static SDL_Texture *_texture;
static SDL_PixelFormat *_fmt; static SDL_PixelFormat *_fmt;
static SDL_Palette *_palette;
static uint32_t _screen_palette[256]; static uint32_t _screen_palette[256];
static uint32_t *_screen_buffer; static uint32_t *_screen_buffer;
static struct input_t *_input = &g_sys.input; static int _copper_color_key;
static int _copper_color;
static uint32_t _copper_palette[COPPER_BARS_H]; static uint32_t _copper_palette[COPPER_BARS_H];
static SDL_GameController *_controller; static SDL_GameController *_controller;
static SDL_Joystick *_joystick; static SDL_Joystick *_joystick;
@ -45,13 +48,10 @@ static int sdl2_init() {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
_screen_w = _screen_h = 0; _screen_w = _screen_h = 0;
_window = 0;
_renderer = 0;
_texture = 0;
_fmt = 0;
memset(_screen_palette, 0, sizeof(_screen_palette)); memset(_screen_palette, 0, sizeof(_screen_palette));
_palette = SDL_AllocPalette(256);
_screen_buffer = 0; _screen_buffer = 0;
_copper_color = -1; _copper_color_key = -1;
SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
_controller = 0; _controller = 0;
const int count = SDL_NumJoysticks(); const int count = SDL_NumJoysticks();
@ -80,6 +80,10 @@ static void sdl2_fini() {
SDL_FreeFormat(_fmt); SDL_FreeFormat(_fmt);
_fmt = 0; _fmt = 0;
} }
if (_palette) {
SDL_FreePalette(_palette);
_palette = 0;
}
if (_texture) { if (_texture) {
SDL_DestroyTexture(_texture); SDL_DestroyTexture(_texture);
_texture = 0; _texture = 0;
@ -140,22 +144,33 @@ static uint32_t convert_amiga_color(uint16_t color) {
r |= r << 4; r |= r << 4;
uint8_t g = (color >> 4) & 15; uint8_t g = (color >> 4) & 15;
g |= g << 4; g |= g << 4;
uint8_t b = color & 15; uint8_t b = color & 15;
b |= b << 4; b |= b << 4;
return SDL_MapRGB(_fmt, r, g, b); return SDL_MapRGB(_fmt, r, g, b);
} }
static void set_amiga_color(uint16_t color, SDL_Color *p) {
const uint8_t r = (color >> 8) & 15;
p->r = (r << 4) | r;
const uint8_t g = (color >> 4) & 15;
p->g = (g << 4) | g;
const uint8_t b = color & 15;
p->b = (b << 4) | b;
}
static void sdl2_set_palette_amiga(const uint16_t *colors, int offset) { static void sdl2_set_palette_amiga(const uint16_t *colors, int offset) {
SDL_Color *palette_colors = &_palette->colors[offset];
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
_screen_palette[offset + i] = convert_amiga_color(colors[i]); _screen_palette[offset + i] = convert_amiga_color(colors[i]);
set_amiga_color(colors[i], &palette_colors[i]);
} }
} }
static void sdl2_set_copper_bars(const uint16_t *data) { static void sdl2_set_copper_bars(const uint16_t *data) {
if (!data) { if (!data) {
_copper_color = -1; _copper_color_key = -1;
} else { } else {
_copper_color = (data[0] - 0x180) / 2; _copper_color_key = (data[0] - 0x180) / 2;
const uint16_t *src = data + 1; const uint16_t *src = data + 1;
uint32_t *dst = _copper_palette; uint32_t *dst = _copper_palette;
for (int i = 0; i < COPPER_BARS_H / 5; ++i) { for (int i = 0; i < COPPER_BARS_H / 5; ++i) {
@ -170,6 +185,7 @@ static void sdl2_set_copper_bars(const uint16_t *data) {
} }
static void sdl2_set_screen_palette(const uint8_t *colors, int offset, int count, int depth) { static void sdl2_set_screen_palette(const uint8_t *colors, int offset, int count, int depth) {
SDL_Color *palette_colors = &_palette->colors[offset];
const int shift = 8 - depth; const int shift = 8 - depth;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
int r = colors[0]; int r = colors[0];
@ -181,8 +197,18 @@ static void sdl2_set_screen_palette(const uint8_t *colors, int offset, int count
b = (b << shift) | (b >> (depth - shift)); b = (b << shift) | (b >> (depth - shift));
} }
_screen_palette[offset + i] = SDL_MapRGB(_fmt, r, g, b); _screen_palette[offset + i] = SDL_MapRGB(_fmt, r, g, b);
palette_colors[i].r = r;
palette_colors[i].g = g;
palette_colors[i].b = b;
colors += 3; colors += 3;
} }
for (int i = 0; i < ARRAYSIZE(_spritesheets); ++i) {
struct spritesheet_t *sheet = &_spritesheets[i];
if (sheet->surface) {
SDL_DestroyTexture(sheet->texture);
sheet->texture = SDL_CreateTextureFromSurface(_renderer, sheet->surface);
}
}
} }
static void sdl2_set_palette_color(int i, const uint8_t *colors) { static void sdl2_set_palette_color(int i, const uint8_t *colors) {
@ -261,12 +287,12 @@ static void sdl2_transition_screen(enum sys_transition_e type, bool open) {
} }
static void sdl2_update_screen(const uint8_t *p, int present) { static void sdl2_update_screen(const uint8_t *p, int present) {
if (_copper_color != -1) { if (_copper_color_key != -1) {
for (int j = 0; j < _screen_h; ++j) { for (int j = 0; j < _screen_h; ++j) {
if (j / 2 < COPPER_BARS_H) { if (j / 2 < COPPER_BARS_H) {
const uint32_t line_color = _copper_palette[j / 2]; const uint32_t line_color = _copper_palette[j / 2];
for (int i = 0; i < _screen_w; ++i) { for (int i = 0; i < _screen_w; ++i) {
_screen_buffer[j * _screen_w + i] = (p[i] == _copper_color) ? line_color : _screen_palette[p[i]]; _screen_buffer[j * _screen_w + i] = (p[i] == _copper_color_key) ? line_color : _screen_palette[p[i]];
} }
} else { } else {
for (int i = 0; i < _screen_w; ++i) { for (int i = 0; i < _screen_w; ++i) {
@ -310,179 +336,179 @@ static void sdl2_update_screen(const uint8_t *p, int present) {
} }
} }
static void handle_keyevent(int keysym, bool keydown) { static void handle_keyevent(int keysym, bool keydown, struct input_t *input) {
switch (keysym) { switch (keysym) {
case SDLK_LEFT: case SDLK_LEFT:
if (keydown) { if (keydown) {
_input->direction |= INPUT_DIRECTION_LEFT; input->direction |= INPUT_DIRECTION_LEFT;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_LEFT; input->direction &= ~INPUT_DIRECTION_LEFT;
} }
break; break;
case SDLK_RIGHT: case SDLK_RIGHT:
if (keydown) { if (keydown) {
_input->direction |= INPUT_DIRECTION_RIGHT; input->direction |= INPUT_DIRECTION_RIGHT;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_RIGHT; input->direction &= ~INPUT_DIRECTION_RIGHT;
} }
break; break;
case SDLK_UP: case SDLK_UP:
if (keydown) { if (keydown) {
_input->direction |= INPUT_DIRECTION_UP; input->direction |= INPUT_DIRECTION_UP;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_UP; input->direction &= ~INPUT_DIRECTION_UP;
} }
break; break;
case SDLK_DOWN: case SDLK_DOWN:
if (keydown) { if (keydown) {
_input->direction |= INPUT_DIRECTION_DOWN; input->direction |= INPUT_DIRECTION_DOWN;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_DOWN; input->direction &= ~INPUT_DIRECTION_DOWN;
} }
break; break;
case SDLK_RETURN: case SDLK_RETURN:
case SDLK_SPACE: case SDLK_SPACE:
_input->space = keydown; input->space = keydown;
break; break;
case SDLK_ESCAPE: case SDLK_ESCAPE:
_input->escape = keydown; input->escape = keydown;
break; break;
case SDLK_1: case SDLK_1:
_input->digit1 = keydown; input->digit1 = keydown;
break; break;
case SDLK_2: case SDLK_2:
_input->digit2 = keydown; input->digit2 = keydown;
break; break;
case SDLK_3: case SDLK_3:
_input->digit3 = keydown; input->digit3 = keydown;
break; break;
} }
} }
static void handle_controlleraxis(int axis, int value) { static void handle_controlleraxis(int axis, int value, struct input_t *input) {
static const int THRESHOLD = 3200; static const int THRESHOLD = 3200;
switch (axis) { switch (axis) {
case SDL_CONTROLLER_AXIS_LEFTX: case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_RIGHTX: case SDL_CONTROLLER_AXIS_RIGHTX:
if (value < -THRESHOLD) { if (value < -THRESHOLD) {
_input->direction |= INPUT_DIRECTION_LEFT; input->direction |= INPUT_DIRECTION_LEFT;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_LEFT; input->direction &= ~INPUT_DIRECTION_LEFT;
} }
if (value > THRESHOLD) { if (value > THRESHOLD) {
_input->direction |= INPUT_DIRECTION_RIGHT; input->direction |= INPUT_DIRECTION_RIGHT;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_RIGHT; input->direction &= ~INPUT_DIRECTION_RIGHT;
} }
break; break;
case SDL_CONTROLLER_AXIS_LEFTY: case SDL_CONTROLLER_AXIS_LEFTY:
case SDL_CONTROLLER_AXIS_RIGHTY: case SDL_CONTROLLER_AXIS_RIGHTY:
if (value < -THRESHOLD) { if (value < -THRESHOLD) {
_input->direction |= INPUT_DIRECTION_UP; input->direction |= INPUT_DIRECTION_UP;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_UP; input->direction &= ~INPUT_DIRECTION_UP;
} }
if (value > THRESHOLD) { if (value > THRESHOLD) {
_input->direction |= INPUT_DIRECTION_DOWN; input->direction |= INPUT_DIRECTION_DOWN;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_DOWN; input->direction &= ~INPUT_DIRECTION_DOWN;
} }
break; break;
} }
} }
static void handle_controllerbutton(int button, bool pressed) { static void handle_controllerbutton(int button, bool pressed, struct input_t *input) {
switch (button) { switch (button) {
case SDL_CONTROLLER_BUTTON_A: case SDL_CONTROLLER_BUTTON_A:
case SDL_CONTROLLER_BUTTON_B: case SDL_CONTROLLER_BUTTON_B:
case SDL_CONTROLLER_BUTTON_X: case SDL_CONTROLLER_BUTTON_X:
case SDL_CONTROLLER_BUTTON_Y: case SDL_CONTROLLER_BUTTON_Y:
_input->space = pressed; input->space = pressed;
break; break;
case SDL_CONTROLLER_BUTTON_BACK: case SDL_CONTROLLER_BUTTON_BACK:
_input->escape = pressed; input->escape = pressed;
break; break;
case SDL_CONTROLLER_BUTTON_START: case SDL_CONTROLLER_BUTTON_START:
break; break;
case SDL_CONTROLLER_BUTTON_DPAD_UP: case SDL_CONTROLLER_BUTTON_DPAD_UP:
if (pressed) { if (pressed) {
_input->direction |= INPUT_DIRECTION_UP; input->direction |= INPUT_DIRECTION_UP;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_UP; input->direction &= ~INPUT_DIRECTION_UP;
} }
break; break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
if (pressed) { if (pressed) {
_input->direction |= INPUT_DIRECTION_DOWN; input->direction |= INPUT_DIRECTION_DOWN;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_DOWN; input->direction &= ~INPUT_DIRECTION_DOWN;
} }
break; break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
if (pressed) { if (pressed) {
_input->direction |= INPUT_DIRECTION_LEFT; input->direction |= INPUT_DIRECTION_LEFT;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_LEFT; input->direction &= ~INPUT_DIRECTION_LEFT;
} }
break; break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
if (pressed) { if (pressed) {
_input->direction |= INPUT_DIRECTION_RIGHT; input->direction |= INPUT_DIRECTION_RIGHT;
} else { } else {
_input->direction &= ~INPUT_DIRECTION_RIGHT; input->direction &= ~INPUT_DIRECTION_RIGHT;
} }
break; break;
} }
} }
static void handle_joystickhatmotion(int value) { static void handle_joystickhatmotion(int value, struct input_t *input) {
_input->direction = 0; input->direction = 0;
if (value & SDL_HAT_UP) { if (value & SDL_HAT_UP) {
_input->direction |= INPUT_DIRECTION_UP; input->direction |= INPUT_DIRECTION_UP;
} }
if (value & SDL_HAT_DOWN) { if (value & SDL_HAT_DOWN) {
_input->direction |= INPUT_DIRECTION_DOWN; input->direction |= INPUT_DIRECTION_DOWN;
} }
if (value & SDL_HAT_LEFT) { if (value & SDL_HAT_LEFT) {
_input->direction |= INPUT_DIRECTION_LEFT; input->direction |= INPUT_DIRECTION_LEFT;
} }
if (value & SDL_HAT_RIGHT) { if (value & SDL_HAT_RIGHT) {
_input->direction |= INPUT_DIRECTION_RIGHT; input->direction |= INPUT_DIRECTION_RIGHT;
} }
} }
static void handle_joystickaxismotion(int axis, int value) { static void handle_joystickaxismotion(int axis, int value, struct input_t *input) {
static const int THRESHOLD = 3200; static const int THRESHOLD = 3200;
switch (axis) { switch (axis) {
case 0: case 0:
_input->direction &= ~(INPUT_DIRECTION_RIGHT | INPUT_DIRECTION_LEFT); input->direction &= ~(INPUT_DIRECTION_RIGHT | INPUT_DIRECTION_LEFT);
if (value > THRESHOLD) { if (value > THRESHOLD) {
_input->direction |= INPUT_DIRECTION_RIGHT; input->direction |= INPUT_DIRECTION_RIGHT;
} else if (value < -THRESHOLD) { } else if (value < -THRESHOLD) {
_input->direction |= INPUT_DIRECTION_LEFT; input->direction |= INPUT_DIRECTION_LEFT;
} }
break; break;
case 1: case 1:
_input->direction &= ~(INPUT_DIRECTION_UP | INPUT_DIRECTION_DOWN); input->direction &= ~(INPUT_DIRECTION_UP | INPUT_DIRECTION_DOWN);
if (value > THRESHOLD) { if (value > THRESHOLD) {
_input->direction |= INPUT_DIRECTION_DOWN; input->direction |= INPUT_DIRECTION_DOWN;
} else if (value < -THRESHOLD) { } else if (value < -THRESHOLD) {
_input->direction |= INPUT_DIRECTION_UP; input->direction |= INPUT_DIRECTION_UP;
} }
break; break;
} }
} }
static void handle_joystickbutton(int button, int pressed) { static void handle_joystickbutton(int button, int pressed, struct input_t *input) {
if (button == 0) { if (button == 0) {
_input->space = pressed; input->space = pressed;
} }
} }
static int handle_event(const SDL_Event *ev, bool *paused) { static int handle_event(const SDL_Event *ev, bool *paused) {
switch (ev->type) { switch (ev->type) {
case SDL_QUIT: case SDL_QUIT:
_input->quit = true; g_sys.input.quit = true;
break; break;
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
switch (ev->window.event) { switch (ev->window.event) {
@ -494,10 +520,10 @@ static int handle_event(const SDL_Event *ev, bool *paused) {
} }
break; break;
case SDL_KEYUP: case SDL_KEYUP:
handle_keyevent(ev->key.keysym.sym, 0); handle_keyevent(ev->key.keysym.sym, 0, &g_sys.input);
break; break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
handle_keyevent(ev->key.keysym.sym, 1); handle_keyevent(ev->key.keysym.sym, 1, &g_sys.input);
break; break;
case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEADDED:
if (!_controller) { if (!_controller) {
@ -516,37 +542,37 @@ static int handle_event(const SDL_Event *ev, bool *paused) {
break; break;
case SDL_CONTROLLERBUTTONUP: case SDL_CONTROLLERBUTTONUP:
if (_controller) { if (_controller) {
handle_controllerbutton(ev->cbutton.button, 0); handle_controllerbutton(ev->cbutton.button, 0, &g_sys.input);
} }
break; break;
case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONDOWN:
if (_controller) { if (_controller) {
handle_controllerbutton(ev->cbutton.button, 1); handle_controllerbutton(ev->cbutton.button, 1, &g_sys.input);
} }
break; break;
case SDL_CONTROLLERAXISMOTION: case SDL_CONTROLLERAXISMOTION:
if (_controller) { if (_controller) {
handle_controlleraxis(ev->caxis.axis, ev->caxis.value); handle_controlleraxis(ev->caxis.axis, ev->caxis.value, &g_sys.input);
} }
break; break;
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION:
if (_joystick) { if (_joystick) {
handle_joystickhatmotion(ev->jhat.value); handle_joystickhatmotion(ev->jhat.value, &g_sys.input);
} }
break; break;
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
if (_joystick) { if (_joystick) {
handle_joystickaxismotion(ev->jaxis.axis, ev->jaxis.value); handle_joystickaxismotion(ev->jaxis.axis, ev->jaxis.value, &g_sys.input);
} }
break; break;
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
if (_joystick) { if (_joystick) {
handle_joystickbutton(ev->jbutton.button, 0); handle_joystickbutton(ev->jbutton.button, 0, &g_sys.input);
} }
break; break;
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
if (_joystick) { if (_joystick) {
handle_joystickbutton(ev->jbutton.button, 1); handle_joystickbutton(ev->jbutton.button, 1, &g_sys.input);
} }
break; break;
default: default:
@ -561,7 +587,7 @@ static void sdl2_process_events() {
SDL_Event ev; SDL_Event ev;
while (SDL_PollEvent(&ev)) { while (SDL_PollEvent(&ev)) {
handle_event(&ev, &paused); handle_event(&ev, &paused);
if (_input->quit) { if (g_sys.input.quit) {
break; break;
} }
} }
@ -606,39 +632,45 @@ static void sdl2_unlock_audio() {
SDL_UnlockAudio(); SDL_UnlockAudio();
} }
static void render_load_sprites(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h, int palette_offset, uint8_t color_key) { static void render_load_sprites(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h, uint8_t color_key, bool update_pal) {
assert(spr_type < ARRAYSIZE(_spritesheets)); assert(spr_type < ARRAYSIZE(_spritesheets));
struct spritesheet_t *spr_sheet = &_spritesheets[spr_type]; struct spritesheet_t *sheet = &_spritesheets[spr_type];
spr_sheet->count = count; sheet->count = count;
spr_sheet->r = (SDL_Rect *)malloc(count * sizeof(SDL_Rect)); sheet->r = (SDL_Rect *)malloc(count * sizeof(SDL_Rect));
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
SDL_Rect *rect = &spr_sheet->r[i]; SDL_Rect *rect = &sheet->r[i];
rect->x = r[i].x; rect->x = r[i].x;
rect->y = r[i].y; rect->y = r[i].y;
rect->w = r[i].w; rect->w = r[i].w;
rect->h = r[i].h; rect->h = r[i].h;
} }
uint32_t *argb = (uint32_t *)malloc(w * h * sizeof(uint32_t)); SDL_Surface *surface = SDL_CreateRGBSurface(0, w, h, 8, 0x0, 0x0, 0x0, 0x0);
if (!argb) { SDL_SetSurfacePalette(surface, _palette);
print_warning("Failed to allocate RGB buffer for sprites type %d", spr_type); SDL_SetColorKey(surface, 1, color_key);
} else { SDL_LockSurface(surface);
spr_sheet->texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, w, h); for (int y = 0; y < h; ++y) {
SDL_SetTextureBlendMode(spr_sheet->texture, SDL_BLENDMODE_BLEND); memcpy(((uint8_t *)surface->pixels) + y * surface->pitch, data + y * w, w);
for (int i = 0; i < w * h; ++i) { }
argb[i] = (data[i] == color_key) ? 0 : (0xFF000000 | _screen_palette[palette_offset + data[i]]); SDL_UnlockSurface(surface);
} sheet->texture = SDL_CreateTextureFromSurface(_renderer, surface);
SDL_UpdateTexture(spr_sheet->texture, 0, argb, w * sizeof(uint32_t)); if (update_pal) { /* update texture on palette change */
free(argb); sheet->surface = surface;
} else {
SDL_FreeSurface(sheet->surface);
sheet->surface = 0;
} }
} }
static void render_unload_sprites(int spr_type) { static void render_unload_sprites(int spr_type) {
struct spritesheet_t *spr_sheet = &_spritesheets[spr_type]; struct spritesheet_t *sheet = &_spritesheets[spr_type];
free(spr_sheet->r); free(sheet->r);
if (spr_sheet->texture) { if (sheet->surface) {
SDL_DestroyTexture(spr_sheet->texture); SDL_FreeSurface(sheet->surface);
} }
memset(spr_sheet, 0, sizeof(struct spritesheet_t)); if (sheet->texture) {
SDL_DestroyTexture(sheet->texture);
}
memset(sheet, 0, sizeof(struct spritesheet_t));
} }
static void render_add_sprite(int spr_type, int frame, int x, int y, int xflip) { static void render_add_sprite(int spr_type, int frame, int x, int y, int xflip) {