From 34fd24b01fb79533d041250b92d5c2c1129bd069 Mon Sep 17 00:00:00 2001 From: Quinn Date: Mon, 20 Jan 2025 00:27:01 +0100 Subject: [PATCH] implement setting coloured shapes --- src/game/game.c | 33 +++++++++++++++++++++++++++------ src/game/game.h | 37 ++++++++++++------------------------- src/game/shapes.h | 36 ++++++++++++++++++++++++++++++++++++ src/window/renderer.c | 29 ++++++++++------------------- src/window/renderer.h | 2 +- 5 files changed, 86 insertions(+), 51 deletions(-) create mode 100644 src/game/shapes.h diff --git a/src/game/game.c b/src/game/game.c index a9b07f8..d9701a1 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -1,22 +1,43 @@ #include "game.h" +#include + #include "../main.h" +#include "../window/renderer.h" +#include "shapes.h" -static void add_shape(const Shape shape, Uint16* row) { - for (int i = 0; i < 4; i++) { - Uint8 rowData = (shape >> (4 * i)) & 0x0F; +static void _add_shape(Row* row, const Shape shape, const uint8_t colour, const uint8_t pos_x) { + for (uint8_t y = 0; y < SHAPE_HEIGHT; y++) { + ShapeRow shape_row = shape_get_row(shape, y); - if (rowData != 0) - row[4 - i] |= rowData; + if (shape_row == 0) + continue; + + for (uint8_t x = 0; x < SHAPE_WIDTH; x++) + if (is_set(shape_row, x)) + row[y].columns[x + pos_x].block = colour; } } +static inline void add_shape(Row* row, const Shape shape, const uint8_t colour, const uint8_t pos_x, const uint8_t pos_y) { + _add_shape(&row[pos_y], shape, colour, pos_x); +} + // called every time the game's state is updated void game_update(GameData* game_data, const Uint8* keys) { if (keys[SDL_SCANCODE_ESCAPE]) { stop(); } - add_shape(TETROMINO_I, &game_data->row[4]); + add_shape(game_data->row, TETROMINO_I, CYAN, 1, 0); + add_shape(game_data->row, TETROMINO_O, YELLOW, 5, 4); + + add_shape(game_data->row, TETROMINO_Z, GREEN, 1, 8); + add_shape(game_data->row, TETROMINO_S, RED, 5, 8); + + add_shape(game_data->row, TETROMINO_J, BLUE, 1, 12); + add_shape(game_data->row, TETROMINO_L, YELLOW | RED, 5, 12); + + add_shape(game_data->row, TETROMINO_T, MAGENTA, 5, 16); } diff --git a/src/game/game.h b/src/game/game.h index 1a5e7f9..8e903ef 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -1,33 +1,20 @@ #pragma once #include -typedef uint16_t Shape; -typedef uint16_t Row; - -// 0 1 2 3 -#define TETROMINO_I ((Shape)0b1000100010001000) // 1000 1000 1000 1000 the I tetromino with no rotation -#define TETROMINO_I_90 ((Shape)0b0000000000001111) // 0000 0000 0000 1111 the I tetromino with a no rotation -#define TETROMINO_O ((Shape)0b1100110000000000) // 1100 1100 0000 0000 the O tetromino with no rotation -#define TETROMINO_T ((Shape)0b1110010000000000) // 1110 0100 0000 0000 the T tetromino with no rotation -#define TETROMINO_T_90 ((Shape)0b1100110010000000) // 1100 1100 1000 0000 the T tetromino with a no rotation -#define TETROMINO_T_180 ((Shape)0b0100111000000000) // 0100 1110 0000 0000 the T tetromino with a 180° rotation -#define TETROMINO_T_270 ((Shape)0b0010011000100000) // 0010 0110 0010 0000 the T tetromino with a 270° rotation -#define TETROMINO_L ((Shape)0b1000100011000000) // 1000 1000 1100 0000 the L tetromino with no rotation -#define TETROMINO_L_90 ((Shape)0b1110100000000000) // 1110 1000 0000 0000 the L tetromino with a no rotation -#define TETROMINO_L_180 ((Shape)0b1100010001000000) // 1100 0100 0100 0000 the L tetromino with a 180° rotation -#define TETROMINO_L_270 ((Shape)0b0000001011100000) // 0000 0010 1110 0000 the L tetromino with a 270° rotation -#define TETROMINO_J ((Shape)0b0100010011000000) // 0100 0100 1100 0000 the J tetromino with no rotation -#define TETROMINO_J_90 ((Shape)0b1000111000000000) // 1000 1110 0000 0000 the J tetromino with a no rotation -#define TETROMINO_J_180 ((Shape)0b1100100010000000) // 1100 1000 1000 0000 the J tetromino with a 180° rotation -#define TETROMINO_J_270 ((Shape)0b1110001000000000) // 1110 0010 0000 0000 the J tetromino with a 270° rotation -#define TETROMINO_S ((Shape)0b0110110000000000) // 0110 1100 0000 0000 the S tetromino with no rotation -#define TETROMINO_S_90 ((Shape)0b1000110001000000) // 1000 1100 0100 0000 the S tetromino with a no rotation -#define TETROMINO_Z ((Shape)0b1100011000000000) // 1100 0110 0000 0000 the Z tetromino with no rotation -#define TETROMINO_Z_90 ((Shape)0b0100110010000000) // 0100 1100 1000 0000 the Z tetromino with a no rotation +typedef uint32_t PackedRow; // stores the data used in the game -#define ROWS 32 -#define COLUMNS (sizeof(Row) * 8 / 3) +#define COLUMNS ((uint8_t)(sizeof(PackedRow) * 8 / 3)) +#define ROWS ((uint8_t)(COLUMNS * 2)) + +typedef union { + // NOTE: this has packing issues + struct { + uint8_t block : 3; + } columns[COLUMNS]; + PackedRow val; +} Row; + typedef struct { Row row[ROWS]; } GameData; diff --git a/src/game/shapes.h b/src/game/shapes.h new file mode 100644 index 0000000..17a87bd --- /dev/null +++ b/src/game/shapes.h @@ -0,0 +1,36 @@ +#include +#define SHAPE_WIDTH 4 +#define SHAPE_HEIGHT 4 + + +typedef uint16_t Shape; +typedef uint8_t ShapeRow; + +// 0 1 2 3 +#define TETROMINO_I ((Shape)0b1000100010001000) // 1000 1000 1000 1000 the I tetromino with no rotation +#define TETROMINO_I_90 ((Shape)0b0000000000001111) // 0000 0000 0000 1111 the I tetromino with a no rotation +#define TETROMINO_O ((Shape)0b1100110000000000) // 1100 1100 0000 0000 the O tetromino with no rotation +#define TETROMINO_T ((Shape)0b1110010000000000) // 1110 0100 0000 0000 the T tetromino with no rotation +#define TETROMINO_T_90 ((Shape)0b1100110010000000) // 1100 1100 1000 0000 the T tetromino with a no rotation +#define TETROMINO_T_180 ((Shape)0b0100111000000000) // 0100 1110 0000 0000 the T tetromino with a 180° rotation +#define TETROMINO_T_270 ((Shape)0b0010011000100000) // 0010 0110 0010 0000 the T tetromino with a 270° rotation +#define TETROMINO_L ((Shape)0b1000100011000000) // 1000 1000 1100 0000 the L tetromino with no rotation +#define TETROMINO_L_90 ((Shape)0b1110100000000000) // 1110 1000 0000 0000 the L tetromino with a no rotation +#define TETROMINO_L_180 ((Shape)0b1100010001000000) // 1100 0100 0100 0000 the L tetromino with a 180° rotation +#define TETROMINO_L_270 ((Shape)0b0000001011100000) // 0000 0010 1110 0000 the L tetromino with a 270° rotation +#define TETROMINO_J ((Shape)0b0100010011000000) // 0100 0100 1100 0000 the J tetromino with no rotation +#define TETROMINO_J_90 ((Shape)0b1000111000000000) // 1000 1110 0000 0000 the J tetromino with a no rotation +#define TETROMINO_J_180 ((Shape)0b1100100010000000) // 1100 1000 1000 0000 the J tetromino with a 180° rotation +#define TETROMINO_J_270 ((Shape)0b1110001000000000) // 1110 0010 0000 0000 the J tetromino with a 270° rotation +#define TETROMINO_S ((Shape)0b0110110000000000) // 0110 1100 0000 0000 the S tetromino with no rotation +#define TETROMINO_S_90 ((Shape)0b1000110001000000) // 1000 1100 0100 0000 the S tetromino with a no rotation +#define TETROMINO_Z ((Shape)0b1100011000000000) // 1100 0110 0000 0000 the Z tetromino with no rotation +#define TETROMINO_Z_90 ((Shape)0b0100110010000000) // 0100 1100 1000 0000 the Z tetromino with a no rotation + +static inline ShapeRow shape_get_row(Shape shape, uint8_t index) { + return shape >> (((SHAPE_HEIGHT - 1) - index) * 4) & 0b1111; +} + +static inline _Bool is_set(ShapeRow row, uint8_t index) { + return (row >> ((SHAPE_WIDTH - 1) - index) & 1) != 0; +} diff --git a/src/window/renderer.c b/src/window/renderer.c index ca65d90..80c5042 100644 --- a/src/window/renderer.c +++ b/src/window/renderer.c @@ -26,16 +26,6 @@ int renderer_init(SDL_Window** window, SDL_Renderer** renderer) { return 0; } -static inline int set_block(SDL_Renderer* renderer, const Row row, const uint8_t block, const uint8_t filter, const uint8_t x, const uint8_t y) { - uint8_t colour = block & filter; - return SDL_SetRenderDrawColor(renderer, - 0xFF * (0 != (colour & (RED | RED << 3))), - 0xFF * (0 != (colour & (GREEN | GREEN << 3))), - 0xFF * (0 != (colour & (BLUE | BLUE << 3))), - 0xFF) | - SDL_RenderFillRect(renderer, &(SDL_Rect){x * BLOCK_WIDTH + 1, y * BLOCK_HEIGHT + 1, BLOCK_WIDTH - 1, BLOCK_HEIGHT - 1}); -} - void renderer_update(const RenderData* render_data) { SDL_Renderer* renderer = render_data->renderer; GameData* data = render_data->game_data; @@ -43,20 +33,21 @@ void renderer_update(const RenderData* render_data) { int success = 0; // if an error occurs, this value is <0 // clear render - success |= SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x50); + success |= SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); success |= SDL_RenderClear(renderer); for (uint8_t y = 0; y < ROWS; y++) { Row row = data->row[y]; - for (uint8_t x = 0; x < COLUMNS; x += 2) { - uint8_t block = row >> (x * 3); // get the two blocks stored at this column - - if ((block & 0x0F) != 0) - success |= set_block(renderer, row, block, 0x0F, x + 1, y); - - if ((block & 0xF0) != 0) - success |= set_block(renderer, row, block, 0xF0, x, y); + for (uint8_t x = 0; x < COLUMNS; x++) { + if (row.columns[x].block != 0) { + success |= SDL_SetRenderDrawColor(renderer, + 0xFF * !!(row.columns[x].block & RED), + 0xFF * !!(row.columns[x].block & GREEN), + 0xFF * !!(row.columns[x].block & BLUE), + 0xFF); + success |= SDL_RenderFillRect(renderer, &(SDL_Rect){x * BLOCK_WIDTH + 1, y * BLOCK_HEIGHT + 1, BLOCK_WIDTH - 1, BLOCK_HEIGHT - 1}); + } } } diff --git a/src/window/renderer.h b/src/window/renderer.h index 164198c..cebb225 100644 --- a/src/window/renderer.h +++ b/src/window/renderer.h @@ -6,7 +6,7 @@ #define SCREEN_WIDTH 256 #define SCREEN_HEIGHT (SCREEN_WIDTH * 2) #define BLOCK_WIDTH (SCREEN_WIDTH / COLUMNS) -#define BLOCK_HEIGHT (SCREEN_HEIGHT / (BLOCK_WIDTH * 2)) +#define BLOCK_HEIGHT (SCREEN_HEIGHT / ROWS) // fits colours in a 3 bit length // 4th bit is unused