Import blues from 116fbc7a
This commit is contained in:
parent
a9b55449cd
commit
4859c25ba0
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
SDL_CFLAGS := `sdl2-config --cflags`
|
SDL_CFLAGS := `sdl2-config --cflags`
|
||||||
SDL_LIBS := `sdl2-config --libs` -lSDL2_mixer
|
SDL_LIBS := `sdl2-config --libs`
|
||||||
|
|
||||||
SRCS := decode.c fileio.c game.c level.c main.c opcodes.c resource.c screen.c sound.c staticres.c sys_sdl2.c triggers.c unpack.c util.c
|
SRCS := decode.c fileio.c game.c level.c main.c opcodes.c resource.c screen.c sound.c staticres.c sys_sdl2.c triggers.c unpack.c util.c
|
||||||
OBJS := $(SRCS:.c=.o)
|
OBJS := $(SRCS:.c=.o)
|
||||||
|
|
8
decode.c
8
decode.c
|
@ -6,9 +6,9 @@ void decode_ega_spr(const uint8_t *src, int src_pitch, int w, int h, uint8_t *ds
|
||||||
src_pitch /= 8;
|
src_pitch /= 8;
|
||||||
assert((w & 7) == 0);
|
assert((w & 7) == 0);
|
||||||
w /= 8;
|
w /= 8;
|
||||||
|
dst += dst_y * dst_pitch + dst_x;
|
||||||
const int bitplane_size = w * h;
|
const int bitplane_size = w * h;
|
||||||
for (int y = 0; y < h; ++y) {
|
for (int y = 0; y < h; ++y) {
|
||||||
const int y_offset = dst_y + y;
|
|
||||||
for (int x = 0; x < w; ++x) {
|
for (int x = 0; x < w; ++x) {
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
int color = 0;
|
int color = 0;
|
||||||
|
@ -18,14 +18,12 @@ void decode_ega_spr(const uint8_t *src, int src_pitch, int w, int h, uint8_t *ds
|
||||||
color |= 1 << (3 - bit);
|
color |= 1 << (3 - bit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (color != 0) {
|
dst[x * 8 + i] = color;
|
||||||
const int x_offset = dst_x + (x * 8 + i);
|
|
||||||
dst[y_offset * dst_pitch + x_offset] = color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
++src;
|
++src;
|
||||||
}
|
}
|
||||||
src += src_pitch - w;
|
src += src_pitch - w;
|
||||||
|
dst += dst_pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
fileio.c
3
fileio.c
|
@ -55,8 +55,9 @@ int fio_open(const char *filename, int error_flag) {
|
||||||
if (!file_slot->fp) {
|
if (!file_slot->fp) {
|
||||||
if (error_flag) {
|
if (error_flag) {
|
||||||
print_error("Unable to open file '%s'", filename);
|
print_error("Unable to open file '%s'", filename);
|
||||||
|
} else {
|
||||||
|
print_warning("Unable to open file '%s'", filename);
|
||||||
}
|
}
|
||||||
print_warning("Unable to open file '%s'", filename);
|
|
||||||
slot = -1;
|
slot = -1;
|
||||||
} else {
|
} else {
|
||||||
fseek(file_slot->fp, 0, SEEK_END);
|
fseek(file_slot->fp, 0, SEEK_END);
|
||||||
|
|
6
game.c
6
game.c
|
@ -282,12 +282,12 @@ static void do_inter_screen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_main() {
|
void game_main() {
|
||||||
|
play_music(0);
|
||||||
g_vars.screen_w = GAME_SCREEN_W;
|
g_vars.screen_w = GAME_SCREEN_W;
|
||||||
g_vars.screen_h = GAME_SCREEN_H;
|
g_vars.screen_h = GAME_SCREEN_H;
|
||||||
g_vars.screen_draw_offset = 0;
|
g_vars.screen_draw_offset = 0;
|
||||||
screen_flip();
|
screen_flip();
|
||||||
screen_init();
|
screen_init();
|
||||||
g_sys.set_screen_size(GAME_SCREEN_W, GAME_SCREEN_H, "Blues Brothers");
|
|
||||||
g_vars.start_level = 0;
|
g_vars.start_level = 0;
|
||||||
load_sqv("sprite.sqv", g_res.spr_sqv, 0);
|
load_sqv("sprite.sqv", g_res.spr_sqv, 0);
|
||||||
if (g_options.amiga_sprites) {
|
if (g_options.amiga_sprites) {
|
||||||
|
@ -303,7 +303,7 @@ void game_main() {
|
||||||
g_sys.set_palette_amiga(palette, 16);
|
g_sys.set_palette_amiga(palette, 16);
|
||||||
}
|
}
|
||||||
do_title_screen();
|
do_title_screen();
|
||||||
while (g_sys.input.quit == 0) {
|
while (!g_sys.input.quit) {
|
||||||
if (!g_vars.level_completed_flag) {
|
if (!g_vars.level_completed_flag) {
|
||||||
// _level_cheat_code = 0;
|
// _level_cheat_code = 0;
|
||||||
g_vars.game_over_flag = 0;
|
g_vars.game_over_flag = 0;
|
||||||
|
@ -316,7 +316,7 @@ void game_main() {
|
||||||
}
|
}
|
||||||
screen_unk5();
|
screen_unk5();
|
||||||
}
|
}
|
||||||
while (g_sys.input.quit == 0 && g_vars.play_level_flag) {
|
while (!g_sys.input.quit && g_vars.play_level_flag) {
|
||||||
if (!g_vars.game_over_flag) {
|
if (!g_vars.game_over_flag) {
|
||||||
do_inter_screen();
|
do_inter_screen();
|
||||||
}
|
}
|
||||||
|
|
39
level.c
39
level.c
|
@ -58,16 +58,12 @@ static const struct {
|
||||||
{ "concert.blk", "concert.tbl", 0, "concert.bin", "ennemi6" },
|
{ "concert.blk", "concert.tbl", 0, "concert.bin", "ennemi6" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *_demo_filenames[] = {
|
|
||||||
"demomag.ck1", "demomag.ck2", "demomag.sql"
|
|
||||||
};
|
|
||||||
|
|
||||||
void load_level_data(int num) {
|
void load_level_data(int num) {
|
||||||
print_debug(DBG_GAME, "load_level_data num %d", num);
|
print_debug(DBG_GAME, "load_level_data num %d", num);
|
||||||
if (num == 0 && (g_res.flags & RESOURCE_FLAGS_DEMO)) {
|
if (num == 0 && (g_res.flags & RESOURCE_FLAGS_DEMO)) {
|
||||||
load_ck(_demo_filenames[0], 0x6000);
|
load_ck("demomag.ck1", 0x6000);
|
||||||
load_ck(_demo_filenames[1], 0x8000);
|
load_ck("demomag.ck2", 0x8000);
|
||||||
load_sql(_demo_filenames[2]);
|
load_sql("demomag.sql");
|
||||||
} else {
|
} else {
|
||||||
load_ck(_levels[num].ck1, 0x6000);
|
load_ck(_levels[num].ck1, 0x6000);
|
||||||
load_ck(_levels[num].ck2, 0x8000);
|
load_ck(_levels[num].ck2, 0x8000);
|
||||||
|
@ -96,9 +92,18 @@ void load_level_data(int num) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_level() {
|
static void init_level() {
|
||||||
|
static const uint16_t restart_xpos[] = { 720, 720, 912, 912, 336, 352, 288, 304, 960, 976, 64, 80 };
|
||||||
|
static const uint16_t restart_ypos[] = { 496, 496, 752, 752, 816, 816, 304, 304, 592, 592, 352, 352 };
|
||||||
|
if (g_vars.play_demo_flag) {
|
||||||
|
g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0;
|
||||||
|
}
|
||||||
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] >> 4) - 10;
|
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;
|
||||||
} else {
|
} else {
|
||||||
g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + 10;
|
g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + 10;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +114,11 @@ static void init_level() {
|
||||||
|
|
||||||
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] >> 4) - 6;
|
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;
|
||||||
} else {
|
} else {
|
||||||
g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + 6;
|
g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + 6;
|
||||||
}
|
}
|
||||||
|
@ -158,7 +167,8 @@ static void init_level() {
|
||||||
obj->xpos = g_vars.level_xpos[i];
|
obj->xpos = g_vars.level_xpos[i];
|
||||||
obj->ypos = g_vars.level_ypos[i];
|
obj->ypos = g_vars.level_ypos[i];
|
||||||
} else {
|
} else {
|
||||||
print_warning("init_level: obj #%d unk60 %d", i, obj->unk60);
|
obj->xpos = restart_xpos[g_vars.level * 2 + obj->type];
|
||||||
|
obj->ypos = restart_ypos[g_vars.level * 2 + obj->type];
|
||||||
}
|
}
|
||||||
print_debug(DBG_GAME, "init_level obj #%d pos %d,%d", i, obj->xpos, obj->ypos);
|
print_debug(DBG_GAME, "init_level obj #%d pos %d,%d", i, obj->xpos, obj->ypos);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2153,9 +2163,9 @@ static void draw_foreground_tiles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_level() {
|
void do_level() {
|
||||||
const int w = TILEMAP_SCREEN_W / 16;
|
static const int W = 320 / 16;
|
||||||
for (int i = 0; i < 256; ++i) {
|
for (int tile_num = 0; tile_num < 256; ++tile_num) {
|
||||||
g_vars.screen_tile_lut[i] = (i / w) * 640 + (i % w);
|
g_vars.screen_tile_lut[tile_num] = (tile_num / W) * 640 + (tile_num % W);
|
||||||
}
|
}
|
||||||
g_vars.screen_tilemap_w = level_dim[g_vars.level * 2];
|
g_vars.screen_tilemap_w = level_dim[g_vars.level * 2];
|
||||||
g_vars.screen_tilemap_h = level_dim[g_vars.level * 2 + 1];
|
g_vars.screen_tilemap_h = level_dim[g_vars.level * 2 + 1];
|
||||||
|
@ -2174,7 +2184,6 @@ void do_level() {
|
||||||
if (g_options.amiga_colors) {
|
if (g_options.amiga_colors) {
|
||||||
g_sys.set_palette_amiga(_colors_data + g_vars.level * 16, 0);
|
g_sys.set_palette_amiga(_colors_data + g_vars.level * 16, 0);
|
||||||
}
|
}
|
||||||
// _time_sync_ptr[1] = 1:
|
|
||||||
g_vars.inp_keyboard[0xB9] = 0; // SPACE
|
g_vars.inp_keyboard[0xB9] = 0; // SPACE
|
||||||
g_vars.screen_draw_offset = TILEMAP_OFFSET_Y * 40;
|
g_vars.screen_draw_offset = TILEMAP_OFFSET_Y * 40;
|
||||||
g_vars.update_objects_counter = 0;
|
g_vars.update_objects_counter = 0;
|
||||||
|
@ -2228,7 +2237,7 @@ void do_level() {
|
||||||
screen_clear_sprites();
|
screen_clear_sprites();
|
||||||
// _draw_last_sprite_flag = 1;
|
// _draw_last_sprite_flag = 1;
|
||||||
|
|
||||||
} while (g_sys.input.quit == 0 && !g_vars.quit_level_flag);
|
} while (!g_sys.input.quit && !g_vars.quit_level_flag);
|
||||||
g_vars.screen_draw_offset -= TILEMAP_OFFSET_Y * 40;
|
g_vars.screen_draw_offset -= TILEMAP_OFFSET_Y * 40;
|
||||||
screen_unk5();
|
screen_unk5();
|
||||||
if (g_options.amiga_copper_bars) {
|
if (g_options.amiga_copper_bars) {
|
||||||
|
|
20
main.c
20
main.c
|
@ -12,6 +12,10 @@ struct options_t g_options;
|
||||||
|
|
||||||
static const char *DEFAULT_DATA_PATH = ".";
|
static const char *DEFAULT_DATA_PATH = ".";
|
||||||
|
|
||||||
|
static const int DEFAULT_SCALE_FACTOR = 2;
|
||||||
|
|
||||||
|
static const char *DEFAULT_SCALE_FILTER = 0; // nearest pixel sampling
|
||||||
|
|
||||||
static const char *USAGE =
|
static const char *USAGE =
|
||||||
"Usage: %s [OPTIONS]...\n"
|
"Usage: %s [OPTIONS]...\n"
|
||||||
" --datapath=PATH Path to data files (default '.')\n"
|
" --datapath=PATH Path to data files (default '.')\n"
|
||||||
|
@ -26,6 +30,9 @@ int main(int argc, char *argv[]) {
|
||||||
// g_options.amiga_sprites = true;
|
// g_options.amiga_sprites = true;
|
||||||
// g_options.amiga_data = true;
|
// g_options.amiga_data = true;
|
||||||
const char *data_path = DEFAULT_DATA_PATH;
|
const char *data_path = DEFAULT_DATA_PATH;
|
||||||
|
int scale_factor = DEFAULT_SCALE_FACTOR;
|
||||||
|
const char *scale_filter = DEFAULT_SCALE_FILTER;
|
||||||
|
bool fullscreen = false;
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) {
|
if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||||
|
@ -39,6 +46,9 @@ int main(int argc, char *argv[]) {
|
||||||
{ "debug", required_argument, 0, 3 },
|
{ "debug", required_argument, 0, 3 },
|
||||||
{ "cheats", required_argument, 0, 4 },
|
{ "cheats", required_argument, 0, 4 },
|
||||||
{ "startpos", required_argument, 0, 5 },
|
{ "startpos", required_argument, 0, 5 },
|
||||||
|
{ "fullscreen", no_argument, 0, 6 },
|
||||||
|
{ "scale", required_argument, 0, 7 },
|
||||||
|
{ "filter", required_argument, 0, 8 },
|
||||||
{ 0, 0, 0, 0 },
|
{ 0, 0, 0, 0 },
|
||||||
};
|
};
|
||||||
int index;
|
int index;
|
||||||
|
@ -62,6 +72,15 @@ int main(int argc, char *argv[]) {
|
||||||
case 5:
|
case 5:
|
||||||
sscanf(optarg, "%dx%d", &g_options.start_xpos16, &g_options.start_ypos16);
|
sscanf(optarg, "%dx%d", &g_options.start_xpos16, &g_options.start_ypos16);
|
||||||
break;
|
break;
|
||||||
|
case 6:
|
||||||
|
fullscreen = true;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
scale_factor = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
scale_filter = strdup(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stdout, USAGE, argv[0]);
|
fprintf(stdout, USAGE, argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -70,6 +89,7 @@ int main(int argc, char *argv[]) {
|
||||||
fio_init(data_path);
|
fio_init(data_path);
|
||||||
res_init();
|
res_init();
|
||||||
g_sys.init();
|
g_sys.init();
|
||||||
|
g_sys.set_screen_size(GAME_SCREEN_W, GAME_SCREEN_H, "Blues Brothers", scale_factor, scale_filter, fullscreen);
|
||||||
sound_init(SYS_AUDIO_FREQ);
|
sound_init(SYS_AUDIO_FREQ);
|
||||||
game_main();
|
game_main();
|
||||||
sound_fini();
|
sound_fini();
|
||||||
|
|
|
@ -300,9 +300,13 @@ static void object_func_op13(struct object_t *obj) {
|
||||||
obj->special_anim = 1;
|
obj->special_anim = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void object_func_op14_helper(int x1, int y1, int x2, int y2, int color) {
|
||||||
|
print_warning("object_func_op14_helper: unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
static void object_func_op14(struct object_t *obj) {
|
static void object_func_op14(struct object_t *obj) {
|
||||||
obj->special_anim = 2;
|
obj->special_anim = 2;
|
||||||
// sub_1AD3B(obj->xpos, level_ypos_egou[obj->unk5D] - _screen_tilemap_yorigin, obj->xpos, obj->ypos - 5, 3);
|
object_func_op14_helper(obj->xpos, level_ypos_egou[obj->unk5D] - g_vars.screen_tilemap_yorigin, obj->xpos, obj->ypos - 5, 3);
|
||||||
if (obj->elevator_direction == 1) {
|
if (obj->elevator_direction == 1) {
|
||||||
if (obj->moving_direction < 25) {
|
if (obj->moving_direction < 25) {
|
||||||
++obj->moving_direction;
|
++obj->moving_direction;
|
||||||
|
|
30
screen.c
30
screen.c
|
@ -5,8 +5,8 @@
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define MAX_SPRITESHEET_W 1024
|
#define MAX_SPRITESHEET_W 512
|
||||||
#define MAX_SPRITESHEET_H 512
|
#define MAX_SPRITESHEET_H 512
|
||||||
|
|
||||||
void screen_init() {
|
void screen_init() {
|
||||||
}
|
}
|
||||||
|
@ -183,28 +183,24 @@ static void decode_graphics(int spr_type, int start, int end) {
|
||||||
}
|
}
|
||||||
current_x = 0;
|
current_x = 0;
|
||||||
max_h = h;
|
max_h = h;
|
||||||
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 {
|
} else {
|
||||||
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;
|
|
||||||
current_x += w;
|
|
||||||
if (h > max_h) {
|
if (h > max_h) {
|
||||||
max_h = h;
|
max_h = h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
r[j].w = w;
|
r[j].w = w;
|
||||||
r[j].h = h;
|
r[j].h = h;
|
||||||
|
current_x += w;
|
||||||
|
if (h > max_h) {
|
||||||
|
max_h = h;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|
13
sys.h
13
sys.h
|
@ -12,13 +12,10 @@
|
||||||
#define SYS_AUDIO_FREQ 22050
|
#define SYS_AUDIO_FREQ 22050
|
||||||
|
|
||||||
struct input_t {
|
struct input_t {
|
||||||
char quit;
|
uint8_t direction;
|
||||||
char escape;
|
bool quit;
|
||||||
char space;
|
bool escape;
|
||||||
char direction;
|
bool space;
|
||||||
char functions[12];
|
|
||||||
char digits[10];
|
|
||||||
char alphabet[26];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*sys_audio_cb)(void *, uint8_t *data, int len);
|
typedef void (*sys_audio_cb)(void *, uint8_t *data, int len);
|
||||||
|
@ -32,7 +29,7 @@ struct sys_t {
|
||||||
struct input_t input;
|
struct input_t input;
|
||||||
int (*init)();
|
int (*init)();
|
||||||
void (*fini)();
|
void (*fini)();
|
||||||
void (*set_screen_size)(int w, int h, const char *caption);
|
void (*set_screen_size)(int w, int h, const char *caption, int scale, const char *filter, bool fullscreen);
|
||||||
void (*set_screen_palette)(const uint8_t *colors, int);
|
void (*set_screen_palette)(const uint8_t *colors, int);
|
||||||
void (*set_palette_amiga)(const uint16_t *colors, int offset);
|
void (*set_palette_amiga)(const uint16_t *colors, int offset);
|
||||||
void (*set_copper_bars)(const uint16_t *data);
|
void (*set_copper_bars)(const uint16_t *data);
|
||||||
|
|
175
sys_sdl2.c
175
sys_sdl2.c
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#define COPPER_BARS_H 80
|
#define COPPER_BARS_H 80
|
||||||
|
|
||||||
static const int SCALE = 2;
|
|
||||||
static const int FADE_STEPS = 16;
|
static const int FADE_STEPS = 16;
|
||||||
|
|
||||||
struct spritesheet_t {
|
struct spritesheet_t {
|
||||||
|
@ -37,9 +36,10 @@ static uint32_t *_screen_buffer;
|
||||||
static struct input_t *_input = &g_sys.input;
|
static struct input_t *_input = &g_sys.input;
|
||||||
static int _copper_color;
|
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 int sdl2_init() {
|
static int sdl2_init() {
|
||||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
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;
|
_window = 0;
|
||||||
|
@ -49,10 +49,32 @@ static int sdl2_init() {
|
||||||
memset(_screen_palette, 0, sizeof(_screen_palette));
|
memset(_screen_palette, 0, sizeof(_screen_palette));
|
||||||
_screen_buffer = 0;
|
_screen_buffer = 0;
|
||||||
_copper_color = -1;
|
_copper_color = -1;
|
||||||
|
SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
|
||||||
|
_controller = 0;
|
||||||
|
const int count = SDL_NumJoysticks();
|
||||||
|
if (count > 0) {
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
if (SDL_IsGameController(i)) {
|
||||||
|
_controller = SDL_GameControllerOpen(i);
|
||||||
|
if (_controller) {
|
||||||
|
fprintf(stdout, "Using controller '%s'\n", SDL_GameControllerName(_controller));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl2_fini() {
|
static void sdl2_fini() {
|
||||||
|
if (_fmt) {
|
||||||
|
SDL_FreeFormat(_fmt);
|
||||||
|
_fmt = 0;
|
||||||
|
}
|
||||||
|
if (_texture) {
|
||||||
|
SDL_DestroyTexture(_texture);
|
||||||
|
_texture = 0;
|
||||||
|
}
|
||||||
if (_renderer) {
|
if (_renderer) {
|
||||||
SDL_DestroyRenderer(_renderer);
|
SDL_DestroyRenderer(_renderer);
|
||||||
_renderer = 0;
|
_renderer = 0;
|
||||||
|
@ -61,27 +83,31 @@ static void sdl2_fini() {
|
||||||
SDL_DestroyWindow(_window);
|
SDL_DestroyWindow(_window);
|
||||||
_window = 0;
|
_window = 0;
|
||||||
}
|
}
|
||||||
if (_texture) {
|
|
||||||
SDL_DestroyTexture(_texture);
|
|
||||||
_texture = 0;
|
|
||||||
}
|
|
||||||
if (_fmt) {
|
|
||||||
SDL_FreeFormat(_fmt);
|
|
||||||
_fmt = 0;
|
|
||||||
}
|
|
||||||
free(_screen_buffer);
|
free(_screen_buffer);
|
||||||
|
if (_controller) {
|
||||||
|
SDL_GameControllerClose(_controller);
|
||||||
|
_controller = 0;
|
||||||
|
}
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl2_set_screen_size(int w, int h, const char *caption) {
|
static void sdl2_set_screen_size(int w, int h, const char *caption, int scale, const char *filter, bool fullscreen) {
|
||||||
assert(_screen_w == 0 && _screen_h == 0); // abort if called more than once
|
assert(_screen_w == 0 && _screen_h == 0); // abort if called more than once
|
||||||
_screen_w = w;
|
_screen_w = w;
|
||||||
_screen_h = h;
|
_screen_h = h;
|
||||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); /* nearest pixel sampling */
|
if (!filter || strcmp(filter, "nearest") == 0) {
|
||||||
const int window_w = w * SCALE;
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
|
||||||
const int window_h = h * SCALE; // * 4 / 3;
|
} else if (strcmp(filter, "linear") == 0) {
|
||||||
_window = SDL_CreateWindow(caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, SDL_WINDOW_RESIZABLE);
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
|
||||||
|
} else {
|
||||||
|
print_warning("Unhandled filter '%s'", filter);
|
||||||
|
}
|
||||||
|
const int window_w = w * scale;
|
||||||
|
const int window_h = h * scale;
|
||||||
|
const int flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE;
|
||||||
|
_window = SDL_CreateWindow(caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, flags);
|
||||||
_renderer = SDL_CreateRenderer(_window, -1, 0);
|
_renderer = SDL_CreateRenderer(_window, -1, 0);
|
||||||
|
SDL_RenderSetLogicalSize(_renderer, w, h);
|
||||||
print_debug(DBG_SYSTEM, "set_screen_size %d,%d", _screen_w, _screen_h);
|
print_debug(DBG_SYSTEM, "set_screen_size %d,%d", _screen_w, _screen_h);
|
||||||
_screen_buffer = (uint32_t *)calloc(_screen_w * _screen_h, sizeof(uint32_t));
|
_screen_buffer = (uint32_t *)calloc(_screen_w * _screen_h, sizeof(uint32_t));
|
||||||
if (!_screen_buffer) {
|
if (!_screen_buffer) {
|
||||||
|
@ -190,10 +216,10 @@ static void sdl2_update_screen(const uint8_t *p, int present) {
|
||||||
struct sprite_t *spr = &_sprites[i];
|
struct sprite_t *spr = &_sprites[i];
|
||||||
struct spritesheet_t *sheet = &_spritesheets[spr->sheet];
|
struct spritesheet_t *sheet = &_spritesheets[spr->sheet];
|
||||||
SDL_Rect r;
|
SDL_Rect r;
|
||||||
r.x = spr->x * SCALE;
|
r.x = spr->x;
|
||||||
r.y = spr->y * SCALE;
|
r.y = spr->y;
|
||||||
r.w = sheet->r[spr->num].w * SCALE;
|
r.w = sheet->r[spr->num].w;
|
||||||
r.h = sheet->r[spr->num].h * SCALE;
|
r.h = sheet->r[spr->num].h;
|
||||||
if (!spr->xflip) {
|
if (!spr->xflip) {
|
||||||
SDL_RenderCopy(_renderer, sheet->texture, &sheet->r[spr->num], &r);
|
SDL_RenderCopy(_renderer, sheet->texture, &sheet->r[spr->num], &r);
|
||||||
} else {
|
} else {
|
||||||
|
@ -205,7 +231,7 @@ static void sdl2_update_screen(const uint8_t *p, int present) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_keyevent(int keysym, int keydown) {
|
static void handle_keyevent(int keysym, bool keydown) {
|
||||||
switch (keysym) {
|
switch (keysym) {
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
if (keydown) {
|
if (keydown) {
|
||||||
|
@ -239,6 +265,85 @@ static void handle_keyevent(int keysym, int keydown) {
|
||||||
case SDLK_SPACE:
|
case SDLK_SPACE:
|
||||||
_input->space = keydown;
|
_input->space = keydown;
|
||||||
break;
|
break;
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
_input->escape = keydown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_controlleraxis(int axis, int value) {
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_LEFT;
|
||||||
|
}
|
||||||
|
if (value > THRESHOLD) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_RIGHT;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_RIGHT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||||
|
if (value < -THRESHOLD) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_UP;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_UP;
|
||||||
|
}
|
||||||
|
if (value > THRESHOLD) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_DOWN;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_DOWN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_controllerbutton(int button, bool pressed) {
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_BACK:
|
||||||
|
_input->escape = pressed;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_START:
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||||
|
if (pressed) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_UP;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_UP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||||
|
if (pressed) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_DOWN;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_DOWN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||||
|
if (pressed) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_LEFT;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_LEFT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||||
|
if (pressed) {
|
||||||
|
_input->direction |= INPUT_DIRECTION_RIGHT;
|
||||||
|
} else {
|
||||||
|
_input->direction &= ~INPUT_DIRECTION_RIGHT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +358,36 @@ static int handle_event(const SDL_Event *ev) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
handle_keyevent(ev->key.keysym.sym, 1);
|
handle_keyevent(ev->key.keysym.sym, 1);
|
||||||
break;
|
break;
|
||||||
|
case SDL_CONTROLLERDEVICEADDED:
|
||||||
|
if (!_controller) {
|
||||||
|
_controller = SDL_GameControllerOpen(ev->cdevice.which);
|
||||||
|
if (_controller) {
|
||||||
|
fprintf(stdout, "Using controller '%s'\n", SDL_GameControllerName(_controller));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERDEVICEREMOVED:
|
||||||
|
if (_controller == SDL_GameControllerFromInstanceID(ev->cdevice.which)) {
|
||||||
|
fprintf(stdout, "Removed controller '%s'\n", SDL_GameControllerName(_controller));
|
||||||
|
SDL_GameControllerClose(_controller);
|
||||||
|
_controller = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERBUTTONUP:
|
||||||
|
if (_controller) {
|
||||||
|
handle_controllerbutton(ev->cbutton.button, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERBUTTONDOWN:
|
||||||
|
if (_controller) {
|
||||||
|
handle_controllerbutton(ev->cbutton.button, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERAXISMOTION:
|
||||||
|
if (_controller) {
|
||||||
|
handle_controlleraxis(ev->caxis.axis, ev->caxis.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue