diff --git a/blues1.png b/blues1.png index 94d4509..fc05f00 100644 Binary files a/blues1.png and b/blues1.png differ diff --git a/blues2.png b/blues2.png index 5f89f6b..19a65f5 100644 Binary files a/blues2.png and b/blues2.png differ diff --git a/decode.c b/decode.c index 14e775c..acba802 100644 --- a/decode.c +++ b/decode.c @@ -49,3 +49,23 @@ void decode_amiga_planar8(const uint8_t *src, int w, int h, int depth, uint8_t * dst += dst_pitch; } } + +void decode_amiga_blk(const uint8_t *src, uint8_t *dst, int dst_pitch) { + uint16_t data[4]; + for (int y = 0; y < 16; ++y) { + for (int p = 0; p < 4; ++p) { + data[p] = READ_BE_UINT16(src); src += 2; + } + for (int b = 0; b < 16; ++b) { + const int mask = 1 << (15 - b); + uint8_t color = 0; + for (int p = 0; p < 4; ++p) { + if (data[p] & mask) { + color |= 1 << p; + } + } + dst[b] = color; + } + dst += dst_pitch; + } +} diff --git a/decode.h b/decode.h index 7ccd477..3fb759a 100644 --- a/decode.h +++ b/decode.h @@ -6,5 +6,6 @@ extern void decode_ega_spr(const uint8_t *src, int src_pitch, int w, int h, uint8_t *dst, int dst_pitch, int dst_x, int dst_y); extern void decode_amiga_planar8(const uint8_t *src, int w, int h, int depth, uint8_t *dst, int dst_pitch, int dst_x, int dst_y); +extern void decode_amiga_blk(const uint8_t *src, uint8_t *dst, int dst_pitch); #endif /* DECODE_H__ */ diff --git a/game.c b/game.c index a5e0c2f..8491903 100644 --- a/game.c +++ b/game.c @@ -3,6 +3,12 @@ #include "resource.h" #include "sys.h" +// palette colors 16..31 +static const uint16_t _colors2_data[] = { + 0x1a0,0x000,0x1a2,0xfdd,0x1a4,0x678,0x1a6,0x046,0x1a8,0x000,0x1aa,0xa20,0x1ac,0xf87,0x1ae,0x955, + 0x1b0,0xbcf,0x1b2,0xfca,0x1b4,0x30a,0x1b6,0xa9a,0x1b8,0x900,0x1ba,0x666,0x1bc,0x747,0x1be,0x020 +}; + struct vars_t g_vars; void update_input() { @@ -17,7 +23,7 @@ void update_input() { void do_title_screen() { const uint32_t timestamp = g_sys.get_timestamp() + 20 * 1000; - load_img(g_options.amiga_lbms ? "blues.lbm" : "pres.sqz"); + load_img(g_options.amiga_data ? "blues.lbm" : "pres.sqz"); fade_in_palette(); do { update_input(); @@ -52,7 +58,7 @@ void do_select_player() { int frame2 = 1; const int color_rgb = 2; const int colors_count = 25; - load_img(g_options.amiga_lbms ? "choix.lbm" : "choix.sqz"); + load_img(g_options.amiga_data ? "choix.lbm" : "choix.sqz"); screen_load_graphics(); screen_clear_sprites(); do { @@ -238,7 +244,7 @@ static void do_inter_screen_helper(int xpos, int ypos, int c) { static void do_inter_screen() { static const uint8_t xpos[] = { 0xFA, 0x50, 0xF0, 0xC8, 0x50, 0x50 }; static const uint8_t ypos[] = { 0xAA, 0x37, 0x28, 0x5F, 0xA5, 0xAA }; - load_img(g_options.amiga_lbms ? "inter.lbm" : "inter.sqz"); + load_img(g_options.amiga_data ? "inter.lbm" : "inter.sqz"); g_vars.screen_h = 199; screen_clear_sprites(); if (g_vars.level > 1) { @@ -284,6 +290,18 @@ void game_main() { g_sys.set_screen_size(GAME_SCREEN_W, GAME_SCREEN_H, "Blues Brothers"); g_vars.start_level = 0; load_sqv("sprite.sqv", g_res.spr_sqv, 0); + if (g_options.amiga_sprites) { + load_spr("sprite", g_res.spr_sqv, 0); + // load_spr("objet", g_res.spr_sqv, 101); + } + if (g_options.amiga_colors) { + uint16_t palette[16]; + for (int i = 0; i < 16; ++i) { + assert(_colors2_data[i * 2] == 0x1a0 + i * 2); + palette[i] = _colors2_data[i * 2 + 1]; + } + g_sys.set_palette_amiga(palette, 16); + } do_title_screen(); while (g_sys.input.quit == 0) { if (!g_vars.level_completed_flag) { diff --git a/game.h b/game.h index 92002b9..a182d85 100644 --- a/game.h +++ b/game.h @@ -43,7 +43,6 @@ struct options_t { bool amiga_copper_bars; bool amiga_colors; bool amiga_sprites; - bool amiga_lbms; bool amiga_data; }; diff --git a/level.c b/level.c index 4dba431..41e7a27 100644 --- a/level.c +++ b/level.c @@ -15,11 +15,6 @@ static const uint16_t _copper_data[18 * MAX_LEVELS] = { 0x198,0x400,0x500,0x600,0x700,0x800,0x900,0xa00,0xb00,0xc00,0xd00,0xe00,0xf00,0xf11,0xf22,0xf33,0xf44,0xf55 }; -static const uint16_t _colors2_data[] = { - 0x1a0,0x000,0x1a2,0xfdd,0x1a4,0x678,0x1a6,0x046,0x1a8,0x000,0x1aa,0xa20,0x1ac,0xf87,0x1ae,0x955, - 0x1b0,0xbcf,0x1b2,0xfca,0x1b4,0x30a,0x1b6,0xa9a,0x1b8,0x900,0x1ba,0x666,0x1bc,0x747,0x1be,0x020 -}; - static const uint16_t _colors_data[16 * MAX_LEVELS] = { 0x000,0xc77,0x989,0x669,0x147,0xfda,0xdb9,0xf87,0x4af,0x050,0x091,0x111,0xbcf,0xa20,0x630,0xfff, 0x000,0xa67,0xb89,0x067,0x046,0xeb8,0xca5,0xf87,0x4af,0x660,0x980,0x111,0x59c,0xa25,0x635,0xfff, @@ -49,15 +44,18 @@ static const struct { }; static const struct { + const char *blk; + const char *tbl; const char *m; const char *bin; + const char *ennemi; } _levels_amiga[MAX_LEVELS] = { - { "mag.m", "magasin.bin" }, - { "ent.m", "entrepo.bin" }, - { "pris.m", "prison.bin" }, - { "egou.m", "egout.bin" }, - { "ville.m", "ville.bin" }, - { 0, "concert.bin" }, + { "mag.blk", "mag.tbl", "mag.m", "magasin.bin", "ennemi1" }, + { "ent.blk", "ent.tbl", "ent.m", "entrepo.bin", "ennemi2" }, + { "prison.blk", "prison.tbl", "pris.m", "prison.bin", "ennemi3" }, + { "egout.blk", "egout.tbl", "egou.m", "egout.bin", "ennemi4" }, + { "ville.blk", "ville.tbl", "ville.m", "ville.bin", "ennemi5" }, + { "concert.blk", "concert.tbl", 0, "concert.bin", "ennemi6" }, }; static const char *_demo_filenames[] = { @@ -76,15 +74,15 @@ void load_level_data(int num) { load_sql(_levels[num].sql); } if (g_options.amiga_data) { + load_blk(_levels_amiga[num].blk); + read_file(_levels_amiga[num].tbl, g_res.sql, 0); load_bin(_levels_amiga[num].bin); } else { load_bin(_levels[num].bin); } load_avt(_levels[num].avt, g_res.avt_sqv, 0); if (g_options.amiga_sprites) { - char name[16]; - snprintf(name, sizeof(name), "ennemi%d", 1 + num); - load_spr(name, g_res.tmp, SPRITES_COUNT); + load_spr(_levels_amiga[num].ennemi, g_res.tmp, SPRITES_COUNT); } else { load_sqv(_levels[num].sqv, g_res.tmp, SPRITES_COUNT); } @@ -304,6 +302,7 @@ static void do_level_update_tiles_anim() { } else { const int current = data[0]; num = data[current + 1]; + *ptr = num; t->unk16 = num; } if (num >= 128) { @@ -2173,13 +2172,7 @@ void do_level() { g_sys.set_copper_bars(_copper_data + g_vars.level * 18); } if (g_options.amiga_colors) { - uint16_t palette[32]; - memcpy(palette, _colors_data + g_vars.level * 16, 16 * sizeof(uint16_t)); - for (int i = 0; i < 16; ++i) { - assert(_colors2_data[i * 2] == 0x1a0 + i * 2); - palette[16 + i] = _colors2_data[i * 2 + 1]; - } - g_sys.set_palette_amiga(palette); + g_sys.set_palette_amiga(_colors_data + g_vars.level * 16, 0); } // _time_sync_ptr[1] = 1: g_vars.inp_keyboard[0xB9] = 0; // SPACE diff --git a/main.c b/main.c index 2e29017..0de9ca9 100644 --- a/main.c +++ b/main.c @@ -24,7 +24,6 @@ int main(int argc, char *argv[]) { g_options.amiga_copper_bars = true; g_options.amiga_colors = true; // g_options.amiga_sprites = true; - // g_options.amiga_lbms = true; // g_options.amiga_data = true; const char *data_path = DEFAULT_DATA_PATH; if (argc == 2) { diff --git a/resource.c b/resource.c index af1ac79..edb5e8b 100644 --- a/resource.c +++ b/resource.c @@ -8,7 +8,7 @@ struct resource_data_t g_res; void res_init() { - static const int SQL_SIZE = 1000 * 16; + static const int SQL_SIZE = 640 * 25; g_res.sql = (uint8_t *)malloc(SQL_SIZE); if (!g_res.sql) { print_error("Failed to allocate sql buffer, %d bytes", SQL_SIZE); @@ -223,6 +223,10 @@ void load_bin(const char *filename) { } } +void load_blk(const char *filename) { + read_file(filename, g_res.tiles, 256 * 16 * 8); +} + void load_ck(const char *filename, uint16_t offset) { const int size = read_compressed_file(filename, g_res.tmp); switch (offset) { @@ -255,7 +259,7 @@ void load_img(const char *filename) { memcpy(g_res.vga, g_res.tmp + 32000, 64000); } -static int load_spr_helper(int offset, const uint8_t *ptr, uint16_t (*read16)(const uint8_t *)) { +static int load_spr_helper(int offset, const uint8_t *ptr, uint16_t (*read16)(const uint8_t *), int depth) { const int count = read16(ptr); ptr += 6; print_debug(DBG_RESOURCE, "spr count %d", count); assert(offset + count <= MAX_SPR_FRAMES); @@ -264,16 +268,18 @@ static int load_spr_helper(int offset, const uint8_t *ptr, uint16_t (*read16)(co const int h = read16(ptr - 4); const int w = read16(ptr - 2); assert((w & 3) == 0); - const int size = (w >> 1) * h + 4; + const int size = h * w * depth / 8; print_debug(DBG_RESOURCE, "sprite %d, dim %d,%d size %d", i, w, h, size); - ptr += size; + ptr += size + 4; } return count; } void load_spr(const char *filename, uint8_t *dst, int offset) { read_file(filename, dst, 0); - const int count = load_spr_helper(offset, dst, READ_BE_UINT16); + // player sprites use 8 colors + const int depth = (offset == 0) ? 3 : 4; + const int count = load_spr_helper(offset, dst, READ_BE_UINT16, depth); g_res.spr_count = offset + count; // convert to little endian uint8_t *ptr = dst; @@ -285,14 +291,14 @@ void load_spr(const char *filename, uint8_t *dst, int offset) { ptr[4] = w; ptr[5] = 0; assert((w & 3) == 0); - const int size = (w >> 1) * h + 4; - ptr += size; + const int size = h * w * depth / 8; + ptr += size + 4; } } void load_sqv(const char *filename, uint8_t *dst, int offset) { read_compressed_file(filename, dst); - const int count = load_spr_helper(offset, dst, READ_LE_UINT16); + const int count = load_spr_helper(offset, dst, READ_LE_UINT16, 4); g_res.spr_count = offset + count; } diff --git a/resource.h b/resource.h index e03b153..c852aaa 100644 --- a/resource.h +++ b/resource.h @@ -54,6 +54,7 @@ extern int read_file(const char *filename, uint8_t *dst, int size); extern int read_compressed_file(const char *filename, uint8_t *dst); extern void load_avt(const char *filename, uint8_t *dst, int offset); extern void load_bin(const char *filename); +extern void load_blk(const char *filename); extern void load_ck(const char *filename, uint16_t offset); extern void load_img(const char *filename); extern void load_spr(const char *filename, uint8_t *dst, int offset); diff --git a/screen.c b/screen.c index 53686a7..dde3a3f 100644 --- a/screen.c +++ b/screen.c @@ -160,7 +160,6 @@ void screen_add_game_sprite4(int x, int y, int frame, int blinking_counter) { } static void decode_graphics(int spr_type, int start, int end) { - const bool amiga = g_options.amiga_sprites && start != 0; struct sys_rect_t r[MAX_SPR_FRAMES]; uint8_t *data = (uint8_t *)calloc(MAX_SPRITESHEET_W * MAX_SPRITESHEET_H, 1); if (data) { @@ -170,6 +169,10 @@ static void decode_graphics(int spr_type, int start, int end) { int max_h = 0; for (int i = start; i < end; ++i) { const uint8_t *ptr = g_res.spr_frames[i]; + if (!ptr) { + memset(&r[i], 0, sizeof(struct sys_rect_t)); + continue; + } const int h = READ_LE_UINT16(ptr - 4); const int w = READ_LE_UINT16(ptr - 2); const int j = i - start; @@ -180,16 +183,16 @@ static void decode_graphics(int spr_type, int start, int end) { } current_x = 0; max_h = h; - if (amiga) { - decode_amiga_planar8(ptr, w / 8, h, 4, data, MAX_SPRITESHEET_W, current_x, current_y); + if (g_options.amiga_sprites) { + decode_amiga_planar8(ptr, w / 8, h, (start == 0) ? 3 : 4, data, MAX_SPRITESHEET_W, current_x, current_y); } else { decode_ega_spr(ptr, w, w, h, data, MAX_SPRITESHEET_W, current_x, current_y); } r[j].x = current_x; r[j].y = current_y; } else { - if (amiga) { - decode_amiga_planar8(ptr, w / 8, h, 4, data, MAX_SPRITESHEET_W, current_x, current_y); + if (g_options.amiga_sprites) { + decode_amiga_planar8(ptr, w / 8, h, (start == 0) ? 3 : 4, data, MAX_SPRITESHEET_W, current_x, current_y); } else { decode_ega_spr(ptr, w, w, h, data, MAX_SPRITESHEET_W, current_x, current_y); } @@ -206,7 +209,8 @@ static void decode_graphics(int spr_type, int start, int end) { assert(max_w <= MAX_SPRITESHEET_W); assert(current_y + max_h <= MAX_SPRITESHEET_H); render_unload_sprites(spr_type); - render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h); + const int palette_offset = (g_options.amiga_sprites && start == 0) ? 16 : 0; + render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h, palette_offset); free(data); } } @@ -216,6 +220,7 @@ void screen_load_graphics() { decode_graphics(RENDER_SPR_GAME, 0, SPRITES_COUNT); } else { decode_graphics(RENDER_SPR_LEVEL, SPRITES_COUNT, g_res.spr_count); + // foreground tiles struct sys_rect_t r[MAX_SPR_FRAMES]; static const int FG_TILE_W = 16; static const int FG_TILE_H = 16; @@ -230,8 +235,24 @@ void screen_load_graphics() { r[i].h = FG_TILE_H; } render_unload_sprites(RENDER_SPR_FG); - render_load_sprites(RENDER_SPR_FG, g_res.avt_count, r, data, g_res.avt_count * FG_TILE_W, FG_TILE_H); + render_load_sprites(RENDER_SPR_FG, g_res.avt_count, r, data, g_res.avt_count * FG_TILE_W, FG_TILE_H, 0); free(data); } + // background tiles (Amiga) - re-arrange to match DOS .ck1/.ck2 layout + if (g_options.amiga_data) { + static const int BG_TILES_COUNT = 256; + static const int W = 320 / 16; + memcpy(g_res.tmp, g_res.tiles, BG_TILES_COUNT * 16 * 8); + for (int i = 0; i < 128; ++i) { + const int y = (i / W); + const int x = (i % W); + decode_amiga_blk(g_res.tmp + i * 16 * 8, g_res.tiles + (y * 640 + x) * 16, 640); + } + for (int i = 128; i < 256; ++i) { + const int y = ((i - 128) / W); + const int x = ((i - 128) % W) + W; + decode_amiga_blk(g_res.tmp + i * 16 * 8, g_res.tiles + (y * 640 + x) * 16, 640); + } + } } } diff --git a/sys.h b/sys.h index a567581..8e444bd 100644 --- a/sys.h +++ b/sys.h @@ -34,7 +34,7 @@ struct sys_t { void (*fini)(); void (*set_screen_size)(int w, int h, const char *caption); void (*set_screen_palette)(const uint8_t *colors, int); - void (*set_palette_amiga)(const uint16_t *colors); + void (*set_palette_amiga)(const uint16_t *colors, int offset); void (*set_copper_bars)(const uint16_t *data); void (*fade_in_palette)(); void (*fade_out_palette)(); @@ -52,14 +52,11 @@ extern struct sys_t g_sys; #define RENDER_SPR_GAME 0 /* player sprites */ #define RENDER_SPR_LEVEL 1 /* level sprites */ -#define RENDER_SPR_FONT 2 /* font (digits) */ -#define RENDER_SPR_FG 3 /* foreground tiles */ +#define RENDER_SPR_FG 2 /* foreground tiles */ -extern void render_load_sprites(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h); +extern 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); extern void render_unload_sprites(int spr_type); extern void render_add_sprite(int spr_type, int frame, int x, int y, int xflip); extern void render_clear_sprites(); -extern void render_draw_tilemap(int x, int y); -extern void render_draw_image(); #endif /* SYS_H__ */ diff --git a/sys_sdl2.c b/sys_sdl2.c index 533220f..fda3f1e 100644 --- a/sys_sdl2.c +++ b/sys_sdl2.c @@ -14,7 +14,7 @@ struct spritesheet_t { SDL_Texture *texture; }; -static struct spritesheet_t _spritesheets[4]; +static struct spritesheet_t _spritesheets[3]; struct sprite_t { int sheet; @@ -102,9 +102,9 @@ static uint32_t convert_amiga_color(uint16_t color) { return SDL_MapRGB(_fmt, r, g, b); } -static void sdl2_set_palette_amiga(const uint16_t *colors) { - for (int i = 0; i < 32; ++i) { - _screen_palette[i] = convert_amiga_color(colors[i]); +static void sdl2_set_palette_amiga(const uint16_t *colors, int offset) { + for (int i = 0; i < 16; ++i) { + _screen_palette[offset + i] = convert_amiga_color(colors[i]); } } @@ -322,7 +322,7 @@ struct sys_t g_sys = { .unlock_audio = sdl2_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) { +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) { assert(spr_type < ARRAYSIZE(_spritesheets)); struct spritesheet_t *spr_sheet = &_spritesheets[spr_type]; spr_sheet->count = count; @@ -341,7 +341,7 @@ void render_load_sprites(int spr_type, int count, const struct sys_rect_t *r, co 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] == 0) ? 0 : (0xFF000000 | _screen_palette[data[i]]); + argb[i] = (data[i] == 0) ? 0 : (0xFF000000 | _screen_palette[palette_offset + data[i]]); } SDL_UpdateTexture(spr_sheet->texture, 0, argb, w * sizeof(uint32_t)); free(argb);