blues/bb/screen.c

337 lines
9.7 KiB
C
Raw Permalink Normal View History

2018-07-08 16:08:53 +02:00
#include "decode.h"
#include "game.h"
#include "resource.h"
#include "sys.h"
#include "util.h"
2018-07-16 14:43:34 +02:00
#define MAX_SPRITESHEET_W 512
#define MAX_SPRITESHEET_H 512
2018-07-12 13:21:15 +02:00
2022-03-12 23:41:23 +01:00
static int _spr_pos_flag;
static int _offset_x_center, _offset_y_bottom, _offset_y_center;
2018-07-27 16:02:05 +02:00
2018-07-08 16:08:53 +02:00
void screen_init() {
2018-07-22 15:28:05 +02:00
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
2022-03-12 23:41:23 +01:00
_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
2018-07-08 16:08:53 +02:00
}
2022-03-12 23:41:23 +01:00
void screen_clear_sprites(int pos_flag) {
_spr_pos_flag = pos_flag;
2018-12-16 15:28:52 +01:00
g_sys.render_clear_sprites();
2018-07-12 13:21:15 +02:00
}
static void add_game_sprite(int x, int y, int frame, int xflip) {
const uint8_t *p = g_res.spr_frames[frame];
2018-12-16 15:28:52 +01:00
if (!p) {
print_warning("add_game_sprite missing frame %d", frame);
return;
}
2018-07-12 13:21:15 +02:00
const int h = READ_LE_UINT16(p - 4);
const int w = READ_LE_UINT16(p - 2);
int spr_type = RENDER_SPR_GAME;
if (frame >= SPRITES_COUNT) {
spr_type = RENDER_SPR_LEVEL;
frame -= SPRITES_COUNT;
}
2018-12-16 15:28:52 +01:00
g_sys.render_add_sprite(spr_type, frame, x - w / 2, y - h, xflip);
2018-07-08 16:08:53 +02:00
}
void screen_add_sprite(int x, int y, int frame) {
2019-05-29 02:07:54 +02:00
if (g_res.amiga_data) {
switch (frame) {
case 125: {
extern const uint8_t spr71a6_amiga[];
static const int w = 16;
static const int h = 6;
decode_amiga_gfx(g_res.vga + (y - h) * GAME_SCREEN_W + (x - w / 2), GAME_SCREEN_W, w, h, 4, spr71a6_amiga, w, 0x0, 0xFFFF);
}
return;
case 126: {
extern const uint8_t spr71da_amiga[];
static const int w = 48;
static const int h = 34;
decode_amiga_gfx(g_res.vga + (y - h) * GAME_SCREEN_W + (x - w / 2), GAME_SCREEN_W, w, h, 4, spr71da_amiga, w, 0x0, 0xFFFF);
}
return;
}
}
2022-03-12 23:41:23 +01:00
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;
}
2018-07-12 13:21:15 +02:00
add_game_sprite(x, y, frame, 0);
2018-07-08 16:08:53 +02:00
}
void screen_redraw_sprites() {
}
void fade_out_palette() {
// g_sys.fade_out_palette();
}
void screen_adjust_palette_color(int color, int b, int c) {
2018-08-12 15:44:16 +02:00
if (!g_options.cga_colors) {
g_res.palette[color * 3 + b] += c;
screen_vsync();
2018-12-16 13:34:03 +01:00
g_sys.set_screen_palette(g_res.palette, 0, 16, 8);
2018-08-12 15:44:16 +02:00
}
2018-07-08 16:08:53 +02:00
}
void screen_vsync() {
}
2018-07-22 15:28:05 +02:00
void screen_draw_frame(const uint8_t *frame, int fh, int fw, int x, int y) {
2022-03-12 23:41:23 +01:00
x += _offset_x_center;
2018-07-27 16:02:05 +02:00
if (y == 161) {
2022-03-12 23:41:23 +01:00
y += _offset_y_bottom;
2018-07-22 15:28:05 +02:00
}
y += fh + 2;
2018-08-12 14:27:20 +02:00
if (g_options.amiga_status_bar || g_res.amiga_data) {
2018-07-20 15:51:02 +02:00
if (frame == g_res.spr_frames[123] || frame == g_res.spr_frames[124]) { // top or bottom status bar
for (int x = 0; x < GAME_SCREEN_W; x += 16) {
decode_amiga_gfx(g_res.vga + y * GAME_SCREEN_W + x, GAME_SCREEN_W, 16, 12, 4, frame, 16, 0x20, 0xFFFF);
}
} else {
decode_amiga_gfx(g_res.vga + y * GAME_SCREEN_W + x, GAME_SCREEN_W, 16, 12, 4, frame, 16, 0x20, 0xFFFF);
}
} else {
const int h = READ_LE_UINT16(frame - 4);
2018-07-22 15:28:05 +02:00
assert(fh <= h);
2018-07-20 15:51:02 +02:00
const int w = READ_LE_UINT16(frame - 2);
2018-07-22 15:28:05 +02:00
assert(fw <= w);
decode_spr(frame, w, fw, h, 4, g_res.vga, GAME_SCREEN_W, x, y, false);
2018-07-20 15:51:02 +02:00
}
2018-07-08 16:08:53 +02:00
}
void screen_unk5() {
// screen_do_transition2();
2018-08-12 14:27:20 +02:00
screen_clear(0);
2018-07-08 16:08:53 +02:00
}
void screen_do_transition1(int a) {
2018-12-16 13:34:03 +01:00
// print_warning("screen_do_transition1 %d", a);
2018-08-12 14:27:20 +02:00
if (a) {
g_sys.transition_screen(TRANSITION_CURTAIN, true);
2018-07-08 16:08:53 +02:00
}
}
2018-07-22 15:28:05 +02:00
void screen_do_transition2() {
2018-12-16 13:34:03 +01:00
// print_warning("screen_do_transition2");
2018-08-12 14:27:20 +02:00
g_sys.transition_screen(TRANSITION_SQUARE, true);
2018-07-22 15:28:05 +02:00
}
2018-07-08 16:08:53 +02:00
void screen_clear(int a) {
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
}
2018-08-12 14:27:20 +02:00
void screen_draw_tile(int tile, int type, int x, int y) {
2018-07-08 16:08:53 +02:00
const uint8_t *src = g_res.tiles + tile * 16;
2018-08-12 15:44:16 +02:00
if (type != 0) {
2018-07-08 16:08:53 +02:00
src += 320;
}
2018-08-12 14:27:20 +02:00
x = g_vars.screen_tilemap_xoffset + x * 16;
int tile_w = 16;
if (x < 0) {
tile_w += x;
src -= x;
x = 0;
}
if (x + tile_w > TILEMAP_SCREEN_W) {
tile_w = TILEMAP_SCREEN_W - x;
}
if (tile_w <= 0) {
return;
}
y = g_vars.screen_tilemap_yoffset + y * 16;
int tile_h = 16;
if (y < 0) {
tile_h += y;
src -= y * 640;
y = 0;
}
if (y + tile_h > TILEMAP_SCREEN_H) {
tile_h = TILEMAP_SCREEN_H - y;
}
if (tile_h <= 0) {
return;
}
for (int i = 0; i < tile_h; ++i) {
memcpy(g_res.vga + (TILEMAP_OFFSET_Y + y + i) * GAME_SCREEN_W + x, src, tile_w);
2018-07-08 16:08:53 +02:00
src += 640;
}
}
2018-07-20 15:51:02 +02:00
static void draw_number_amiga(int digit, int x, int y) {
extern const uint8_t icon7086[]; // 01
extern const uint8_t icon70ea[]; // 23
extern const uint8_t icon714e[]; // 45
extern const uint8_t icon71b2[]; // 67
extern const uint8_t icon7216[]; // 89
static const uint8_t *icons[] = { icon7086, icon70ea, icon714e, icon71b2, icon7216 };
uint16_t mask = 0xFF00;
if (digit & 1) {
x -= 8;
mask >>= 8;
}
decode_amiga_gfx(g_res.vga + y * GAME_SCREEN_W + x, GAME_SCREEN_W, 16, 12, 4, icons[digit >> 1], 16, 0x20, mask);
}
2018-07-08 16:08:53 +02:00
void screen_draw_number(int num, int x, int y, int color) {
2018-07-27 16:02:05 +02:00
if (y >= 161) {
2022-03-12 23:41:23 +01:00
x += _offset_x_center;
y += _offset_y_bottom;
2018-07-27 16:02:05 +02:00
}
2018-07-08 16:08:53 +02:00
y += TILEMAP_OFFSET_Y;
2018-08-12 14:27:20 +02:00
if (g_options.amiga_status_bar || g_res.amiga_data) {
2018-07-20 15:51:02 +02:00
draw_number_amiga(num / 10, x - 8, y - 2);
draw_number_amiga(num % 10, x, y - 2);
} else {
extern const uint8_t font_data[];
decode_spr(font_data + (num / 10) * 32, 8, 8, 8, 4, g_res.vga, GAME_SCREEN_W, x - 8, y, false);
decode_spr(font_data + (num % 10) * 32, 8, 8, 8, 4, g_res.vga, GAME_SCREEN_W, x, y, false);
}
2018-07-08 16:08:53 +02:00
}
void screen_add_game_sprite1(int x, int y, int frame) {
2018-07-12 13:21:15 +02:00
add_game_sprite(x, y + TILEMAP_OFFSET_Y, frame, 0);
2018-07-08 16:08:53 +02:00
}
void screen_add_game_sprite2(int x, int y, int frame) {
2018-07-12 13:21:15 +02:00
add_game_sprite(x, y + TILEMAP_OFFSET_Y, frame, 1);
2018-07-08 16:08:53 +02:00
}
void screen_add_game_sprite3(int x, int y, int frame, int blinking_counter) {
2018-07-12 13:21:15 +02:00
// print_warning("screen_add_game_sprite3");
2018-07-08 16:08:53 +02:00
}
void screen_add_game_sprite4(int x, int y, int frame, int blinking_counter) {
2018-07-12 13:21:15 +02:00
// print_warning("screen_add_game_sprite4");
}
2018-08-12 16:55:27 +02:00
static void dither_graphics(uint8_t *dst, int dst_pitch, int w, int h, const uint8_t *dither_lut, uint8_t color_key) {
for (int y = 0; y < h; ++y) {
const uint8_t *p = dither_lut + (y & 1) * 0x10;
for (int x = 0; x < w; ++x) {
const uint8_t color = dst[x];
if (color == 0) {
dst[x] = color_key;
} else {
2018-12-16 13:34:03 +01:00
dst[x] = p[color];
2018-08-12 16:55:27 +02:00
}
}
dst += dst_pitch;
}
}
static void decode_graphics(int spr_type, int start, int end, const uint8_t *dither_lut) {
2018-07-12 13:21:15 +02:00
struct sys_rect_t r[MAX_SPR_FRAMES];
uint8_t *data = (uint8_t *)calloc(MAX_SPRITESHEET_W * MAX_SPRITESHEET_H, 1);
if (data) {
2018-08-12 16:55:27 +02:00
const uint8_t color_key = dither_lut ? 0x20 : 0;
2018-08-12 14:27:20 +02:00
const int depth = g_res.amiga_data && (start == 0) ? 3 : 4;
2018-07-12 13:21:15 +02:00
int current_x = 0;
int max_w = 0;
int current_y = 0;
int max_h = 0;
for (int i = start; i < end; ++i) {
const uint8_t *ptr = g_res.spr_frames[i];
2018-07-13 14:34:11 +02:00
if (!ptr) {
memset(&r[i], 0, sizeof(struct sys_rect_t));
continue;
}
2018-07-12 13:21:15 +02:00
const int h = READ_LE_UINT16(ptr - 4);
const int w = READ_LE_UINT16(ptr - 2);
if (current_x + w > MAX_SPRITESHEET_W) {
current_y += max_h;
if (current_x > max_w) {
max_w = current_x;
}
current_x = 0;
max_h = h;
} else {
if (h > max_h) {
max_h = h;
}
}
2018-08-12 14:27:20 +02:00
decode_spr(ptr, w, w, h, depth, data, MAX_SPRITESHEET_W, current_x, current_y, g_res.amiga_data);
2018-08-12 16:55:27 +02:00
if (dither_lut) {
dither_graphics(data + current_y * MAX_SPRITESHEET_W + current_x, MAX_SPRITESHEET_W, w, h, dither_lut, color_key);
}
2018-12-16 13:34:03 +01:00
const int j = i - start;
2018-07-16 14:43:34 +02:00
r[j].x = current_x;
r[j].y = current_y;
2018-07-12 13:21:15 +02:00
r[j].w = w;
r[j].h = h;
2018-07-16 14:43:34 +02:00
current_x += w;
if (h > max_h) {
max_h = h;
}
2018-07-12 13:21:15 +02:00
}
2021-12-19 01:09:02 +01:00
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;
}
}
}
2018-07-12 13:21:15 +02:00
assert(max_w <= MAX_SPRITESHEET_W);
assert(current_y + max_h <= MAX_SPRITESHEET_H);
2018-12-16 15:28:52 +01:00
g_sys.render_unload_sprites(spr_type);
2021-12-19 01:09:02 +01:00
g_sys.render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h, color_key, false);
2018-07-12 13:21:15 +02:00
free(data);
}
}
2018-08-12 16:55:27 +02:00
void screen_load_graphics(const uint8_t *dither_lut_sqv, const uint8_t *dither_lut_avt) {
2018-07-12 13:21:15 +02:00
if (g_res.spr_count <= SPRITES_COUNT) {
2018-08-12 16:55:27 +02:00
decode_graphics(RENDER_SPR_GAME, 0, g_res.spr_count, dither_lut_sqv);
2018-07-12 13:21:15 +02:00
} else {
2018-08-12 16:55:27 +02:00
decode_graphics(RENDER_SPR_LEVEL, SPRITES_COUNT, g_res.spr_count, dither_lut_sqv);
2018-07-13 14:34:11 +02:00
// foreground tiles
2018-08-12 16:55:27 +02:00
const uint8_t color_key = dither_lut_avt ? 0x20 : 0;
2018-07-12 13:21:15 +02:00
struct sys_rect_t r[MAX_SPR_FRAMES];
static const int FG_TILE_W = 16;
static const int FG_TILE_H = 16;
uint8_t *data = (uint8_t *)malloc(g_res.avt_count * FG_TILE_W * FG_TILE_H);
if (data) {
const int pitch = g_res.avt_count * FG_TILE_W;
for (int i = 0; i < g_res.avt_count; ++i) {
2018-07-20 15:51:02 +02:00
decode_spr(g_res.avt[i], FG_TILE_W, FG_TILE_W, FG_TILE_H, 4, data, pitch, i * FG_TILE_W, 0, false);
2018-07-12 13:21:15 +02:00
r[i].x = i * FG_TILE_W;
r[i].y = 0;
r[i].w = FG_TILE_W;
r[i].h = FG_TILE_H;
}
2018-08-12 16:55:27 +02:00
if (dither_lut_avt) {
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);
}
2018-12-16 15:28:52 +01:00
g_sys.render_unload_sprites(RENDER_SPR_FG);
2021-12-19 01:09:02 +01:00
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);
2018-07-12 13:21:15 +02:00
free(data);
}
2018-07-13 14:34:11 +02:00
// background tiles (Amiga) - re-arrange to match DOS .ck1/.ck2 layout
2018-08-12 14:27:20 +02:00
if (g_res.amiga_data) {
2018-07-13 14:34:11 +02:00
static const int BG_TILES_COUNT = 256;
static const int W = 320 / 16;
2018-08-12 16:55:27 +02:00
memcpy(g_res.vga, g_res.tiles, BG_TILES_COUNT * 16 * 8);
2018-07-13 14:34:11 +02:00
for (int i = 0; i < 128; ++i) {
const int y = (i / W);
const int x = (i % W);
2018-08-12 16:55:27 +02:00
decode_amiga_blk(g_res.vga + i * 16 * 8, g_res.tiles + (y * 640 + x) * 16, 640);
2018-07-13 14:34:11 +02:00
}
for (int i = 128; i < 256; ++i) {
const int y = ((i - 128) / W);
const int x = ((i - 128) % W) + W;
2018-08-12 16:55:27 +02:00
decode_amiga_blk(g_res.vga + i * 16 * 8, g_res.tiles + (y * 640 + x) * 16, 640);
2018-07-13 14:34:11 +02:00
}
}
2018-07-12 13:21:15 +02:00
}
2018-07-08 16:08:53 +02:00
}