diff --git a/bb/level.c b/bb/level.c index ba5fbdd..44edd91 100644 --- a/bb/level.c +++ b/bb/level.c @@ -106,30 +106,32 @@ static void init_level() { if (g_vars.play_demo_flag) { g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0; } + const int xoffs = (TILEMAP_SCREEN_W / 16) / 2; int xpos = g_options.start_xpos16; if (xpos < 0) { 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)) { xpos = restart_xpos[g_vars.level * 2]; } - xpos = (xpos >> 4) - 10; + xpos = (xpos >> 4) - xoffs; } else { - g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + 10; + g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + xoffs; } if (xpos < 0) { xpos = 0; } g_vars.screen_tilemap_xorigin = xpos << 4; + const int yoffs = (TILEMAP_SCREEN_H / 16) / 2 + 1; int ypos = g_options.start_ypos16; if (ypos < 0) { 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)) { ypos = restart_ypos[g_vars.level * 2]; } - ypos = (ypos >> 4) - 6; + ypos = (ypos >> 4) - yoffs; } else { - g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + 6; + g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + yoffs; } if (ypos < 0) { ypos = 0; diff --git a/bb/screen.c b/bb/screen.c index 4dec4a9..f5c0363 100644 --- a/bb/screen.c +++ b/bb/screen.c @@ -272,11 +272,17 @@ static void decode_graphics(int spr_type, int start, int end, const uint8_t *dit 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(current_y + max_h <= MAX_SPRITESHEET_H); 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, palette_offset, color_key); + g_sys.render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h, color_key, false); 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); } 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); } // background tiles (Amiga) - re-arrange to match DOS .ck1/.ck2 layout diff --git a/bb/unpack.c b/bb/unpack.c index a44e71a..4713cfb 100644 --- a/bb/unpack.c +++ b/bb/unpack.c @@ -4,50 +4,43 @@ struct unpack_t { uint8_t dict_buf[0x200 * 2]; - uint8_t rd[0x1000]; }; static struct unpack_t g_unpack; int unpack(FILE *in, uint8_t *dst) { - fread(g_unpack.rd, 1, 6, in); - const int uncompressed_size = (READ_LE_UINT16(g_unpack.rd) << 16) + READ_LE_UINT16(g_unpack.rd + 2); - const int dict_len = READ_LE_UINT16(g_unpack.rd + 4); + uint8_t buf[6]; + fread(buf, 1, 6, in); + 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); fread(g_unpack.dict_buf, 1, dict_len, in); const uint8_t *start = dst; - const uint8_t *src = g_unpack.rd; - int len = 1; - int bytes_count = 2; + int bits_count = 1; uint16_t bits = 0; uint16_t val = 0; while ((dst - start) < uncompressed_size) { - --len; - if (len == 0) { - bytes_count -= 2; - if (bytes_count == 0) { - bytes_count = fread(g_unpack.rd, 1, 0x1000, in); - if (bytes_count == 0) { - break; - } - bytes_count += (bytes_count & 1); - src = g_unpack.rd; + --bits_count; + if (bits_count == 0) { + if (fread(buf, 1, 2, in) == 0) { + break; } - bits = READ_BE_UINT16(src); src += 2; - len = 17; - continue; + bits = READ_BE_UINT16(buf); + bits_count = 16; } - const int carry = (bits & 0x8000) != 0; + const bool carry = (bits & 0x8000) != 0; bits <<= 1; if (carry) { val += 2; } - assert(val < 0x400); + assert((val & 1) == 0); + assert(val < dict_len); val = READ_LE_UINT16(g_unpack.dict_buf + val); if ((val & 0x8000) == 0) { continue; } + assert((val & 0x7F00) == 0); *dst++ = val & 255; val = 0; } diff --git a/ja/screen.c b/ja/screen.c index 94defba..b795a0b 100644 --- a/ja/screen.c +++ b/ja/screen.c @@ -231,7 +231,7 @@ void video_load_sprites() { assert(max_w <= MAX_SPRITESHEET_W); assert(current_y + max_h <= MAX_SPRITESHEET_H); 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); } } diff --git a/p2/bosses.c b/p2/bosses.c index f570a84..4102545 100644 --- a/p2/bosses.c +++ b/p2/bosses.c @@ -138,23 +138,23 @@ static void level_update_boss_gorilla_init_objects(const uint16_t *p) { ++g_vars.boss.parts[3].y_pos; } if (g_vars.boss.hdir) { - g_vars.boss.parts[0].spr_num |= 0x8000; - g_vars.boss.parts[1].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) { + g_vars.boss.parts[i].spr_num |= 0x8000; + } } for (int i = 0; i < 5; ++i) { struct object_t *obj = &g_vars.objects_tbl[103 + i]; const uint16_t addr = *p++; - if (addr == 0xA609) { + switch (addr) { + case 0xA609: g_vars.boss.obj1 = obj; - } - if (addr == 0xA60F) { + break; + case 0xA60F: g_vars.boss.obj2 = obj; - } - if (addr == 0xA603) { + break; + case 0xA603: g_vars.boss.obj3 = obj; + break; } assert(addr == 0xA5F7 || addr == 0xA5FD || addr == 0xA603 || addr == 0xA609 || addr == 0xA60F); const int num = (addr - 0xA5F7) / 6; @@ -597,7 +597,7 @@ static void level_update_boss_tree() { g_vars.boss_level5.spr106_pos = 0; } uint8_t ah = 1; - if (g_vars.boss_level5.spr106_pos != 0) { + if (g_vars.boss_level5.spr106_pos != 1) { ah = 3; g_vars.shake_screen_counter = 4; obj_player->x_pos += 2; diff --git a/p2/game.h b/p2/game.h index 33a0ad8..6495497 100644 --- a/p2/game.h +++ b/p2/game.h @@ -299,7 +299,7 @@ extern const uint8_t monster_anim_tbl[1100]; extern const uint8_t boss_minotaur_seq_data[86]; 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 snow_pattern1_data[11]; +extern const uint16_t snow_pattern1_data[1]; extern const uint16_t snow_pattern2_data[10]; /* game.c */ diff --git a/p2/level.c b/p2/level.c index b910e94..4424759 100644 --- a/p2/level.c +++ b/p2/level.c @@ -944,7 +944,7 @@ static void level_update_tile1(uint16_t offset) { level_update_tile_type_1(offset); break; case 2: - level_update_tile_type_2(offset); + level_update_tile_type_2(); break; default: 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); level_update_object_anim(anim); 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; return; diff --git a/p2/screen.c b/p2/screen.c index 67afe08..e417e8b 100644 --- a/p2/screen.c +++ b/p2/screen.c @@ -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) { 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) { uint8_t code = *s++; if (code != 0x20) { @@ -68,10 +71,10 @@ void video_draw_string(int offset, int hspace, const char *s) { if (code > 9) { code -= 2; } - decode_planar(g_res.allfonts + code * 48, g_res.vga + offset * 8, 320, 8, 12, 0); - } - ++offset; - } + decode_planar(g_res.allfonts + code * 48, dst, GAME_SCREEN_W, 8, 12, 0); + } + dst += 8; + } } 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); ++tile; 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; } } @@ -260,7 +263,7 @@ void video_load_sprites() { assert(max_w <= MAX_SPRITESHEET_W); assert(current_y + max_h <= MAX_SPRITESHEET_H); 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); print_debug(DBG_SCREEN, "sprites total_size %d count %d", offset, count); } diff --git a/p2/unpack.c b/p2/unpack.c index 790a8a5..e69c106 100644 --- a/p2/unpack.c +++ b/p2/unpack.c @@ -250,7 +250,7 @@ static int unpack_sqv(FILE *in, struct unpack_sqv_t *u) { int bytes_count = 2; int state = 0; int count = 0; - uint8_t code, prev; + uint8_t code, prev = 0; uint16_t bits = 0; uint16_t val = 0; while ((dst - output_buffer) < uncompressed_size) { diff --git a/sys.h b/sys.h index 1bc9fcb..2effbfa 100644 --- a/sys.h +++ b/sys.h @@ -55,7 +55,7 @@ struct sys_t { void (*stop_audio)(); void (*lock_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_add_sprite)(int spr_type, int frame, int x, int y, int xflip); void (*render_clear_sprites)(); diff --git a/sys_sdl2.c b/sys_sdl2.c index 98dd83b..6d97980 100644 --- a/sys_sdl2.c +++ b/sys_sdl2.c @@ -5,16 +5,18 @@ #define COPPER_BARS_H 80 #define MAX_SPRITES 256 +#define MAX_SPRITESHEETS 3 static const int FADE_STEPS = 16; struct spritesheet_t { int count; SDL_Rect *r; + SDL_Surface *surface; SDL_Texture *texture; }; -static struct spritesheet_t _spritesheets[3]; +static struct spritesheet_t _spritesheets[MAX_SPRITESHEETS]; struct sprite_t { int sheet; @@ -33,11 +35,12 @@ static SDL_Window *_window; static SDL_Renderer *_renderer; static SDL_Texture *_texture; static SDL_PixelFormat *_fmt; +static SDL_Palette *_palette; static uint32_t _screen_palette[256]; static uint32_t *_screen_buffer; -static struct input_t *_input = &g_sys.input; -static int _copper_color; +static int _copper_color_key; static uint32_t _copper_palette[COPPER_BARS_H]; + static SDL_GameController *_controller; 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_ShowCursor(SDL_DISABLE); _screen_w = _screen_h = 0; - _window = 0; - _renderer = 0; - _texture = 0; - _fmt = 0; memset(_screen_palette, 0, sizeof(_screen_palette)); + _palette = SDL_AllocPalette(256); _screen_buffer = 0; - _copper_color = -1; + _copper_color_key = -1; SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); _controller = 0; const int count = SDL_NumJoysticks(); @@ -80,6 +80,10 @@ static void sdl2_fini() { SDL_FreeFormat(_fmt); _fmt = 0; } + if (_palette) { + SDL_FreePalette(_palette); + _palette = 0; + } if (_texture) { SDL_DestroyTexture(_texture); _texture = 0; @@ -140,22 +144,33 @@ static uint32_t convert_amiga_color(uint16_t color) { r |= r << 4; uint8_t g = (color >> 4) & 15; g |= g << 4; - uint8_t b = color & 15; + uint8_t b = color & 15; b |= b << 4; 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) { + SDL_Color *palette_colors = &_palette->colors[offset]; for (int i = 0; i < 16; ++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) { if (!data) { - _copper_color = -1; + _copper_color_key = -1; } else { - _copper_color = (data[0] - 0x180) / 2; + _copper_color_key = (data[0] - 0x180) / 2; const uint16_t *src = data + 1; uint32_t *dst = _copper_palette; 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) { + SDL_Color *palette_colors = &_palette->colors[offset]; const int shift = 8 - depth; for (int i = 0; i < count; ++i) { 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)); } _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; } + 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) { @@ -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) { - if (_copper_color != -1) { + if (_copper_color_key != -1) { for (int j = 0; j < _screen_h; ++j) { if (j / 2 < COPPER_BARS_H) { const uint32_t line_color = _copper_palette[j / 2]; 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 { 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) { case SDLK_LEFT: if (keydown) { - _input->direction |= INPUT_DIRECTION_LEFT; + input->direction |= INPUT_DIRECTION_LEFT; } else { - _input->direction &= ~INPUT_DIRECTION_LEFT; + input->direction &= ~INPUT_DIRECTION_LEFT; } break; case SDLK_RIGHT: if (keydown) { - _input->direction |= INPUT_DIRECTION_RIGHT; + input->direction |= INPUT_DIRECTION_RIGHT; } else { - _input->direction &= ~INPUT_DIRECTION_RIGHT; + input->direction &= ~INPUT_DIRECTION_RIGHT; } break; case SDLK_UP: if (keydown) { - _input->direction |= INPUT_DIRECTION_UP; + input->direction |= INPUT_DIRECTION_UP; } else { - _input->direction &= ~INPUT_DIRECTION_UP; + input->direction &= ~INPUT_DIRECTION_UP; } break; case SDLK_DOWN: if (keydown) { - _input->direction |= INPUT_DIRECTION_DOWN; + input->direction |= INPUT_DIRECTION_DOWN; } else { - _input->direction &= ~INPUT_DIRECTION_DOWN; + input->direction &= ~INPUT_DIRECTION_DOWN; } break; case SDLK_RETURN: case SDLK_SPACE: - _input->space = keydown; + input->space = keydown; break; case SDLK_ESCAPE: - _input->escape = keydown; + input->escape = keydown; break; case SDLK_1: - _input->digit1 = keydown; + input->digit1 = keydown; break; case SDLK_2: - _input->digit2 = keydown; + input->digit2 = keydown; break; case SDLK_3: - _input->digit3 = keydown; + input->digit3 = keydown; 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; switch (axis) { case SDL_CONTROLLER_AXIS_LEFTX: case SDL_CONTROLLER_AXIS_RIGHTX: if (value < -THRESHOLD) { - _input->direction |= INPUT_DIRECTION_LEFT; + input->direction |= INPUT_DIRECTION_LEFT; } else { - _input->direction &= ~INPUT_DIRECTION_LEFT; + input->direction &= ~INPUT_DIRECTION_LEFT; } if (value > THRESHOLD) { - _input->direction |= INPUT_DIRECTION_RIGHT; + input->direction |= INPUT_DIRECTION_RIGHT; } else { - _input->direction &= ~INPUT_DIRECTION_RIGHT; + input->direction &= ~INPUT_DIRECTION_RIGHT; } break; case SDL_CONTROLLER_AXIS_LEFTY: case SDL_CONTROLLER_AXIS_RIGHTY: if (value < -THRESHOLD) { - _input->direction |= INPUT_DIRECTION_UP; + input->direction |= INPUT_DIRECTION_UP; } else { - _input->direction &= ~INPUT_DIRECTION_UP; + input->direction &= ~INPUT_DIRECTION_UP; } if (value > THRESHOLD) { - _input->direction |= INPUT_DIRECTION_DOWN; + input->direction |= INPUT_DIRECTION_DOWN; } else { - _input->direction &= ~INPUT_DIRECTION_DOWN; + input->direction &= ~INPUT_DIRECTION_DOWN; } break; } } -static void handle_controllerbutton(int button, bool pressed) { +static void handle_controllerbutton(int button, bool pressed, struct input_t *input) { switch (button) { case SDL_CONTROLLER_BUTTON_A: case SDL_CONTROLLER_BUTTON_B: case SDL_CONTROLLER_BUTTON_X: case SDL_CONTROLLER_BUTTON_Y: - _input->space = pressed; + input->space = pressed; break; case SDL_CONTROLLER_BUTTON_BACK: - _input->escape = pressed; + input->escape = pressed; break; case SDL_CONTROLLER_BUTTON_START: break; case SDL_CONTROLLER_BUTTON_DPAD_UP: if (pressed) { - _input->direction |= INPUT_DIRECTION_UP; + input->direction |= INPUT_DIRECTION_UP; } else { - _input->direction &= ~INPUT_DIRECTION_UP; + input->direction &= ~INPUT_DIRECTION_UP; } break; case SDL_CONTROLLER_BUTTON_DPAD_DOWN: if (pressed) { - _input->direction |= INPUT_DIRECTION_DOWN; + input->direction |= INPUT_DIRECTION_DOWN; } else { - _input->direction &= ~INPUT_DIRECTION_DOWN; + input->direction &= ~INPUT_DIRECTION_DOWN; } break; case SDL_CONTROLLER_BUTTON_DPAD_LEFT: if (pressed) { - _input->direction |= INPUT_DIRECTION_LEFT; + input->direction |= INPUT_DIRECTION_LEFT; } else { - _input->direction &= ~INPUT_DIRECTION_LEFT; + input->direction &= ~INPUT_DIRECTION_LEFT; } break; case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: if (pressed) { - _input->direction |= INPUT_DIRECTION_RIGHT; + input->direction |= INPUT_DIRECTION_RIGHT; } else { - _input->direction &= ~INPUT_DIRECTION_RIGHT; + input->direction &= ~INPUT_DIRECTION_RIGHT; } break; } } -static void handle_joystickhatmotion(int value) { - _input->direction = 0; +static void handle_joystickhatmotion(int value, struct input_t *input) { + input->direction = 0; if (value & SDL_HAT_UP) { - _input->direction |= INPUT_DIRECTION_UP; + input->direction |= INPUT_DIRECTION_UP; } if (value & SDL_HAT_DOWN) { - _input->direction |= INPUT_DIRECTION_DOWN; + input->direction |= INPUT_DIRECTION_DOWN; } if (value & SDL_HAT_LEFT) { - _input->direction |= INPUT_DIRECTION_LEFT; + input->direction |= INPUT_DIRECTION_LEFT; } 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; switch (axis) { case 0: - _input->direction &= ~(INPUT_DIRECTION_RIGHT | INPUT_DIRECTION_LEFT); + input->direction &= ~(INPUT_DIRECTION_RIGHT | INPUT_DIRECTION_LEFT); if (value > THRESHOLD) { - _input->direction |= INPUT_DIRECTION_RIGHT; + input->direction |= INPUT_DIRECTION_RIGHT; } else if (value < -THRESHOLD) { - _input->direction |= INPUT_DIRECTION_LEFT; + input->direction |= INPUT_DIRECTION_LEFT; } break; case 1: - _input->direction &= ~(INPUT_DIRECTION_UP | INPUT_DIRECTION_DOWN); + input->direction &= ~(INPUT_DIRECTION_UP | INPUT_DIRECTION_DOWN); if (value > THRESHOLD) { - _input->direction |= INPUT_DIRECTION_DOWN; + input->direction |= INPUT_DIRECTION_DOWN; } else if (value < -THRESHOLD) { - _input->direction |= INPUT_DIRECTION_UP; + input->direction |= INPUT_DIRECTION_UP; } break; } } -static void handle_joystickbutton(int button, int pressed) { +static void handle_joystickbutton(int button, int pressed, struct input_t *input) { if (button == 0) { - _input->space = pressed; + input->space = pressed; } } static int handle_event(const SDL_Event *ev, bool *paused) { switch (ev->type) { case SDL_QUIT: - _input->quit = true; + g_sys.input.quit = true; break; case SDL_WINDOWEVENT: switch (ev->window.event) { @@ -494,10 +520,10 @@ static int handle_event(const SDL_Event *ev, bool *paused) { } break; case SDL_KEYUP: - handle_keyevent(ev->key.keysym.sym, 0); + handle_keyevent(ev->key.keysym.sym, 0, &g_sys.input); break; case SDL_KEYDOWN: - handle_keyevent(ev->key.keysym.sym, 1); + handle_keyevent(ev->key.keysym.sym, 1, &g_sys.input); break; case SDL_CONTROLLERDEVICEADDED: if (!_controller) { @@ -516,37 +542,37 @@ static int handle_event(const SDL_Event *ev, bool *paused) { break; case SDL_CONTROLLERBUTTONUP: if (_controller) { - handle_controllerbutton(ev->cbutton.button, 0); + handle_controllerbutton(ev->cbutton.button, 0, &g_sys.input); } break; case SDL_CONTROLLERBUTTONDOWN: if (_controller) { - handle_controllerbutton(ev->cbutton.button, 1); + handle_controllerbutton(ev->cbutton.button, 1, &g_sys.input); } break; case SDL_CONTROLLERAXISMOTION: if (_controller) { - handle_controlleraxis(ev->caxis.axis, ev->caxis.value); + handle_controlleraxis(ev->caxis.axis, ev->caxis.value, &g_sys.input); } break; case SDL_JOYHATMOTION: if (_joystick) { - handle_joystickhatmotion(ev->jhat.value); + handle_joystickhatmotion(ev->jhat.value, &g_sys.input); } break; case SDL_JOYAXISMOTION: if (_joystick) { - handle_joystickaxismotion(ev->jaxis.axis, ev->jaxis.value); + handle_joystickaxismotion(ev->jaxis.axis, ev->jaxis.value, &g_sys.input); } break; case SDL_JOYBUTTONUP: if (_joystick) { - handle_joystickbutton(ev->jbutton.button, 0); + handle_joystickbutton(ev->jbutton.button, 0, &g_sys.input); } break; case SDL_JOYBUTTONDOWN: if (_joystick) { - handle_joystickbutton(ev->jbutton.button, 1); + handle_joystickbutton(ev->jbutton.button, 1, &g_sys.input); } break; default: @@ -561,7 +587,7 @@ static void sdl2_process_events() { SDL_Event ev; while (SDL_PollEvent(&ev)) { handle_event(&ev, &paused); - if (_input->quit) { + if (g_sys.input.quit) { break; } } @@ -606,39 +632,45 @@ static void sdl2_unlock_audio() { 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)); - struct spritesheet_t *spr_sheet = &_spritesheets[spr_type]; - spr_sheet->count = count; - spr_sheet->r = (SDL_Rect *)malloc(count * sizeof(SDL_Rect)); + struct spritesheet_t *sheet = &_spritesheets[spr_type]; + sheet->count = count; + sheet->r = (SDL_Rect *)malloc(count * sizeof(SDL_Rect)); 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->y = r[i].y; rect->w = r[i].w; rect->h = r[i].h; } - uint32_t *argb = (uint32_t *)malloc(w * h * sizeof(uint32_t)); - if (!argb) { - print_warning("Failed to allocate RGB buffer for sprites type %d", spr_type); - } else { - spr_sheet->texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, w, h); - SDL_SetTextureBlendMode(spr_sheet->texture, SDL_BLENDMODE_BLEND); - for (int i = 0; i < w * h; ++i) { - argb[i] = (data[i] == color_key) ? 0 : (0xFF000000 | _screen_palette[palette_offset + data[i]]); - } - SDL_UpdateTexture(spr_sheet->texture, 0, argb, w * sizeof(uint32_t)); - free(argb); + SDL_Surface *surface = SDL_CreateRGBSurface(0, w, h, 8, 0x0, 0x0, 0x0, 0x0); + SDL_SetSurfacePalette(surface, _palette); + SDL_SetColorKey(surface, 1, color_key); + SDL_LockSurface(surface); + for (int y = 0; y < h; ++y) { + memcpy(((uint8_t *)surface->pixels) + y * surface->pitch, data + y * w, w); + } + SDL_UnlockSurface(surface); + sheet->texture = SDL_CreateTextureFromSurface(_renderer, surface); + if (update_pal) { /* update texture on palette change */ + sheet->surface = surface; + } else { + SDL_FreeSurface(sheet->surface); + sheet->surface = 0; } } static void render_unload_sprites(int spr_type) { - struct spritesheet_t *spr_sheet = &_spritesheets[spr_type]; - free(spr_sheet->r); - if (spr_sheet->texture) { - SDL_DestroyTexture(spr_sheet->texture); + struct spritesheet_t *sheet = &_spritesheets[spr_type]; + free(sheet->r); + if (sheet->surface) { + 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) {