Import blues from c1e25536

This commit is contained in:
Gregory Montoir 2022-03-13 06:41:23 +08:00
parent 140c6cdb1e
commit 9d70ca5872
22 changed files with 635 additions and 209 deletions

View File

@ -37,11 +37,11 @@ The data files of the DOS version, full game or [demo](http://cd.textfiles.com/c
## Changes
Compared to the original DOS executables, the rewritten engines feature :
Compared to the original DOS executables, the rewritten engines feature:
- horizontal scrolling
- configurable screen size
- game cheats : unlimited lifes and energy, no hit
- game cheats: unlimited lifes and energy, no hit
## Running
@ -66,4 +66,4 @@ Usage: blues [OPTIONS]...
## Downloads
[blues-sdl2-win32.zip](https://www.dropbox.com/s/vv8mh0vrk8l6xro/blues-gh-sdl2-win32.zip?dl=0) - Win32 executable
[blues-sdl2-win32.zip](https://www.dropbox.com/s/rybnnn4s3rmicva/blues-gh-sdl2-win32.zip?dl=0) - Win32 executable

View File

@ -23,12 +23,12 @@ struct vars_t g_vars;
void update_input() {
g_sys.process_events();
g_vars.inp_key_left = ((g_sys.input.direction & INPUT_DIRECTION_LEFT) != 0) || g_vars.inp_keyboard[0x4B] || g_vars.inp_keyboard[0x7A];
g_vars.inp_key_right = ((g_sys.input.direction & INPUT_DIRECTION_RIGHT) != 0) || g_vars.inp_keyboard[0x4D] || g_vars.inp_keyboard[0x79];
g_vars.inp_key_up = ((g_sys.input.direction & INPUT_DIRECTION_UP) != 0) || g_vars.inp_keyboard[0x48] || g_vars.inp_keyboard[0x7C];
g_vars.inp_key_down = ((g_sys.input.direction & INPUT_DIRECTION_DOWN) != 0) || g_vars.inp_keyboard[0x50] || g_vars.inp_keyboard[0x7B];
g_vars.inp_key_space = g_sys.input.space || g_vars.inp_keyboard[0x39] || g_vars.inp_keyboard[0x77];
// g_vars.inp_key_tab = g_vars.inp_keyboard[0xF] || g_vars.inp_keyboard[0x78];
g_vars.inp_key_left = ((g_sys.input.direction & INPUT_DIRECTION_LEFT) != 0);
g_vars.inp_key_right = ((g_sys.input.direction & INPUT_DIRECTION_RIGHT) != 0);
g_vars.inp_key_up = ((g_sys.input.direction & INPUT_DIRECTION_UP) != 0);
g_vars.inp_key_down = ((g_sys.input.direction & INPUT_DIRECTION_DOWN) != 0);
g_vars.inp_key_space = g_sys.input.space;
g_vars.inp_key_jump = g_sys.input.jump;
}
static void do_title_screen() {
@ -78,8 +78,8 @@ static void do_select_player() {
if (g_res.spr_count <= SPRITES_COUNT) {
screen_load_graphics(g_options.cga_colors ? g_res.cga_lut_sqv : 0, 0);
}
screen_clear_sprites();
do {
screen_clear_sprites(1);
update_input();
const uint32_t timestamp = g_sys.get_timestamp();
switch (state) {
@ -205,11 +205,10 @@ static void do_select_player() {
}
continue;
}
screen_flip();
g_sys.update_screen();
screen_vsync();
const int diff = (timestamp + (1000 / 30)) - g_sys.get_timestamp();
g_sys.sleep(diff < 10 ? 10 : diff);
screen_clear_sprites();
if (g_sys.input.space || g_vars.play_demo_flag) {
quit = 1;
}
@ -222,14 +221,14 @@ static void do_inter_screen_helper(int xpos, int ypos, int c) {
if (c != 0) {
screen_vsync();
}
screen_clear_sprites();
screen_clear_sprites(1);
}
for (int i = 0; i < 40; ++i) {
screen_add_sprite(xpos - 20 + 1 + i, ypos - 20 + 1 + i, 125);
if (c != 0) {
screen_vsync();
}
screen_clear_sprites();
screen_clear_sprites(1);
}
}
@ -237,7 +236,7 @@ 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_res.amiga_data ? "inter.lbm" : "inter.sqz", GAME_SCREEN_W, g_options.cga_colors ? 9 : -1);
screen_clear_sprites();
screen_clear_sprites(1);
if (g_vars.level > 1) {
for (int i = 0; i < g_vars.level - 1; ++i) {
do_inter_screen_helper(xpos[i], ypos[i], 0);
@ -251,12 +250,12 @@ static void do_inter_screen() {
do_inter_screen_helper(xpos[g_vars.level - 1], ypos[g_vars.level - 1], 1);
}
// screen_do_transition2();
screen_flip();
g_sys.update_screen();
if (g_vars.level < MAX_LEVELS - 1) {
play_sound(SOUND_2);
screen_add_sprite(xpos[g_vars.level], ypos[g_vars.level], 126);
}
screen_flip();
g_sys.update_screen();
const uint32_t timestamp = g_sys.get_timestamp() + 4 * 1000;
do {
update_input();
@ -270,7 +269,6 @@ static void do_inter_screen() {
void game_main() {
play_music(0);
screen_init();
screen_flip();
g_vars.start_level = 0;
if (g_res.amiga_data) {
load_spr("sprite", g_res.spr_sqv, 0);

View File

@ -152,15 +152,16 @@ struct vars_t {
bool two_players_flag;
bool switch_player_scrolling_flag;
int music_num;
uint8_t inp_keyboard[256];
bool inp_key_jump;
bool inp_key_jump_prev;
bool inp_key_space;
bool inp_key_space_prev;
bool inp_key_up;
bool inp_key_up_prev;
bool inp_key_down;
bool inp_key_down_prev;
bool inp_key_right;
bool inp_key_left;
bool inp_key_up_prev;
bool inp_key_down_prev;
bool inp_key_space_prev;
struct door_t doors[MAX_DOORS];
struct object_t objects[MAX_OBJECTS];
int vinyls_count;
@ -219,13 +220,12 @@ extern void level_call_object_func(struct object_t *);
/* screen.c */
extern void screen_init();
extern void screen_clear_sprites();
extern void screen_clear_sprites(int pos_flag);
extern void screen_add_sprite(int x, int y, int frame);
extern void fade_out_palette();
extern void screen_adjust_palette_color(int color, int b, int c);
extern void screen_vsync();
extern void screen_draw_frame(const uint8_t *frame, int fh, int fw, int x, int y);
extern void screen_flip();
extern void screen_unk5();
extern void screen_do_transition1(int a);
extern void screen_do_transition2();

View File

@ -1162,7 +1162,8 @@ void do_level_enter_door(struct object_t *obj) {
if (g_vars.two_players_flag) {
do_level_update_panel_2nd_player();
}
screen_flip();
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
g_sys.update_screen();
screen_do_transition1(1);
obj->unk3D = 0;
obj->sprite_type = 0;
@ -1224,9 +1225,9 @@ static void do_level_update_input(struct object_t *obj) {
obj->direction_lr |= OBJECT_DIRECTION_LEFT;
}
_si = triggers_get_tile_type(obj->xpos16, obj->ypos16);
if (g_vars.inp_key_up && !g_vars.inp_key_space) {
if ((g_options.jump_button ? g_vars.inp_key_jump : g_vars.inp_key_up) && !g_vars.inp_key_space) {
obj->direction_ud = OBJECT_DIRECTION_UP;
if (!g_vars.inp_key_up_prev && obj->sprite_type != 0) {
if ((g_options.jump_button ? !g_vars.inp_key_jump_prev : !g_vars.inp_key_up_prev) && obj->sprite_type != 0) {
obj->yfriction = 0;
_di = triggers_get_tile_type(obj->xpos16, obj->ypos16 - 2);
if (_di == 10 && (_si == 0 || _si == 1)) {
@ -1255,6 +1256,7 @@ static void do_level_update_input(struct object_t *obj) {
}
g_vars.inp_key_up_prev = g_vars.inp_key_up;
g_vars.inp_key_down_prev = g_vars.inp_key_down;
g_vars.inp_key_jump_prev = g_vars.inp_key_jump;
if (obj->grab_state == 0) {
if (obj->carry_crate_flag != 0 && _si == 5) { // crate
obj->grab_type = 0;
@ -1301,12 +1303,10 @@ static void do_level_update_scrolling(struct object_t *obj) {
if ((g_vars.screen_scrolling_dirmask & 2) != 0 && obj->screen_xpos < TILEMAP_SCREEN_W / 2) {
g_vars.screen_scrolling_dirmask &= ~2;
g_vars.switch_player_scrolling_flag = 0;
g_vars.inp_keyboard[0xC1] = 0;
}
if ((g_vars.screen_scrolling_dirmask & 1) != 0 && obj->screen_xpos > TILEMAP_SCREEN_W / 2) {
g_vars.screen_scrolling_dirmask &= ~1;
g_vars.switch_player_scrolling_flag = 0;
g_vars.inp_keyboard[0xC1] = 0;
}
} else {
int _si = (obj->xvelocity >> 3) + obj->unk1C;
@ -1871,18 +1871,6 @@ static void do_level_update_objects() {
obj->direction_lr = 0;
obj->direction_ud = 0;
if (obj->type < 2) {
if (g_vars.inp_keyboard[0xC1] != 0) { // F7, change player
if (!g_vars.switch_player_scrolling_flag && g_vars.two_players_flag) {
if (!g_vars.player2_scrolling_flag && !g_vars.objects[OBJECT_NUM_PLAYER1].scrolling_lock_flag) {
g_vars.player2_scrolling_flag = 1;
g_vars.switch_player_scrolling_flag = 1;
} else if (g_vars.player2_scrolling_flag && !g_vars.objects[OBJECT_NUM_PLAYER2].scrolling_lock_flag) {
g_vars.player2_scrolling_flag = 1;
g_vars.switch_player_scrolling_flag = 1;
}
}
g_vars.inp_keyboard[0xC1] = 0;
}
if (obj->blinking_counter != 0) {
--obj->blinking_counter;
}
@ -2099,7 +2087,7 @@ void do_level() {
if (g_options.amiga_copper_bars) {
g_sys.set_copper_bars(_copper_data + g_vars.level * 18);
}
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.update_objects_counter = 0;
g_vars.game_over_flag = 0;
@ -2110,25 +2098,9 @@ void do_level() {
g_sys.render_set_sprites_clipping_rect(0, TILEMAP_OFFSET_Y, TILEMAP_SCREEN_W, TILEMAP_SCREEN_H);
bool screen_transition_flag = true;
do {
screen_clear_sprites(0);
const uint32_t timestamp = g_sys.get_timestamp();
update_input();
if (g_vars.inp_keyboard[0xBF] != 0) { // F5, quit game
play_sound(SOUND_0);
g_vars.inp_keyboard[0xBF] = 0;
g_vars.quit_level_flag = 1;
g_vars.play_level_flag = 0;
g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0;
g_vars.objects[OBJECT_NUM_PLAYER2].unk60 = 0;
g_vars.objects[OBJECT_NUM_PLAYER1].data5F = 0;
g_vars.objects[OBJECT_NUM_PLAYER2].data5F = 0;
if (!g_vars.play_demo_flag) {
g_vars.start_level = 0;
}
} else if (g_vars.inp_keyboard[0xC4] != 0) { // F10
play_sound(SOUND_0);
while (g_vars.inp_keyboard[0xC4] != 0 && g_vars.inp_keyboard[0xB] == 0);
while (g_vars.inp_keyboard[0xC4] != 0 && g_vars.inp_keyboard[0xB] != 0);
}
// demo
do_level_update_scrolling2();
do_level_update_objects();
@ -2138,18 +2110,17 @@ void do_level() {
++g_vars.level_loop_counter;
draw_level_panel();
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
if (screen_transition_flag) {
screen_transition_flag = false;
g_sys.update_screen(g_res.vga, 0);
screen_do_transition2();
} else {
g_sys.update_screen(g_res.vga, 1);
g_sys.update_screen();
}
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
const int diff = (timestamp + (1000 / 30)) - g_sys.get_timestamp();
g_sys.sleep(diff < 10 ? 10 : diff);
screen_clear_sprites();
} while (!g_sys.input.quit && !g_vars.quit_level_flag);
// g_vars.screen_draw_offset -= TILEMAP_OFFSET_Y * 40;
@ -2158,5 +2129,4 @@ void do_level() {
g_sys.set_copper_bars(0);
}
g_sys.render_set_sprites_clipping_rect(0, 0, GAME_SCREEN_W, GAME_SCREEN_H);
g_vars.inp_keyboard[0xBF] = 0;
}

View File

@ -314,11 +314,11 @@ void load_img(const char *filename, int screen_w, int dither_pattern) {
size = read_compressed_file(filename, g_res.tmp);
}
assert(size <= 32000);
load_iff(g_res.tmp, size, g_res.vga, screen_w, dither_pattern);
load_iff(g_res.tmp, size, g_res.vga, 320, dither_pattern);
g_sys.copy_bitmap(g_res.vga, 320, 200);
if (dither_pattern < 0) {
g_sys.set_screen_palette(g_res.palette, 0, 16, 8);
}
g_sys.update_screen(g_res.vga, 0);
}
void load_m(const char *filename) {

View File

@ -8,15 +8,19 @@
#define MAX_SPRITESHEET_W 512
#define MAX_SPRITESHEET_H 512
static int _offset_x, _offset_y;
static int _spr_pos_flag;
static int _offset_x_center, _offset_y_bottom, _offset_y_center;
void screen_init() {
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
_offset_x = (GAME_SCREEN_W > 320) ? (GAME_SCREEN_W - 320) / 2 : 0; // center horizontally
_offset_y = (GAME_SCREEN_H > 200) ? (GAME_SCREEN_H - 200) : 0; // align to bottom
_offset_x_center = (GAME_SCREEN_W > 320) ? (GAME_SCREEN_W - 320) / 2 : 0; // center horizontally
_offset_y_center = (GAME_SCREEN_H > 200) ? (GAME_SCREEN_H - 200) / 2 : 0; // center vertically
_offset_y_bottom = (GAME_SCREEN_H > 200) ? (GAME_SCREEN_H - 200) : 0; // align to bottom
}
void screen_clear_sprites() {
void screen_clear_sprites(int pos_flag) {
_spr_pos_flag = pos_flag;
g_sys.render_clear_sprites();
}
@ -32,11 +36,6 @@ static void add_game_sprite(int x, int y, int frame, int xflip) {
if (frame >= SPRITES_COUNT) {
spr_type = RENDER_SPR_LEVEL;
frame -= SPRITES_COUNT;
} else {
if (y >= 161 && frame >= 120) {
x += _offset_x;
y += _offset_y;
}
}
g_sys.render_add_sprite(spr_type, frame, x - w / 2, y - h, xflip);
}
@ -60,6 +59,13 @@ void screen_add_sprite(int x, int y, int frame) {
return;
}
}
if (_spr_pos_flag) { /* introduction screens */
x += _offset_x_center;
y += _offset_y_center;
} else if ((frame >= 120 && frame < SPRITES_COUNT) && y >= 161) { /* bottom panel */
x += _offset_x_center;
y += _offset_y_bottom;
}
add_game_sprite(x, y, frame, 0);
}
@ -82,9 +88,9 @@ void screen_vsync() {
}
void screen_draw_frame(const uint8_t *frame, int fh, int fw, int x, int y) {
x += _offset_x;
x += _offset_x_center;
if (y == 161) {
y += _offset_y;
y += _offset_y_bottom;
}
y += fh + 2;
if (g_options.amiga_status_bar || g_res.amiga_data) {
@ -104,10 +110,6 @@ void screen_draw_frame(const uint8_t *frame, int fh, int fw, int x, int y) {
}
}
void screen_flip() {
g_sys.update_screen(g_res.vga, 1);
}
void screen_unk5() {
// screen_do_transition2();
screen_clear(0);
@ -183,8 +185,8 @@ static void draw_number_amiga(int digit, int x, int y) {
void screen_draw_number(int num, int x, int y, int color) {
if (y >= 161) {
x += _offset_x;
y += _offset_y;
x += _offset_x_center;
y += _offset_y_bottom;
}
y += TILEMAP_OFFSET_Y;
if (g_options.amiga_status_bar || g_res.amiga_data) {

View File

@ -11,7 +11,7 @@
#include <stdbool.h>
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#define SWAP(x, y) do { typeof(x) tmp = x; x = y; y = tmp; } while(0)
#define SWAP(x, y) do { __typeof__(x) tmp = x; x = y; y = tmp; } while(0)
#undef MIN
static inline int MIN(int a, int b) {
@ -51,6 +51,7 @@ struct options_t {
int screen_w;
int screen_h;
bool dos_scrolling;
bool jump_button;
// 'bb' only options
bool amiga_copper_bars;
bool amiga_colors;
@ -62,7 +63,6 @@ struct options_t {
struct game_t {
const char *name;
//int (*detect)(const char *data_path);
void (*run)(const char *data_path);
};

View File

@ -15,6 +15,7 @@ void update_input() {
g_vars.input_key_up = (g_sys.input.direction & INPUT_DIRECTION_UP) != 0 ? 0xFF : 0;
g_vars.input_key_down = (g_sys.input.direction & INPUT_DIRECTION_DOWN) != 0 ? 0xFF : 0;
g_vars.input_key_space = g_sys.input.space ? 0xFF : 0;
g_vars.input_key_jump = g_sys.input.jump ? 0xFF : 0;
g_vars.input_keystate[2] = g_sys.input.digit1;
g_vars.input_keystate[3] = g_sys.input.digit2;
@ -52,7 +53,8 @@ static void scroll_screen_palette() {
for (int i = 0; i < count; ++i) {
g_sys.set_palette_color(225 + i, g_res.tmp + (225 + g_vars.level_time + i) * 3);
}
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, 320, 200);
g_sys.update_screen();
}
static void do_select_screen_scroll_palette(int start, int end, int step, int count) {
@ -66,7 +68,8 @@ static void do_select_screen_scroll_palette(int start, int end, int step, int co
g_vars.palette_buffer[i] = color;
}
g_sys.set_screen_palette(g_vars.palette_buffer + start * 3, start, end - start + 1, 6);
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, 320, 200);
g_sys.update_screen();
g_sys.sleep(20);
} while (--count != 0);
}

View File

@ -129,7 +129,7 @@ struct vars_t {
int player;
bool input_keystate[128];
uint32_t timestamp;
uint8_t input_key_left, input_key_right, input_key_down, input_key_up, input_key_space;
uint8_t input_key_left, input_key_right, input_key_down, input_key_up, input_key_space, input_key_jump;
uint16_t buffer[128 * 2]; /* level objects state 0xFFFF, 0xFF20 or g_vars.objects_table index */
int16_t dragon_coords[1 + 128];
struct player_t players_table[2];

View File

@ -27,7 +27,8 @@ static void do_end_of_level() {
ja_decode_motif(g_vars.level_num % 9, color_index);
static const uint8_t white[] = { 0x3F, 0x3F, 0x3F };
g_sys.set_palette_color(color_index, white);
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
g_sys.update_screen();
g_sys.sleep(1000);
g_sys.fade_out_palette();
}
@ -398,7 +399,7 @@ static void level_update_player_anim_1(struct player_t *player) {
static void level_update_player_anim_5(struct player_t *player) {
level_player_update_hdirection(player);
player->obj.spr_num = 5;
if (player_jump_counter(&player->obj) != 0 && (player_flags2(&player->obj) & 1) == 0 && g_vars.input_key_up) {
if (player_jump_counter(&player->obj) != 0 && (player_flags2(&player->obj) & 1) == 0 && (g_options.jump_button ? g_vars.input_key_jump : g_vars.input_key_up)) {
--player_jump_counter(&player->obj);
const int dy = (int8_t)player_anim_dy[player_jump_counter(&player->obj)] + player_y_delta(&player->obj);
if (dy >= -70) {
@ -550,7 +551,7 @@ static void level_update_player_anim_12(struct player_t *player) {
static void level_update_player_anim_18(struct player_t *player) {
level_player_update_hdirection(player);
player->obj.spr_num = 18;
if (player_jump_counter(&player->obj) != 0 && g_vars.input_key_up) {
if (player_jump_counter(&player->obj) != 0 && (g_options.jump_button ? g_vars.input_key_jump : g_vars.input_key_up)) {
--player_jump_counter(&player->obj);
player_y_delta(&player->obj) += (int8_t)player_anim_dy[player_jump_counter(&player->obj)];
}
@ -594,7 +595,7 @@ static void level_update_player_anim_19(struct player_t *player) {
static void level_update_player_anim_26(struct player_t *player) {
level_player_update_hdirection(player);
player->obj.spr_num = 26;
if (player_jump_counter(&player->obj) == 0 || !g_vars.input_key_up) {
if (player_jump_counter(&player->obj) == 0 || (g_options.jump_button ? !g_vars.input_key_jump : !g_vars.input_key_up)) {
return;
}
--player_jump_counter(&player->obj);
@ -737,7 +738,7 @@ static void level_update_player_from_input(struct player_t *player) {
} else {
mask <<= 4;
if ((player_flags(&player->obj) & 0x10) == 0) {
mask |= (g_vars.input_key_up & 8);
mask |= (g_options.jump_button ? g_vars.input_key_jump : g_vars.input_key_up) & 8;
}
mask |= (g_vars.input_key_right & 4);
if (player_jump_counter(&player->obj) == 7) {
@ -2695,7 +2696,8 @@ static void level_sync() {
--g_vars.level_time;
}
}
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
g_sys.update_screen();
g_sys.render_clear_sprites();
const int diff = (g_vars.timestamp + (1000 / 30)) - g_sys.get_timestamp();
g_sys.sleep(MAX(diff, 10));

View File

@ -46,17 +46,8 @@ void video_copy_vga(int size) {
} else {
assert(size == 0x7D00);
g_sys.set_screen_palette(g_res.tmp, 0, 256, 6);
const uint8_t *src = g_res.tmp + 768;
if (GAME_SCREEN_W * GAME_SCREEN_H == 64000) {
memcpy(g_res.vga, src, 64000);
} else {
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
for (int y = 0; y < MIN(200, GAME_SCREEN_H); ++y) {
memcpy(g_res.vga + y * GAME_SCREEN_W, src, MIN(320, GAME_SCREEN_W));
src += 320;
}
}
g_sys.update_screen(g_res.vga, 0);
memcpy(g_res.vga, g_res.tmp + 768, 64000);
g_sys.copy_bitmap(g_res.vga, 320, 200);
}
}

View File

@ -1,5 +1,5 @@
/* uncompress data packed with DIET by T.Matsumoto */
/* uncompress data packed with DIET.EXE */
#include "unpack.h"
#include "util.h"

63
main.c
View File

@ -28,43 +28,40 @@ static const char *USAGE =
;
static struct game_t *detect_game(const char *data_path) {
#if 0
extern struct game_t bb_game;
extern struct game_t ja_game;
extern struct game_t p2_game;
static struct game_t *games[] = {
&bb_game,
&ja_game,
&p2_game,
0
};
for (int i = 0; games[i]; ++i) {
if (games[i]->detect(data_path)) {
return games[i];
}
}
return 0;
#else
extern struct game_t game;
return &game;
#endif
}
#if defined(PSP)
/* stubs */
void sound_init() {
}
void sound_fini() {
}
void play_sound(int num) {
}
void play_music(int num) {
}
#endif
int main(int argc, char *argv[]) {
g_options.start_xpos16 = -1;
g_options.start_ypos16 = -1;
g_options.screen_w = 320;
g_options.screen_h = 200;
g_options.dos_scrolling = false;
g_options.amiga_copper_bars = true;
g_options.amiga_colors = true;
// g_options.amiga_status_bar = true;
g_options.cga_colors = false;
g_options.hybrid_color = false;
const char *data_path = DEFAULT_DATA_PATH;
int scale_factor = DEFAULT_SCALE_FACTOR;
const char *scale_filter = DEFAULT_SCALE_FILTER;
bool fullscreen = false;
g_options.start_xpos16 = -1;
g_options.start_ypos16 = -1;
g_options.amiga_copper_bars = true;
g_options.amiga_colors = true;
// g_options.amiga_status_bar = true;
#if defined(PSP)
g_options.screen_w = 480;
g_options.screen_h = 272;
g_options.jump_button = true;
#else
g_options.screen_w = 320;
g_options.screen_h = 200;
// g_options.jump_button = true;
if (argc == 2) {
struct stat st;
if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) {
@ -121,7 +118,14 @@ int main(int argc, char *argv[]) {
if (sscanf(optarg, "%dx%d", &g_options.screen_w, &g_options.screen_h) == 2) {
// align to tile 16x16
g_options.screen_w = (g_options.screen_w + 15) & ~15;
g_options.screen_h = ((g_options.screen_h + 15) & ~15) + 40; // PANEL_H
g_options.screen_h = ((g_options.screen_h + 15) & ~15) + 40; // PANEL_H;
// do not allow lower resolution than the original
if (g_options.screen_w < 320) {
g_options.screen_w = 320;
}
if (g_options.screen_h < 200) {
g_options.screen_h = 200;
}
}
break;
case 10:
@ -138,6 +142,7 @@ int main(int argc, char *argv[]) {
return -1;
}
}
#endif
struct game_t *game = detect_game(data_path);
if (!game) {
fprintf(stdout, "No data files found\n");

View File

@ -15,6 +15,7 @@ void update_input() {
g_vars.input.key_up = (g_sys.input.direction & INPUT_DIRECTION_UP) != 0 ? 0xFF : 0;
g_vars.input.key_down = (g_sys.input.direction & INPUT_DIRECTION_DOWN) != 0 ? 0xFF : 0;
g_vars.input.key_space = g_sys.input.space ? 0xFF : 0;
g_vars.input.key_jump = g_sys.input.jump ? 0xFF : 0;
g_vars.input.keystate[2] = g_sys.input.digit1;
g_vars.input.keystate[3] = g_sys.input.digit2;
@ -51,7 +52,8 @@ static void do_programmed_in_1992_screen() {
video_draw_string(offset, 1, "PROGRAMMED IN 1992 ON AT >286 12MHZ>");
offset += 0x1E0;
video_draw_string(offset, 3, "> > > ENJOY OLDIES<<");
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, 320, 200);
g_sys.update_screen();
wait_input(100);
video_clear();
}
@ -76,23 +78,14 @@ static void do_credits() {
video_draw_string(offset, 2, "CRISTELLE> GIL ESPECHE AND CORINNE>");
offset += 0x1E0;
video_draw_string(offset, 0, "SEBASTIEN BECHET AND OLIVIER AKA DELTA>");
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, 320, 200);
g_sys.update_screen();
}
static void update_screen_img(const uint8_t *src, int present) {
const int size = GAME_SCREEN_W * GAME_SCREEN_H;
if (size < 64000) {
return;
} else if (size == 64000) {
g_sys.update_screen(src, present);
} else {
memset(g_res.vga, 0, size);
const int y_offs = (GAME_SCREEN_H - 200) / 2;
const int x_offs = (GAME_SCREEN_W - 320) / 2;
for (int y = 0; y < 200; ++y) {
memcpy(g_res.vga + (y_offs + y) * GAME_SCREEN_W + x_offs, src + y * 320, 320);
}
g_sys.update_screen(g_res.vga, present);
g_sys.copy_bitmap(src, 320, 200);
if (present) {
g_sys.update_screen();
}
}
@ -190,8 +183,8 @@ void do_gameover_screen() {
if (data) {
video_copy_img(data);
video_copy_background();
g_sys.update_screen(g_res.vga, 0);
g_sys.set_screen_palette(gameover_palette_data, 0, 16, 6);
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
do_gameover_animation();
g_sys.fade_out_palette();
free(data);
@ -205,8 +198,8 @@ static void do_menu2() {
if (data) {
video_copy_img(data);
video_copy_background();
g_sys.update_screen(g_res.vga, 0);
g_sys.set_screen_palette(data + 32000, 0, 16, 6);
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
g_sys.fade_in_palette();
do_demo_animation();
g_sys.fade_out_palette();

View File

@ -120,7 +120,7 @@ struct vars_t {
} random;
struct {
bool keystate[128];
uint8_t key_left, key_right, key_down, key_up, key_space;
uint8_t key_left, key_right, key_down, key_up, key_space, key_jump;
uint8_t key_vdir, key_hdir;
uint16_t demo_offset;
uint8_t demo_mask, demo_counter;

View File

@ -2446,7 +2446,7 @@ static void level_update_player() {
mask <<= 1;
mask |= g_vars.input.key_left & 1;
mask <<= 1;
mask |= g_vars.input.key_up & 1;
mask |= (g_options.jump_button ? g_vars.input.key_jump : g_vars.input.key_up) & 1;
mask <<= 1;
mask |= g_vars.input.key_down & 1;
mask <<= 1;
@ -2664,7 +2664,7 @@ static void level_update_player_collision() {
level_add_object75_score(obj_player, (int16_t)data[num >> 1]);
}
}
g_vars.objects_tbl[1].data.p.y_velocity = (g_vars.input.key_up != 0) ? -224 : -64;
g_vars.objects_tbl[1].data.p.y_velocity = (g_options.jump_button ? g_vars.input.key_jump : g_vars.input.key_up) ? -224 : -64;
g_vars.player_jumping_counter = 0;
g_vars.objects_tbl[1].y_pos -= g_vars.monster.collide_y_dist;
} else if (g_vars.objects_tbl[1].data.p.y_velocity <= 32) {
@ -3269,7 +3269,8 @@ static void level_update_light_palette() {
static void level_sync() {
update_input();
g_sys.update_screen(g_res.vga, 1);
g_sys.copy_bitmap(g_res.vga, GAME_SCREEN_W, GAME_SCREEN_H);
g_sys.update_screen();
g_sys.render_clear_sprites();
const int diff = (g_vars.timestamp + (1000 / 30)) - g_sys.get_timestamp();
g_sys.sleep(MAX(diff, 10));

View File

@ -61,9 +61,7 @@ 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;
uint8_t *dst = g_res.vga + offset * 8;
while (*s) {
uint8_t code = *s++;
if (code != 0x20) {
@ -71,7 +69,7 @@ void video_draw_string(int offset, int hspace, const char *s) {
if (code > 9) {
code -= 2;
}
decode_planar(g_res.allfonts + code * 48, dst, GAME_SCREEN_W, 8, 12, 0);
decode_planar(g_res.allfonts + code * 48, dst, 320, 8, 12, 0);
}
dst += 8;
}

8
sys.h
View File

@ -14,11 +14,13 @@
#define RENDER_SPR_GAME 0 /* player sprites */
#define RENDER_SPR_LEVEL 1 /* level sprites */
#define RENDER_SPR_FG 2 /* foreground tiles */
#define RENDER_SPR_COUNT 3
struct input_t {
uint8_t direction;
bool quit;
bool space;
bool jump;
bool digit1, digit2, digit3;
};
@ -36,7 +38,7 @@ enum sys_transition_e {
struct sys_t {
struct input_t input;
int (*init)();
void (*init)();
void (*fini)();
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 offset, int count, int depth);
@ -45,7 +47,8 @@ struct sys_t {
void (*set_palette_color)(int i, const uint8_t *colors);
void (*fade_in_palette)();
void (*fade_out_palette)();
void (*update_screen)(const uint8_t *p, int present);
void (*copy_bitmap)(const uint8_t *p, int w, int h);
void (*update_screen)();
void (*shake_screen)(int dx, int dy);
void (*transition_screen)(enum sys_transition_e type, bool open);
void (*process_events)();
@ -60,6 +63,7 @@ struct sys_t {
void (*render_add_sprite)(int spr_type, int frame, int x, int y, int xflip);
void (*render_clear_sprites)();
void (*render_set_sprites_clipping_rect)(int x, int y, int w, int h);
void (*print_log)(FILE *fp, const char *s);
};
extern struct sys_t g_sys;

428
sys_psp.c Normal file
View File

@ -0,0 +1,428 @@
#include <pspaudio.h>
#include <pspaudiolib.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspkernel.h>
#include <pspsdk.h>
#include <malloc.h>
#include "sys.h"
PSP_MODULE_INFO("Blues Brothers", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
static uint32_t _buttons;
static sys_audio_cb _audio_proc;
static void *_audio_param;
static int _audio_channel;
static SceUID _audio_mutex;
static uint32_t _fb_offset;
// static const int AUDIO_FREQ = 44100;
static const int AUDIO_SAMPLES_COUNT = 2048;
static const int SCREEN_W = 480;
static const int SCREEN_H = 272;
static const int SCREEN_PITCH = 512;
static uint32_t __attribute__((aligned(16))) _dlist[262144];
static uint32_t __attribute__((aligned(16))) _clut[256];
#define MAX_SPRITES 256
struct vertex_t {
int16_t u, v;
int16_t x, y, z;
};
struct spritetexture_t {
int w, h;
uint8_t *bitmap;
int count;
struct sys_rect_t *r;
};
static struct spritetexture_t _spritetextures[RENDER_SPR_COUNT];
struct sprite_t {
struct vertex_t v[2];
int tex;
};
static struct sprite_t _sprites[MAX_SPRITES];
static int _sprites_count;
static void print_log(FILE *fp, const char *s) {
static bool first_open = false;
if (!first_open) {
fp = fopen("stdout.txt", "w");
first_open = true;
} else {
fp = fopen("stdout.txt", "a");
}
fprintf(fp, "%s\n", s);
fclose(fp);
}
static int exit_callback(int arg1, int arg2, void *common) {
g_sys.input.quit = true;
return 0;
}
static int callback_thread(SceSize args, void *argp) {
const int cb = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cb);
sceKernelSleepThreadCB();
return 0;
}
static void psp_init() {
_buttons = 0;
memset(&_audio_proc, 0, sizeof(_audio_proc));
_audio_channel = -1;
_audio_mutex = 0;
const int th = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, 0);
if (th >= 0) {
sceKernelStartThread(th, 0, 0);
}
sceKernelDcacheWritebackAll();
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
}
static void psp_fini() {
sceGuTerm();
sceKernelExitGame();
}
static void psp_set_screen_size(int w, int h, const char *caption, int scale, const char *filter, bool fullscreen) {
sceGuInit();
sceGuStart(GU_DIRECT, _dlist);
const int fbSize = SCREEN_PITCH * SCREEN_H * sizeof(uint32_t); // rgba
uint32_t vramOffset = 0;
sceGuDrawBuffer(GU_PSM_8888, (void *)vramOffset, SCREEN_PITCH); vramOffset += fbSize;
sceGuDispBuffer(SCREEN_W, SCREEN_H, (void *)vramOffset, SCREEN_PITCH); vramOffset += fbSize;
sceGuOffset(2048 - (SCREEN_W / 2), 2048 - (SCREEN_H / 2));
sceGuViewport(2048, 2048, SCREEN_W, SCREEN_H);
sceGuScissor(0, 0, SCREEN_W, SCREEN_H);
sceGuEnable(GU_SCISSOR_TEST);
sceGuEnable(GU_TEXTURE_2D);
sceGuDisable(GU_DEPTH_TEST);
sceGuClearColor(0);
sceGuClear(GU_COLOR_BUFFER_BIT);
sceGuFinish();
sceGuSync(GU_SYNC_WHAT_DONE, GU_SYNC_FINISH);
sceDisplayWaitVblankStart();
_fb_offset = (uint32_t)sceGuSwapBuffers();
sceGuDisplay(GU_TRUE);
for (int i = 0; i < 256; ++i) {
_clut[i] = GU_RGBA(0, 0, 0, 255);
}
sceKernelDcacheWritebackRange(_clut, sizeof(_clut));
}
static void psp_set_screen_palette(const uint8_t *colors, int offset, int count, int depth) {
const int shift = 8 - depth;
for (int i = 0; i < count; ++i) {
int r = *colors++;
int g = *colors++;
int b = *colors++;
if (shift != 0) {
r = (r << shift) | (r >> (depth - shift));
g = (g << shift) | (g >> (depth - shift));
b = (b << shift) | (b >> (depth - shift));
}
_clut[offset + i] = GU_RGBA(r, g, b, 255);
}
sceKernelDcacheWritebackRange(_clut, sizeof(_clut));
}
static uint32_t convert_amiga_color(uint16_t color) {
uint8_t r = (color >> 8) & 15;
r |= r << 4;
uint8_t g = (color >> 4) & 15;
g |= g << 4;
uint8_t b = color & 15;
b |= b << 4;
return GU_RGBA(r, g, b, 255);
}
static void psp_set_palette_amiga(const uint16_t *colors, int offset) {
for (int i = 0; i < 16; ++i) {
_clut[offset + i] = convert_amiga_color(colors[i]);
}
sceKernelDcacheWritebackRange(_clut, sizeof(_clut));
}
static void psp_set_copper_bars(const uint16_t *data) {
}
static void psp_set_palette_color(int i, const uint8_t *colors) {
_clut[i] = GU_RGBA(colors[0], colors[1], colors[2], 255);
sceKernelDcacheWritebackRange(_clut, sizeof(_clut));
}
static void psp_fade_in_palette() {
sceDisplayWaitVblankStart();
_fb_offset = (uint32_t)sceGuSwapBuffers();
}
static void psp_fade_out_palette() {
uint32_t *buffer = (uint32_t *)(((uint8_t *)sceGeEdramGetAddr()) + _fb_offset);
for (int y = 0; y < SCREEN_H; ++y) {
memset(buffer, 0, SCREEN_W * sizeof(uint32_t));
buffer += SCREEN_PITCH;
}
}
static void psp_transition_screen(enum sys_transition_e type, bool open) {
}
static void psp_copy_bitmap(const uint8_t *p, int w, int h) {
const int dx = (SCREEN_W - w) / 2;
const int dy = (SCREEN_H - h) / 2;
uint32_t *buffer = (uint32_t *)(((uint8_t *)sceGeEdramGetAddr()) + _fb_offset);
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
buffer[(dy + y) * SCREEN_PITCH + (dx + x)] = _clut[*p++];
}
}
}
static void psp_update_screen() {
sceGuStart(GU_DIRECT, _dlist);
sceGuClutMode(GU_PSM_8888, 0, 0xFF, 0);
sceGuClutLoad(256 / 8, _clut);
sceGuTexMode(GU_PSM_T8, 0, 0, 0);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_NEAREST, GU_NEAREST);
sceGuEnable(GU_COLOR_TEST);
sceGuColorFunc(GU_NOTEQUAL, _clut[0], 0xFFFFFF);
int prev_tex = -1;
for (int i = 0; i < _sprites_count; ++i) {
struct sprite_t *spr = &_sprites[i];
if (prev_tex != spr->tex) {
struct spritetexture_t *st = &_spritetextures[spr->tex];
sceGuTexImage(0, st->w, st->h, st->w, st->bitmap);
prev_tex = spr->tex;
}
struct vertex_t *v = (struct vertex_t *)sceGuGetMemory(2 * sizeof(struct vertex_t));
v[0] = spr->v[0];
v[1] = spr->v[1];
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_16BIT | GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, v);
}
sceGuDisable(GU_COLOR_TEST);
sceGuFinish();
sceGuSync(GU_SYNC_WHAT_DONE, GU_SYNC_FINISH);
sceDisplayWaitVblankStart();
_fb_offset = (uint32_t)sceGuSwapBuffers();
}
static void psp_shake_screen(int dx, int dy) {
sceGuOffset(2048 - (SCREEN_W / 2) + dx, 2048 - (SCREEN_H / 2) + dy);
}
static void psp_process_events() {
g_sys.input.direction = 0;
static const struct {
int psp;
int sys;
} mapping[] = {
{ PSP_CTRL_UP, INPUT_DIRECTION_UP },
{ PSP_CTRL_RIGHT, INPUT_DIRECTION_RIGHT },
{ PSP_CTRL_DOWN, INPUT_DIRECTION_DOWN },
{ PSP_CTRL_LEFT, INPUT_DIRECTION_LEFT },
{ 0, 0 }
};
SceCtrlData data;
sceCtrlPeekBufferPositive(&data, 1);
for (int i = 0; mapping[i].psp != 0; ++i) {
if (data.Buttons & mapping[i].psp) {
g_sys.input.direction |= mapping[i].sys;
}
}
static const int lxMargin = 64;
if (data.Lx < 127 - lxMargin) {
g_sys.input.direction |= INPUT_DIRECTION_LEFT;
} else if (data.Lx > 127 + lxMargin) {
g_sys.input.direction |= INPUT_DIRECTION_RIGHT;
}
static const int lyMargin = 64;
if (data.Ly < 127 - lyMargin) {
g_sys.input.direction |= INPUT_DIRECTION_UP;
} else if (data.Ly > 127 + lyMargin) {
g_sys.input.direction |= INPUT_DIRECTION_DOWN;
}
// PSP_CTRL_CROSS
g_sys.input.space = (data.Buttons & PSP_CTRL_SQUARE) != 0;
g_sys.input.jump = (data.Buttons & PSP_CTRL_CIRCLE) != 0;
// PSP_CTRL_TRIANGLE
const uint32_t mask = data.Buttons ^ _buttons;
if ((data.Buttons & PSP_CTRL_LTRIGGER) & mask) {
}
if ((data.Buttons & PSP_CTRL_RTRIGGER) & mask) {
}
_buttons = data.Buttons;
}
static void psp_sleep(int duration) {
sceKernelDelayThread(duration * 1000);
}
static uint32_t psp_get_timestamp() {
struct timeval tv;
sceKernelLibcGettimeofday(&tv, 0);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static void psp_lock_audio() {
sceKernelWaitSema(_audio_mutex, 1, 0);
}
static void psp_unlock_audio() {
sceKernelSignalSema(_audio_mutex, 1);
}
static void audio_callback(void *buf, unsigned int samples, void *param) { // 44100hz S16 stereo
int16_t buf22khz[samples];
memset(buf22khz, 0, sizeof(buf22khz));
psp_lock_audio();
_audio_proc(_audio_param, (uint8_t *)buf22khz, samples);
psp_unlock_audio();
uint32_t *buf44khz = (uint32_t *)buf;
static int16_t prev;
for (unsigned int i = 0; i < samples; ++i) {
const int16_t current = buf22khz[i];
buf44khz[i] = (current << 16) | (((prev + current) >> 1) & 0xFFFF);
prev = current;
}
}
static void psp_start_audio(sys_audio_cb callback, void *param) {
// sceAudioSetFrequency(AUDIO_FREQ);
pspAudioInit();
_audio_proc = callback;
_audio_param = param;
_audio_mutex = sceKernelCreateSema("audio_lock", 0, 1, 1, 0);
_audio_channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, AUDIO_SAMPLES_COUNT, PSP_AUDIO_FORMAT_STEREO);
pspAudioSetChannelCallback(_audio_channel, audio_callback, 0);
}
static void psp_stop_audio() {
sceAudioChRelease(_audio_channel);
sceKernelDeleteSema(_audio_mutex);
pspAudioEnd();
}
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) {
struct spritetexture_t *st = &_spritetextures[spr_type];
st->r = (struct sys_rect_t *)malloc(count * sizeof(struct sys_rect_t));
if (st->r) {
memcpy(st->r, r, count * sizeof(struct sys_rect_t));
st->count = count;
}
st->bitmap = (uint8_t *)memalign(16, w * h);
if (st->bitmap) {
memcpy(st->bitmap, data, w * h);
st->w = w;
st->h = h;
sceKernelDcacheWritebackRange(st->bitmap, w * h);
}
}
static void render_unload_sprites(int spr_type) {
struct spritetexture_t *st = &_spritetextures[spr_type];
if (st->r) {
free(st->r);
}
if (st->bitmap) {
free(st->bitmap);
}
memset(st, 0, sizeof(struct spritetexture_t));
}
static void render_add_sprite(int spr_type, int frame, int x, int y, int xflip) {
if (_sprites_count < MAX_SPRITES) {
struct sprite_t *spr = &_sprites[_sprites_count];
struct vertex_t *v = spr->v;
struct sys_rect_t *r = &_spritetextures[spr_type].r[frame];
if (!xflip) {
v[0].u = r->x; v[1].u = r->x + r->w;
} else {
v[0].u = r->x + r->w; v[1].u = r->x;
}
v[0].v = r->y; v[1].v = r->y + r->h;
v[0].x = x; v[1].x = x + r->w;
v[0].y = y; v[1].y = y + r->h;
v[0].z = 0; v[1].z = 0;
spr->tex = spr_type;
++_sprites_count;
}
}
static void render_clear_sprites() {
_sprites_count = 0;
}
static void render_set_sprites_clipping_rect(int x, int y, int w, int h) {
sceGuScissor(x, y, w, h);
}
struct sys_t g_sys = {
.init = psp_init,
.fini = psp_fini,
.set_screen_size = psp_set_screen_size,
.set_screen_palette = psp_set_screen_palette,
.set_palette_amiga = psp_set_palette_amiga,
.set_copper_bars = psp_set_copper_bars,
.set_palette_color = psp_set_palette_color,
.fade_in_palette = psp_fade_in_palette,
.fade_out_palette = psp_fade_out_palette,
.copy_bitmap = psp_copy_bitmap,
.update_screen = psp_update_screen,
.shake_screen = psp_shake_screen,
.transition_screen = psp_transition_screen,
.process_events = psp_process_events,
.sleep = psp_sleep,
.get_timestamp = psp_get_timestamp,
.start_audio = psp_start_audio,
.stop_audio = psp_stop_audio,
.lock_audio = psp_lock_audio,
.unlock_audio = psp_unlock_audio,
.render_load_sprites = render_load_sprites,
.render_unload_sprites = render_unload_sprites,
.render_add_sprite = render_add_sprite,
.render_clear_sprites = render_clear_sprites,
.render_set_sprites_clipping_rect = render_set_sprites_clipping_rect,
.print_log = print_log,
};

View File

@ -5,7 +5,6 @@
#define COPPER_BARS_H 80
#define MAX_SPRITES 256
#define MAX_SPRITESHEETS 3
static const int FADE_STEPS = 16;
@ -16,7 +15,7 @@ struct spritesheet_t {
SDL_Texture *texture;
};
static struct spritesheet_t _spritesheets[MAX_SPRITESHEETS];
static struct spritesheet_t _spritesheets[RENDER_SPR_COUNT];
struct sprite_t {
int sheet;
@ -44,7 +43,7 @@ static uint32_t _copper_palette[COPPER_BARS_H];
static SDL_GameController *_controller;
static SDL_Joystick *_joystick;
static int sdl2_init() {
static void 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;
@ -72,7 +71,6 @@ static int sdl2_init() {
}
}
}
return 0;
}
static void sdl2_fini() {
@ -188,9 +186,9 @@ static void sdl2_set_screen_palette(const uint8_t *colors, int offset, int count
SDL_Color *palette_colors = &_palette->colors[offset];
const int shift = 8 - depth;
for (int i = 0; i < count; ++i) {
int r = colors[0];
int g = colors[1];
int b = colors[2];
int r = *colors++;
int g = *colors++;
int b = *colors++;
if (depth != 8) {
r = (r << shift) | (r >> (depth - shift));
g = (g << shift) | (g >> (depth - shift));
@ -200,7 +198,6 @@ static void sdl2_set_screen_palette(const uint8_t *colors, int offset, int count
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];
@ -286,11 +283,21 @@ static void sdl2_transition_screen(enum sys_transition_e type, bool open) {
} while (r.x > 0 && (type == TRANSITION_CURTAIN || r.y > 0));
}
static void sdl2_update_screen(const uint8_t *p, int present) {
if (_copper_color_key != -1) {
static void sdl2_copy_bitmap(const uint8_t *p, int w, int h) {
if (w != _screen_w || h != _screen_h) {
memset(_screen_buffer, 0, _screen_w * _screen_h * sizeof(uint32_t));
const int offset_x = (_screen_w - w) / 2;
const int offset_y = (_screen_h - h) / 2;
for (int j = 0; j < h; ++j) {
for (int i = 0; i < w; ++i) {
_screen_buffer[(offset_y + j) * _screen_w + (offset_x + i)] = _screen_palette[*p++];
}
}
} else 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];
const int color = (j * 200 / _screen_h) / 2;
if (color < COPPER_BARS_H) {
const uint32_t line_color = _copper_palette[color];
for (int i = 0; i < _screen_w; ++i) {
_screen_buffer[j * _screen_w + i] = (p[i] == _copper_color_key) ? line_color : _screen_palette[p[i]];
}
@ -307,38 +314,39 @@ static void sdl2_update_screen(const uint8_t *p, int present) {
}
}
SDL_UpdateTexture(_texture, 0, _screen_buffer, _screen_w * sizeof(uint32_t));
if (present) {
SDL_Rect r;
r.x = _shake_dx;
r.y = _shake_dy;
r.w = _screen_w;
r.h = _screen_h;
SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, _texture, 0, &r);
}
// sprites
SDL_RenderSetClipRect(_renderer, &_sprites_cliprect);
for (int i = 0; i < _sprites_count; ++i) {
const struct sprite_t *spr = &_sprites[i];
struct spritesheet_t *sheet = &_spritesheets[spr->sheet];
if (spr->num >= sheet->count) {
continue;
}
SDL_Rect r;
r.x = spr->x + _shake_dx;
r.y = spr->y + _shake_dy;
r.w = sheet->r[spr->num].w;
r.h = sheet->r[spr->num].h;
if (!spr->xflip) {
SDL_RenderCopy(_renderer, sheet->texture, &sheet->r[spr->num], &r);
} else {
SDL_RenderCopyEx(_renderer, sheet->texture, &sheet->r[spr->num], &r, 0., 0, SDL_FLIP_HORIZONTAL);
}
static void sdl2_update_screen() {
SDL_Rect r;
r.x = _shake_dx;
r.y = _shake_dy;
r.w = _screen_w;
r.h = _screen_h;
SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, _texture, 0, &r);
// sprites
SDL_RenderSetClipRect(_renderer, &_sprites_cliprect);
for (int i = 0; i < _sprites_count; ++i) {
const struct sprite_t *spr = &_sprites[i];
struct spritesheet_t *sheet = &_spritesheets[spr->sheet];
if (spr->num >= sheet->count) {
continue;
}
SDL_Rect r;
r.x = spr->x + _shake_dx;
r.y = spr->y + _shake_dy;
r.w = sheet->r[spr->num].w;
r.h = sheet->r[spr->num].h;
if (!spr->xflip) {
SDL_RenderCopy(_renderer, sheet->texture, &sheet->r[spr->num], &r);
} else {
SDL_RenderCopyEx(_renderer, sheet->texture, &sheet->r[spr->num], &r, 0., 0, SDL_FLIP_HORIZONTAL);
}
SDL_RenderSetClipRect(_renderer, 0);
SDL_RenderPresent(_renderer);
}
SDL_RenderSetClipRect(_renderer, 0);
SDL_RenderPresent(_renderer);
}
static void sdl2_shake_screen(int dx, int dy) {
@ -380,6 +388,10 @@ static void handle_keyevent(int keysym, bool keydown, struct input_t *input, boo
case SDLK_SPACE:
input->space = keydown;
break;
case SDLK_LSHIFT:
case SDLK_RSHIFT:
input->jump = keydown;
break;
case SDLK_ESCAPE:
if (keydown) {
g_sys.input.quit = true;
@ -437,13 +449,10 @@ static void handle_controlleraxis(int axis, int value, struct input_t *input) {
static void handle_controllerbutton(int button, bool pressed, struct input_t *input, bool *paused) {
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:
g_sys.input.quit = true;
case SDL_CONTROLLER_BUTTON_B:
input->jump = pressed;
break;
case SDL_CONTROLLER_BUTTON_START:
if (!pressed) {
@ -520,8 +529,13 @@ static void handle_joystickaxismotion(int axis, int value, struct input_t *input
}
static void handle_joystickbutton(int button, int pressed, struct input_t *input) {
if (button == 0) {
switch (button) {
case 0:
input->space = pressed;
break;
case 1:
input->jump = pressed;
break;
}
}
@ -717,6 +731,9 @@ static void render_set_sprites_clipping_rect(int x, int y, int w, int h) {
_sprites_cliprect.h = h;
}
static void print_log(FILE *fp, const char *s) {
}
struct sys_t g_sys = {
.init = sdl2_init,
.fini = sdl2_fini,
@ -727,6 +744,7 @@ struct sys_t g_sys = {
.set_palette_color = sdl2_set_palette_color,
.fade_in_palette = sdl2_fade_in_palette,
.fade_out_palette = sdl2_fade_out_palette,
.copy_bitmap = sdl2_copy_bitmap,
.update_screen = sdl2_update_screen,
.shake_screen = sdl2_shake_screen,
.transition_screen = sdl2_transition_screen,
@ -741,5 +759,6 @@ struct sys_t g_sys = {
.render_unload_sprites = render_unload_sprites,
.render_add_sprite = render_add_sprite,
.render_clear_sprites = render_clear_sprites,
.render_set_sprites_clipping_rect = render_set_sprites_clipping_rect
.render_set_sprites_clipping_rect = render_set_sprites_clipping_rect,
.print_log = print_log,
};

8
util.c
View File

@ -1,6 +1,8 @@
#include <stdarg.h>
#include <sys/param.h>
#include <sys/unistd.h>
#include "sys.h"
#include "util.h"
int g_debug_mask = 0;
@ -21,6 +23,7 @@ void string_upper(char *p) {
}
}
#ifndef NDEBUG
void print_debug(int debug_channel, const char *msg, ...) {
if (g_debug_mask & debug_channel) {
char buf[256];
@ -29,8 +32,10 @@ void print_debug(int debug_channel, const char *msg, ...) {
vsprintf(buf, msg, va);
va_end(va);
fprintf(stdout, "%s\n", buf);
g_sys.print_log(stdout, buf);
}
}
#endif
void print_warning(const char *msg, ...) {
char buf[256];
@ -39,6 +44,7 @@ void print_warning(const char *msg, ...) {
vsprintf(buf, msg, va);
va_end(va);
fprintf(stderr, "WARNING: %s\n", buf);
g_sys.print_log(stderr, buf);
}
void print_error(const char *msg, ...) {
@ -48,6 +54,7 @@ void print_error(const char *msg, ...) {
vsprintf(buf, msg, va);
va_end(va);
fprintf(stderr, "ERROR: %s!\n", buf);
g_sys.print_log(stderr, buf);
exit(-1);
}
@ -58,6 +65,7 @@ void print_info(const char *msg, ...) {
vsprintf(buf, msg, va);
va_end(va);
fprintf(stdout, "%s\n", buf);
g_sys.print_log(stdout, buf);
}
FILE *fopen_nocase(const char *path, const char *filename) {

4
util.h
View File

@ -22,6 +22,10 @@ extern void print_warning(const char *msg, ...);
extern void print_error(const char *msg, ...);
extern void print_info(const char *msg, ...);
#ifdef NDEBUG
#define print_debug(x, ...)
#endif
extern FILE * fopen_nocase(const char *path, const char *filename);
extern uint16_t fread_le16(FILE *fp);