#include "game_graphics.h" #include #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_CONTENT_SIZE 544 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 15, 22, 5, 18, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 77, 0, 77, 86, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 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, 0, 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, }; // 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 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); // 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 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!!! for(uint16_t tile = 0; tile < sizeof(box_content_win); tile++) { if(!content[tile]) continue; uint8_t x = tile % (SCREEN_WIDTH_B - (ENDGAME_BOX_X_OFFSET * 2) - 4); uint8_t y = tile / (SCREEN_WIDTH_B - (ENDGAME_BOX_X_OFFSET * 2) - 4); uint8_t invert = content[tile] & 0x80; uint8_t ch_num = content[tile] & 0x7F; for(uint8_t row = 0; row < CHAR_HEIGHT; row++) { uint16_t offset = line_offset_map[ENDGAME_BOX_Y_OFFSET + (2 * CHAR_HEIGHT) + (y * CHAR_HEIGHT) + row] + ENDGAME_BOX_X_OFFSET + 2 + x; front_buf[offset] = invert ? ((~CHARSET[(ch_num * CHAR_HEIGHT) + row]) & 0x7F) : CHARSET[(ch_num * CHAR_HEIGHT) + row]; } } // TODO: Add additional info to the box, if necessary } // 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; } } }