TK2048/src/game_graphics.c
2025-08-20 12:23:52 +02:00

405 lines
19 KiB
C

#include "game_graphics.h"
#include <string.h>
#include "utility.h"
#include "mem_map.h"
#include "mem_registers.h"
#include "line_data.h"
#include "game_logic.h"
#include "tiles.h"
#include "charset.h"
#include "monitor_subroutines.h"
#include "graph_misc_data.h"
#include "arrows_pic.h"
#define SCREEN_WIDTH 280
#define SCREEN_HEIGHT 192
#define SCREEN_WIDTH_B 40
#define GRID_CELL_SIDE 35
#define TOP_OFFSET 7
#define LEFT_OFFSET_B 1 // Left is offset by 1 bytes (7 pixels)
static uint8_t *front_buf;
static uint8_t *back_buf;
#define BOX_WIDTH 32
#define BOX_HEIGHT 17
#define BOX_CONTENT_SIZE (BOX_WIDTH * BOX_HEIGHT)
static const uint8_t box_content_win[BOX_CONTENT_SIZE] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 77, 0, 77, 0, 83, 77, 84, 0, 77, 0, 77, 0, 0, 77, 0, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 0, 0,
0, 0, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 84, 77, 0, 0, 0, 0,
0, 0, 0, 0,212, 77,211, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 0, 0,
0, 0, 0, 0, 0, 77, 0, 0,212, 77,211, 0,212, 77,211, 0, 0,212,211, 0,212,211, 0, 77, 0, 77, 0, 77, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 25, 15, 21, 18, 0, 19, 3, 15, 18, 5, 0, 9, 19, 58, 0, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 16, 21, 19, 8, 0, 1, 14, 25, 0, 11, 5, 25, 0, 20, 15, 0, 3, 15, 14, 20, 9, 14, 21, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const uint8_t box_content_lose[BOX_CONTENT_SIZE] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 13, 5, 0, 0, 15, 22, 5, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 77, 0, 77, 0, 83, 77, 84, 0, 77, 0, 77, 0, 0, 77, 0, 0, 0, 83, 77, 84, 0, 83, 77,192, 0, 77, 77, 77, 0, 0,
0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 77, 0, 0, 0, 77, 0, 77, 0,212, 77, 84, 0, 77, 0, 0, 0, 0,
0, 0,212, 77,211, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 77, 0, 0, 0, 77, 0, 77, 0, 0,203, 77, 0, 77,193, 0, 0, 0,
0, 0, 0, 77, 0, 0,212, 77,211, 0,212, 77,211, 0, 0,212, 77, 77, 0,212, 77,211, 0, 77, 77,211, 0, 77, 77, 77, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 25, 15, 21, 18, 0, 19, 3, 15, 18, 5, 0, 9, 19, 58, 0, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 16, 21, 19, 8, 0, 1, 14, 25, 0, 11, 5, 25, 0, 20, 15, 0, 3, 15, 14, 20, 9, 14, 21, 5, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const uint8_t box_content_start[BOX_CONTENT_SIZE] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 16, 21, 19, 8, 0, 1, 14, 25, 0, 11, 5, 25, 0, 20, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 83, 77,192, 0, 77, 77, 77, 0, 83, 77, 84, 0, 77, 77, 84, 0, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,212, 77, 84, 0, 0, 77, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,203, 77, 0, 0, 77, 0, 0, 77,192, 77, 0, 77, 77,211, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 77, 77,211, 0, 0, 77, 0, 0, 77, 0, 77, 0, 77,198, 84, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const uint8_t box_new_hi_score[BOX_WIDTH] = {
0, 0,102, 0, 23, 5, 0, 7, 15, 20, 0, 1, 0, 14, 5, 23, 0, 8, 9, 7, 8, 45, 19, 3, 15, 18, 5, 33, 0,102, 0, 0
};
#define INSTR_BOX_WIDTH 12
#define INSTR_BOX_HEIGHT 8
#define INSTR_BOX_SIZE (INSTR_BOX_HEIGHT * INSTR_BOX_WIDTH)
#define INSTR_BOX_X 28
#define INSTR_BOX_Y 127
static const uint8_t instruction_box[INSTR_BOX_SIZE] = {
3, 21, 18, 19, 15, 18, 0, 0, 11, 5, 25, 19,
19, 12, 9, 4, 5, 0, 0, 20, 9, 12, 5, 19,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 17, 21, 1, 12, 19, 0, 13, 5, 18, 7, 5,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
18, 5, 1, 3, 8, 0, 0, 50, 48, 52, 56, 33,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79, 0, 50, 48, 50, 53, 0, 49, 46, 48, 0, 79
};
// The grid is 5x5 squares,
// It is offset on the left side by 7 pixels and on the top by 14
// Every square is 35x35 pixels
void draw_field_borders_on_buffer(uint8_t brd, uint8_t* buf);
void draw_picture(uint8_t w, uint8_t h, uint8_t x, uint8_t y, const uint8_t *data, uint8_t *dest);
void direct_draw_number(uint16_t n, uint8_t len, uint8_t x, uint8_t y, uint8_t *disp_buf);
void draw_graph_char_box(uint8_t x_offset, uint8_t y_offset, uint8_t width, uint8_t height, uint8_t const *data, uint8_t* buf);
void ddraw_field_borders_on_buffer(uint8_t brd) {
draw_field_borders_on_buffer(brd, front_buf);
}
#define HIGH_TEXT_X 32
#define HIGH_TEXT_Y 107
#define HIGH_TEXT_WIDTH 5
void draw_game_background(uint16_t hi_score) {
// Draw the background on display page 1
uint8_t* buf = (uint8_t*)DISPLAY_PAGE_1;
// Draw the borders
draw_field_borders_on_buffer(0x0F, buf);
// Draw required pics
draw_picture(SCORE_PIC_WIDTH_BYTES, SCORE_PIC_HEIGHT, 31, 14, score_pic_data, buf);
draw_picture(MOVES_PIC_WIDTH_BYTES, MOVES_PIC_HEIGHT, 31, 45, moves_pic_data, buf);
draw_picture(HIGH_PIC_WIDTH_BYTES, HIGH_PIC_HEIGHT, 31, 76, high_pic_data, buf);
draw_picture(SCORE_PIC_WIDTH_BYTES, SCORE_PIC_HEIGHT, 31, 90, score_pic_data, buf);
// Draw the high-score. This won't change at every turn, so makes sense to just draw once
direct_draw_number(hi_score, HIGH_TEXT_WIDTH, HIGH_TEXT_X, HIGH_TEXT_Y, front_buf);
// Draw instruction box
draw_graph_char_box(INSTR_BOX_X, INSTR_BOX_Y, INSTR_BOX_WIDTH, INSTR_BOX_HEIGHT, instruction_box, front_buf);
// Copy the data from display page 1 to 2
memcpy((void*)DISPLAY_PAGE_2, (void*)DISPLAY_PAGE_1, DISPLAY_PAGE_SIZE);
}
// This will draw directly to the front buffer
void ddraw_single_tile(uint8_t offset) {
uint8_t* grid = get_front_grid();
if(!grid[offset]) return; // The tile is not there, nothing to do
const uint8_t *tile_data = tiles + (TILE_WIDTH_BYTES * TILE_HEIGHT * (grid[offset] - 1));
uint8_t col = offset % GRID_SIDE;
uint8_t row = offset / GRID_SIDE;
uint8_t delay = 0xFF;
for(uint8_t h = 0; h < TILE_HEIGHT; h++) {
memcpy(front_buf + line_offset_map[TOP_OFFSET + 7 + (row * GRID_CELL_SIDE) + h] + LEFT_OFFSET_B + 1 + (col * GRID_CELL_SIDE/7),
tile_data + (TILE_WIDTH_BYTES * h), TILE_WIDTH_BYTES);
WAIT(48);
}
}
void direct_draw_number(uint16_t n, uint8_t len, uint8_t x, uint8_t y, uint8_t *disp_buf) {
uint8_t buf[len];
// Decode the number into the buffer
num_to_decbuf(n, len, buf);
for(uint8_t row = 0; row < CHAR_HEIGHT; row++) {
uint16_t offset = line_offset_map[y + row];
for(uint8_t col = 0; col < len; col++) {
disp_buf[(offset + (len - 1) - col) + x] = CHARSET[NUM_OFFSET + (buf[col] * CHAR_HEIGHT) + row];
}
}
}
void draw_number(uint16_t n, uint8_t len, uint8_t x, uint8_t y) {
direct_draw_number(n, len, x, y, back_buf);
}
void draw_tiles(void) {
uint8_t* grid = get_front_grid();
// Clear the grid so we'll be able to draw the boxes on
clear_box(GRID_SIDE * (GRID_CELL_SIDE/7) + 1, (GRID_SIDE * GRID_CELL_SIDE) + 4, LEFT_OFFSET_B, TOP_OFFSET + 1, back_buf);
for (uint8_t tile = 0; tile < GRID_SIDE * GRID_SIDE; tile++) {
if(grid[tile]) {
const uint8_t *tile_data = tiles + (TILE_WIDTH_BYTES * TILE_HEIGHT * (grid[tile] - 1));
uint8_t col = tile % GRID_SIDE;
uint8_t row = tile / GRID_SIDE;
draw_picture(TILE_WIDTH_BYTES, TILE_HEIGHT, LEFT_OFFSET_B + 1 + (col * GRID_CELL_SIDE/7), TOP_OFFSET + 7 + (row * GRID_CELL_SIDE), tile_data, back_buf);
}
}
// Re-draw the borders, to restore the correct width
draw_field_borders_on_buffer(0x0F, back_buf);
}
#define ENDGAME_BOX_X_OFFSET 2
#define ENDGAME_BOX_Y_OFFSET 16
#define ENDGAME_BOX_SCORE_LEN 5
void ddraw_endgame_box(int8_t done, uint16_t score, uint16_t hi_score) {
// Clear the part of the screen where we'll draw
clear_box((SCREEN_WIDTH_B - (ENDGAME_BOX_X_OFFSET * 2)) + 1, (SCREEN_HEIGHT - (ENDGAME_BOX_Y_OFFSET * 2)) + CHAR_HEIGHT, ENDGAME_BOX_X_OFFSET, ENDGAME_BOX_Y_OFFSET, front_buf);
// Horizontal lines
for(uint8_t row = 0; row < CHAR_HEIGHT; row++) {
uint16_t offset_top = line_offset_map[ENDGAME_BOX_Y_OFFSET + CHAR_HEIGHT + row] + ENDGAME_BOX_X_OFFSET + 1;
uint16_t offset_bottom = line_offset_map[SCREEN_HEIGHT - ENDGAME_BOX_Y_OFFSET - CHAR_HEIGHT + row] + ENDGAME_BOX_X_OFFSET + 1;
for(uint8_t col = 0; col < SCREEN_WIDTH_B - ((ENDGAME_BOX_X_OFFSET * 2) + 2); col++) {
front_buf[offset_top + col] = CHARSET[GRAPH_OFFSET + (12 * CHAR_HEIGHT) + row];
front_buf[offset_bottom + col] = CHARSET[GRAPH_OFFSET + (12 * CHAR_HEIGHT) + row];
}
}
// Corners
for(uint8_t row = 0; row < CHAR_HEIGHT; row++) {
uint16_t offset_top = line_offset_map[ENDGAME_BOX_Y_OFFSET + CHAR_HEIGHT + row] + ENDGAME_BOX_X_OFFSET + 1;
uint16_t offset_bottom = line_offset_map[SCREEN_HEIGHT - ENDGAME_BOX_Y_OFFSET - CHAR_HEIGHT + row] + ENDGAME_BOX_X_OFFSET + 1;
front_buf[offset_top] = CHARSET[GRAPH_OFFSET + (25 * CHAR_HEIGHT) + row];
front_buf[offset_bottom] = CHARSET[GRAPH_OFFSET + (27 * CHAR_HEIGHT) + row];
front_buf[offset_top + (SCREEN_WIDTH_B - ((ENDGAME_BOX_X_OFFSET * 2) + 2))] = CHARSET[GRAPH_OFFSET + (26 * CHAR_HEIGHT) + row];
front_buf[offset_bottom + (SCREEN_WIDTH_B - ((ENDGAME_BOX_X_OFFSET * 2) + 2))] = CHARSET[GRAPH_OFFSET + (28 * CHAR_HEIGHT) + row];
}
// Vertical lines
for(uint8_t row = 0; row < ((SCREEN_HEIGHT - (ENDGAME_BOX_Y_OFFSET * 3) - CHAR_HEIGHT)) + 1; row++) {
uint16_t offset = line_offset_map[ENDGAME_BOX_Y_OFFSET + (CHAR_HEIGHT * 2) + row] + ENDGAME_BOX_X_OFFSET + 1;
front_buf[offset] = CHARSET[GRAPH_OFFSET + (19 * CHAR_HEIGHT) + (row % CHAR_HEIGHT)];
front_buf[offset + (SCREEN_WIDTH_B - ((ENDGAME_BOX_X_OFFSET * 2) + 2))] = CHARSET[GRAPH_OFFSET + (19 * CHAR_HEIGHT) + (row % CHAR_HEIGHT)];
}
uint8_t const *content;
// Decide which type of content to show
if(done == 0) content = box_content_start;
else if (done > 0) content = box_content_win;
else content = box_content_lose;
// And now, the content!!!
draw_graph_char_box(ENDGAME_BOX_X_OFFSET + 2, (ENDGAME_BOX_Y_OFFSET + (2 * CHAR_HEIGHT)), BOX_WIDTH, BOX_HEIGHT, content, front_buf);
if(done != 0) { // Print the score
direct_draw_number(score, ENDGAME_BOX_SCORE_LEN, ENDGAME_BOX_X_OFFSET + 23, ENDGAME_BOX_Y_OFFSET + (11 * CHAR_HEIGHT), front_buf);
if(score > hi_score) {
draw_graph_char_box(ENDGAME_BOX_X_OFFSET + 2, (ENDGAME_BOX_Y_OFFSET + (2 * CHAR_HEIGHT) + (13 * CHAR_HEIGHT)), BOX_WIDTH, 1, box_new_hi_score, front_buf);
}
}
}
void draw_graph_char_box(uint8_t x_offset, uint8_t y_offset, uint8_t width, uint8_t height, uint8_t const *data, uint8_t* buf) {
// Draw box
for(uint16_t tile = 0; tile < width * height; tile++) {
if(!data[tile]) continue;
uint8_t x = tile % width;
uint8_t y = tile / width;
uint8_t invert = data[tile] & 0x80;
uint8_t ch_num = data[tile] & 0x7F;
for(uint8_t row = 0; row < CHAR_HEIGHT; row++) {
uint16_t offset = line_offset_map[y_offset + (y * CHAR_HEIGHT) + row] + x_offset + x;
buf[offset] = invert ? ((~CHARSET[(ch_num * CHAR_HEIGHT) + row]) & 0x7F) : CHARSET[(ch_num * CHAR_HEIGHT) + row];
}
}
}
// Note that the horizontal values here are in group of 7 pixels
void clear_box(uint8_t w, uint8_t h, uint8_t off_x, uint8_t off_y, uint8_t *disp_buf) {
for(uint8_t y = off_y; y < off_y + h; y++) {
uint16_t line_counter = line_offset_map[y];
for(uint8_t x = off_x; x < off_x + w; x++) {
disp_buf[line_counter + x] = 0;
}
}
}
void swap_display_buffers(void) {
uint8_t *temp = front_buf;
front_buf = back_buf;
back_buf = temp;
// Show the current buffer
PEEK(((uint16_t)front_buf == DISPLAY_PAGE_1) ? IO_DISPLAY_PAGE1 : IO_DISPLAY_PAGE2);
}
void clear_display_buffers(void) {
// Clear the buffers
memset((void*)DISPLAY_PAGE_1, 0, DISPLAY_PAGE_SIZE);
memset((void*)DISPLAY_PAGE_2, 0, DISPLAY_PAGE_SIZE);
PEEK(IO_DISPLAY_PAGE1); // Select the first display page
// Restore the buffer ordering
front_buf = (uint8_t*)DISPLAY_PAGE_1;
back_buf = (uint8_t*)DISPLAY_PAGE_2;
}
void draw_field_borders_on_buffer(uint8_t brd, uint8_t* buf) {
// Horizontal borders
for(uint8_t col = 0; col < (GRID_SIDE * (GRID_CELL_SIDE/7)) + 1; col++) {
buf[line_offset_map[TOP_OFFSET - 1] + col + LEFT_OFFSET_B] = BRD_SKIP_UP(brd) ? 0x00: 0x7F;
buf[line_offset_map[TOP_OFFSET - 0] + col + LEFT_OFFSET_B] = BRD_DOUBLING_UP(brd) && !BRD_SKIP_UP(brd) ? 0x7F : 0x00;
buf[line_offset_map[TOP_OFFSET + (GRID_CELL_SIDE * GRID_SIDE) + 7] + col + LEFT_OFFSET_B] = BRD_SKIP_DOWN(brd) ? 0x00: 0x7F;
buf[line_offset_map[TOP_OFFSET + (GRID_CELL_SIDE * GRID_SIDE) + 6] + col + LEFT_OFFSET_B] = BRD_DOUBLING_DOWN(brd) && !BRD_SKIP_DOWN(brd) ? 0x7F : 0x00;
}
// Vertical borders
for(uint8_t row = 0; row < (GRID_CELL_SIDE * GRID_SIDE) + 7; row++) {
buf[line_offset_map[row + TOP_OFFSET] + LEFT_OFFSET_B - 1] = BRD_SKIP_LEFT(brd) ? 0x00 : (BRD_DOUBLING_LEFT(brd) ? 0x60 : 0x40);
buf[line_offset_map[row + TOP_OFFSET] + LEFT_OFFSET_B + (GRID_SIDE * (GRID_CELL_SIDE/7)) + 1] = BRD_SKIP_RIGHT(brd) ? 0x00 : (BRD_DOUBLING_RIGHT(brd) ? 0x03 : 0x01);
}
}
void draw_picture(uint8_t w, uint8_t h, uint8_t x, uint8_t y, const uint8_t *data, uint8_t *dest) {
for(uint8_t row = 0; row < h; row++) {
memcpy(dest + line_offset_map[row + y] + x, data + (w * row), w);
}
}
void ddraw_direction_arrows(arrow_direction dir) {
uint8_t pic_buffer[ARROWS_HEIGHT];
int8_t start, step, end, flip;
uint8_t ext, x, y;
switch(dir) {
case ARROW_UP:
x = 2;
y = TOP_OFFSET + 1;
ext = 1;
start = 1;
step = 1;
end = ARROWS_HEIGHT;
flip = 0;
break;
case ARROW_DOWN:
x = 2;
y = TOP_OFFSET + (GRID_SIDE * GRID_CELL_SIDE);
ext = 1;
start = ARROWS_HEIGHT - 1;
step = -1;
end = 0;
flip = 0;
break;
case ARROW_LEFT:
x = 1;
y = TOP_OFFSET + 7;
ext = 0;
start = ARROWS_HEIGHT;
step = 1;
end = (ARROWS_HEIGHT * 2);
flip = 0;
break;
case ARROW_RIGHT:
x = 1 + (GRID_SIDE * (GRID_CELL_SIDE/7));
y = TOP_OFFSET + 7;
ext = 0;
start = ARROWS_HEIGHT;
step = 1;
end = (ARROWS_HEIGHT * 2);
flip = 1;
break;
default:
return;
}
uint8_t tot_arrows = (GRID_SIDE * (GRID_CELL_SIDE/7)) - 1;
if(ext) { // Horizontal lines
uint8_t s_start = x;
for(uint8_t cur_arrow = 0; cur_arrow < tot_arrows; cur_arrow++) {
for(int8_t s = start, row = 0; s != end; s += step, row++) {
front_buf[line_offset_map[y + row] + s_start] = arrows_pic[s];
}
s_start++;
}
} else {
uint8_t s_start = y;
for(uint8_t cur_arrow = 0; cur_arrow < tot_arrows; cur_arrow++) {
for(int8_t s = start, row = 0; s != end; s += step, row++) {
front_buf[line_offset_map[s_start + row] + x] = flip ? (bit_reverse(arrows_pic[s]) >> 1) : arrows_pic[s];
}
s_start += ARROWS_HEIGHT;
}
}
}