diff --git a/src/game/tetromino/placing.c b/src/game/tetromino/placing.c index 0bd8d9e..be53ad8 100644 --- a/src/game/tetromino/placing.c +++ b/src/game/tetromino/placing.c @@ -12,17 +12,17 @@ #include "shapes.h" -/* checks if `row` of `COLUMNS` wide contains anything with `0`. - * returns `1` if it doesn't, otherwise returns `0` */ -__attribute_const__ static int is_filled(u8 const* restrict row) { - int res = 0; +/* count the empty columns in the row */ +__attribute_const__ static int count_empty(u8 const* restrict row) { + int cnt = 0; #if defined(__clang__) #pragma unroll COLUMNS #elif defined(__GNUC__) #pragma GCC unroll COLUMNS #endif - for (int i = 0; i < COLUMNS; i++) res |= !row[i]; - return !res; + for (int i = 0; i < COLUMNS; i++) + cnt += !row[i]; + return cnt; } /* checks for filled rows, clearing a max of 4 consecutive rows, if present. @@ -32,11 +32,11 @@ static void clear_rows(u8* restrict* restrict rows, u16* const score) { uint fillc = 0; uint checkc = 0; - for (uint y = 0; y < (ROWS - fillc); y++) { + for (uint y = 0; y < (ROWS - fillc) && checkc <= 4; y++) { int i = (ROWS - 1) - y; // invert the index direction, so we start at the highest index rows[i] = rows[i - fillc]; // either assigns the current row to itself, or to the "next" row - if (checkc >= 4 || !is_filled(rows[i])) { + if (count_empty(rows[i])) { checkc += (fillc > 0 && checkc < 4); continue; } @@ -57,7 +57,7 @@ static void clear_rows(u8* restrict* restrict rows, u16* const score) { // TODO: this is suboptimal, ditch the entire "representing shapes as binary-formatted data" and instead use a switch...case. /* writes a shape to the screen */ -static void set_shape(u8* restrict const* restrict row, u8 id, i8vec2 pos) { +static void plcmnt_place(u8* restrict const* restrict row, u8 id, i8vec2 pos) { u8 colour = colour_from_id(id); i8vec2 bpos[4]; @@ -73,19 +73,19 @@ static void set_shape(u8* restrict const* restrict row, u8 id, i8vec2 pos) { row[bpos[3][VY]][bpos[3][VX]] = colour; } -static inline int shape_is_valid_pos(u8* restrict const* restrict const rows, i8vec2 pos) { +static int plcmnt_valid(u8* restrict const* restrict const rows, i8vec2 pos) { return pos[VX] >= 0 && pos[VX] < COLUMNS && pos[VY] >= 0 && pos[VY] < ROWS && !rows[pos[VY]][pos[VX]]; } -static int shape_intersects(u8* restrict const* restrict const rows, u8 const id, i8vec2 pos) { +static int plcmnt_intersect(u8* restrict const* restrict const rows, u8 const id, i8vec2 pos) { i8vec2 bpos[4]; shape_getblocks(id, bpos); - return !(shape_is_valid_pos(rows, pos + bpos[0]) && - shape_is_valid_pos(rows, pos + bpos[1]) && - shape_is_valid_pos(rows, pos + bpos[2]) && - shape_is_valid_pos(rows, pos + bpos[3])); + return !(plcmnt_valid(rows, pos + bpos[0]) && + plcmnt_valid(rows, pos + bpos[1]) && + plcmnt_valid(rows, pos + bpos[2]) && + plcmnt_valid(rows, pos + bpos[3])); } void place_update(struct gamedata* gdat, int movdat) { @@ -96,10 +96,10 @@ void place_update(struct gamedata* gdat, int movdat) { // update Y axis tmp = !!(movdat & MOVD); gdat->pdat.sel[VY] += tmp; - tmp = tmp && shape_intersects(gdat->rows, id, gdat->pdat.sel); + tmp = tmp && plcmnt_intersect(gdat->rows, id, gdat->pdat.sel); if (tmp) { gdat->pdat.sel[VY]--; - set_shape(gdat->rows, id, gdat->pdat.sel); + plcmnt_place(gdat->rows, id, gdat->pdat.sel); clear_rows(gdat->rows, &gdat->pnts); // clear the rows that have been completed next_shape(); audio_play(AUDIO_ID_PLACE); @@ -107,9 +107,9 @@ void place_update(struct gamedata* gdat, int movdat) { // update X axis tmp = !!(movdat & MOVR) - !!(movdat & MOVL); - gdat->pdat.sel[VX] += (tmp && !shape_intersects(gdat->rows, id, (i8vec2){gdat->pdat.sel[VX] + tmp, gdat->pdat.sel[VY]})) * tmp; + gdat->pdat.sel[VX] += (tmp && !plcmnt_intersect(gdat->rows, id, (i8vec2){gdat->pdat.sel[VX] + tmp, gdat->pdat.sel[VY]})) * tmp; // update roll tmp = id ^ (((!!(movdat & MOVRR) - !!(movdat & MOVRL)) * 8 + id) & 31); - gdat->pdat.cur ^= (tmp && !shape_intersects(gdat->rows, id ^ tmp, gdat->pdat.sel)) * tmp; + gdat->pdat.cur ^= (tmp && !plcmnt_intersect(gdat->rows, id ^ tmp, gdat->pdat.sel)) * tmp; } diff --git a/src/io/render.c b/src/io/render.c index 111db52..ca06dd3 100644 --- a/src/io/render.c +++ b/src/io/render.c @@ -39,7 +39,7 @@ void render_init(SDL_Window* win, struct gamedata const* game_data) { gdat = game_data; } -static inline int32_t get_column_pos(uint column) { +static inline i32 colpos(uint column) { return column * BLOCK_WIDTH + 1 + TET_PADDING; } @@ -62,14 +62,14 @@ static void draw_score_text(void) { } assert(score_surface && score_texture); - SDL_Rect text_rect = {get_column_pos(COLUMNS + 1), get_row_pos(0), score_surface->w, score_surface->h}; + SDL_Rect text_rect = {colpos(COLUMNS + 1), rowpos(0), score_surface->w, score_surface->h}; SDL_RenderCopy(rend, score_texture, NULL, &text_rect); } // TODO: this is suboptimal, since each block will be 2 triangles, wasting perf. Consider using switch...case hard-coded drawing // draws a block at the specified position static inline int draw_block(SDL_Renderer* const renderer, i8vec2 pos) { - SDL_Rect const block = {get_column_pos(pos[VX]), get_row_pos(pos[VY]), BLOCK_WIDTH - 1, BLOCK_HEIGHT - 1}; + SDL_Rect const block = {colpos(pos[VX]), rowpos(pos[VY]), BLOCK_WIDTH - 1, BLOCK_HEIGHT - 1}; return SDL_RenderFillRect(renderer, &block); }