aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <dbphillipsnz@gmail.com>2016-01-12 20:41:56 +1300
committerDavid Phillips <dbphillipsnz@gmail.com>2016-01-12 20:41:56 +1300
commit58bef85206c7cce153400e51b247e2476e9e65a4 (patch)
tree9e9856c8c554545c44834c89fe0086f9a36abf22
downloadtetris-58bef85206c7cce153400e51b247e2476e9e65a4.tar.xz
Initial commit of rough-arse Tetris
-rw-r--r--.gitignore2
-rw-r--r--Makefile15
-rw-r--r--README.md3
-rw-r--r--colour.h5
-rw-r--r--config.mk2
-rw-r--r--plot.c103
-rw-r--r--plot.h14
-rw-r--r--tetris.c265
-rw-r--r--tetromino.h207
-rw-r--r--window.c44
-rw-r--r--window.h20
11 files changed, 680 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..213c075
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+tetris
+*.o
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..545347b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+include config.mk
+
+all: tetris
+
+tetris: tetris.o plot.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -c -o $@ $< $(CFLAGS)
+
+clean:
+ rm -f tetris
+ find -name "*.o" -delete
+
+.PHONY: all clean
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2ec5c1f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+What?
+=====
+Tetris.
diff --git a/colour.h b/colour.h
new file mode 100644
index 0000000..fc25ac9
--- /dev/null
+++ b/colour.h
@@ -0,0 +1,5 @@
+struct colour {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+};
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..d3875ba
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,2 @@
+CFLAGS += -I/usr/include/SDL2 -Wall -Wextra -Werror
+LDFLAGS += -lm -lsqlite3 -lSDL2
diff --git a/plot.c b/plot.c
new file mode 100644
index 0000000..6a579d6
--- /dev/null
+++ b/plot.c
@@ -0,0 +1,103 @@
+#include <SDL.h>
+
+#include "colour.h"
+#include "plot.h"
+
+static SDL_Window *window = NULL;
+static SDL_Renderer *renderer = NULL;
+
+void plot_update()
+{
+ SDL_RenderPresent(renderer);
+}
+
+void plot_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, struct colour *c)
+{
+ SDL_Rect rect;
+
+ SDL_SetRenderDrawColor(renderer, c->r, c->g, c->b, 255);
+
+ rect.x = x;
+ rect.y = y;
+ rect.w = width;
+ rect.h = height;
+
+ SDL_RenderFillRect(renderer, &rect);
+}
+
+void plot_cell(unsigned int x, unsigned int y, struct colour *c)
+{
+ plot_rect(
+ x*CELL_SIZE+(x-1)*BORDER_THICKNESS,
+ y*CELL_SIZE+(y-1)*BORDER_THICKNESS,
+ CELL_SIZE,
+ CELL_SIZE,
+ c
+ );
+}
+
+void plot_cell_borders()
+{
+ int i, j;
+
+ struct colour col = {.r = 0, .g = 0, .b = 0};
+
+ for (i = 1; i < WIDTH_CELLS; i++)
+ {
+ j = i*CELL_SIZE + (i-1)*BORDER_THICKNESS;
+ plot_rect(
+ j, 0,
+ BORDER_THICKNESS, HEIGHT_PIXELS,
+ &col);
+ }
+
+ for (i = 1; i < HEIGHT_CELLS; i++)
+ {
+ j = i*CELL_SIZE + (i-1)*BORDER_THICKNESS;
+ plot_rect(
+ 0, j,
+ WIDTH_PIXELS, BORDER_THICKNESS,
+ &col);
+ }
+
+}
+
+
+int plot_init()
+{
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ {
+ fprintf(stderr, "Failed to init SDL video: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ window = SDL_CreateWindow(
+ "Some title",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ WIDTH_PIXELS,
+ HEIGHT_PIXELS,
+ SDL_WINDOW_SHOWN
+ );
+
+ if (window == NULL)
+ {
+ fprintf(stderr, "Failed to create window: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ renderer = SDL_CreateRenderer(window, 0, 0);
+ if (renderer == NULL)
+ {
+ fprintf(stderr, "Failed to get window renderer: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ /* blank out the background with gray */
+ SDL_SetRenderDrawColor(renderer, 0x33, 0x33, 0x33, 0xFF);
+ SDL_RenderFillRect(renderer, NULL);
+
+ plot_cell_borders();
+
+ return 0;
+}
diff --git a/plot.h b/plot.h
new file mode 100644
index 0000000..836c377
--- /dev/null
+++ b/plot.h
@@ -0,0 +1,14 @@
+void plot_rect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, struct colour *c);
+void plot_cell(unsigned int x, unsigned int y, struct colour *c);
+void plot_cell_borders();
+int plot_init();
+void plot_update();
+
+#define CELL_SIZE 25
+#define BORDER_THICKNESS 2
+#define WIDTH_CELLS 10
+#define HEIGHT_CELLS 20
+
+#define WIDTH_PIXELS (WIDTH_CELLS * CELL_SIZE + BORDER_THICKNESS * (WIDTH_CELLS-1))
+#define HEIGHT_PIXELS (HEIGHT_CELLS * CELL_SIZE + BORDER_THICKNESS * (HEIGHT_CELLS-1))
+
diff --git a/tetris.c b/tetris.c
new file mode 100644
index 0000000..3b6364a
--- /dev/null
+++ b/tetris.c
@@ -0,0 +1,265 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <SDL.h>
+#include <time.h>
+
+#include "colour.h"
+#include "tetromino.h"
+#include "plot.h"
+
+#define TETROMINO_WIDTH 4
+#define TETROMINO_HEIGHT 4
+#define TETROMINO_AREA (TETROMINO_HEIGHT*TETROMINO_WIDTH)
+
+
+#define MIN(a,b) (a<b? a : b)
+
+
+void main_loop();
+
+
+
+
+struct colour palette[] = {
+ {.r=0x00,.g=0x00,.b=0x00},
+ {.r=0x00,.g=0x00,.b=0xFF},
+ {.r=0x00,.g=0xFF,.b=0x00},
+ {.r=0x00,.g=0xFF,.b=0xFF},
+ {.r=0xFF,.g=0x00,.b=0x00},
+ {.r=0xFF,.g=0x00,.b=0xFF},
+ {.r=0xFF,.g=0xFF,.b=0x00},
+ {.r=0xFF,.g=0xFF,.b=0xFF}
+};
+
+
+void draw_board(struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS])
+{
+ unsigned int x,y;
+ for (y = 0; y < HEIGHT_CELLS; y++)
+ {
+ for (x = 0; x < WIDTH_CELLS; x++)
+ {
+ plot_cell(x,y, (*board)[x][y]);
+ }
+ }
+}
+
+void draw_piece(int x, int y, struct colour *c, char (*piece)[4][4])
+{
+ int px, py, ipx, ipy, end_x, end_y, wx, wy;
+ ipx = (x < 0)? -x : 0;
+ ipy = (y < 0)? -y : 0;
+ end_y = MIN(HEIGHT_CELLS, y + 4);
+ end_x = MIN(WIDTH_CELLS, x + 4);
+
+ for (wy = (y < 0)? 0 : y, py = ipy; wy < end_y; wy++, py++)
+ for (wx = (x < 0)? 0 : x, px = ipx; wx < end_x; wx++, px++)
+ if ((*piece)[px][py])
+ plot_cell(wx, wy, c);
+}
+
+void drop_piece(int x, int y, struct piece *piece, struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS])
+{
+ int px, py, ipx, ipy, end_x, end_y, wx, wy;
+ ipx = (x < 0)? -x : 0;
+ ipy = (y < 0)? -y : 0;
+ end_y = MIN(HEIGHT_CELLS, y + 4);
+ end_x = MIN(WIDTH_CELLS, x + 4);
+
+ for (wy = (y < 0)? 0 : y, py = ipy; wy < end_y; wy++, py++)
+ for (wx = (x < 0)? 0 : x, px = ipx; wx < end_x; wx++, px++)
+ if ((*piece->bitmap)[px][py])
+ (*board)[wx][wy] = piece->colour;
+}
+
+Uint32 gravity_callback(Uint32 interval, void *param)
+{
+ (void)param; /* solves unused parameter warn+error */
+ SDL_Event e;
+ SDL_UserEvent ue;
+ ue.type = SDL_USEREVENT;
+ ue.code = 0;
+ ue.data1 = 0;
+ ue.data2 = 0;
+
+ e.type = SDL_USEREVENT;
+ e.user = ue;
+
+ SDL_PushEvent(&e);
+ return interval;
+}
+
+int main()
+{
+ srand(time(NULL));
+ plot_init();
+ main_loop();
+}
+
+
+int hit_floor(int x, int y, struct piece *held, struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS])
+{
+ int px,py;
+ for (px = 0; px < 4; px++)
+ {
+ /* seek to first cell of column */
+ py = 0;
+ while (py < 4 && (*held->bitmap)[px][py] == 0)
+ py++;
+
+ /* column has no cells? no collision possible. NEXT! */
+ if (py == 4)
+ continue;
+
+ while (py < 4 && (*held->bitmap)[px][py])
+ py++;
+
+ if ( y + py >= HEIGHT_CELLS
+ || (*board)[x + px][y + py] != &(palette[0]))
+ return 1;
+ }
+ return 0;
+}
+
+int hit_side(int x, int y, struct piece *held, struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS])
+{
+ int px,py;
+ for (py = 0; py < 4; py++)
+ {
+ for (px = 0; px < 4; px++)
+ {
+ if ((*held->bitmap)[px][py]
+ &&
+ ( x + px >= WIDTH_CELLS
+ || x + px < 0
+ || (*board)[x + px][y + py] != &(palette[0])
+ ))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void update_bitmap(struct piece *held)
+{
+ held->bitmap = &(tetrominoes[0][held->type][held->rotation]);
+}
+
+void new_piece(struct piece *held)
+{
+ held->colour = &palette[rand() % 7 + 1];
+ held->type = rand()%7;
+ held->rotation= rand()%4;
+ update_bitmap(held);
+}
+
+void rotate(struct piece *held)
+{
+ held->rotation++;
+ if (held->rotation >= 4)
+ held->rotation -= 4;
+
+ update_bitmap(held);
+}
+
+
+void clear_rows(struct colour* (*board)[WIDTH_CELLS][HEIGHT_CELLS])
+{
+ char row;
+ int x, y, x1, y1;
+ for (y = 0; y < HEIGHT_CELLS; y++)
+ {
+ row = 1;
+ for (x = 0; x < WIDTH_CELLS; x++)
+ {
+ if ((*board)[x][y] == &(palette[0]))
+ {
+ row = 0;
+ break;
+ }
+ }
+ if (!row)
+ continue;
+
+ for (y1 = y; y1 > 0; y1--)
+ for (x1 = 0; x1 < WIDTH_CELLS; x1++)
+ (*board)[x1][y1] = (*board)[x1][y1-1];
+
+ for (x1 = 0; x1 < WIDTH_CELLS; x1++)
+ (*board)[x1][y1] = &(palette[0]);
+ }
+}
+
+void main_loop()
+{
+ struct colour *board[WIDTH_CELLS][HEIGHT_CELLS];
+ SDL_Event e = {0};
+ bool running = false;
+ int x = 0;
+ int y = 0;
+ int last_x = 0;
+ int last_y = 1;
+ struct piece held;
+ new_piece(&held);
+
+ for (y = 0; y < HEIGHT_CELLS; y++)
+ for (x = 0; x < WIDTH_CELLS; x++)
+ board[x][y] = &(palette[0]);
+
+ running = true;
+ last_x = last_y = x = y = 0;
+ SDL_AddTimer(500, &gravity_callback, NULL);
+ char lockout;
+ while (running)
+ {
+ lockout = 0;
+ clear_rows(&board);
+ if (hit_side(x, y, &held, &board))
+ {
+ x = last_x;
+ }
+ if (hit_floor(x, y, &held, &board))
+ {
+ lockout = 1;
+ }
+ draw_board(&board);
+ draw_piece(x, y, held.colour, held.bitmap);
+ plot_update();
+ while(SDL_PollEvent(&e))
+ {
+ switch (e.type)
+ {
+ case SDL_USEREVENT:
+ if (lockout) {
+ drop_piece(x, y, &held, &board);
+ last_x = last_y = x = y = 0;
+ new_piece(&held);
+ lockout = 0;
+ } else {
+ last_y = y++; /* gravity */
+ last_x = x;
+ }
+ break;
+ case SDL_QUIT:
+ fprintf(stderr, "quit\n");
+ running = false;
+ break;
+
+ case SDL_KEYDOWN:
+ switch (e.key.keysym.sym)
+ {
+ case SDLK_a: last_x = x--; break;
+ case SDLK_d: last_x = x++; break;
+ case SDLK_w: rotate(&held); break;
+ case SDLK_q:
+ running = false;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/tetromino.h b/tetromino.h
new file mode 100644
index 0000000..c0a33f0
--- /dev/null
+++ b/tetromino.h
@@ -0,0 +1,207 @@
+#define TETROMINO_WIDTH 4
+#define TETROMINO_HEIGHT 4
+#define TETROMINO_AREA (TETROMINO_HEIGHT*TETROMINO_WIDTH)
+/*
+struct tetromino {
+ char name;
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ unsigned int width;
+ unsigned int height;
+ char data[4][16];
+};*/
+
+struct piece
+{
+ struct colour *colour;
+ char (*bitmap)[4][4];
+ int type;
+ int rotation;
+};
+
+char tetromino_I[4][4][4] = {
+ {
+ {0,0,0,0},
+ {1,1,1,1},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,0,1,0},
+ {0,0,1,0},
+ {0,0,1,0},
+ {0,0,1,0}
+ },{
+ {0,0,0,0},
+ {0,0,0,0},
+ {1,1,1,1},
+ {0,0,0,0}
+ },{
+ {0,1,0,0},
+ {0,1,0,0},
+ {0,1,0,0},
+ {0,1,0,0}
+ }
+};
+
+
+char tetromino_J[4][4][4] = {
+ {
+ {1,0,0,0},
+ {1,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,1,1,0},
+ {0,1,0,0},
+ {0,1,0,0},
+ {0,0,0,0}
+ },{
+ {0,0,0,0},
+ {1,1,1,0},
+ {0,0,1,0},
+ {0,0,0,0}
+ },{
+ {0,1,0,0},
+ {0,1,0,0},
+ {1,1,0,0},
+ {0,0,0,0}
+ }
+};
+
+
+char tetromino_L[4][4][4] = {
+ {
+ {0,0,1,0},
+ {1,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,1,0,0},
+ {0,1,0,0},
+ {0,1,1,0},
+ {0,0,0,0}
+ },{
+ {0,0,0,0},
+ {1,1,1,0},
+ {1,0,0,0},
+ {0,0,0,0}
+ },{
+ {1,1,0,0},
+ {0,1,0,0},
+ {0,1,0,0},
+ {0,0,0,0}
+ }
+};
+
+
+char tetromino_O[4][4][4]= {
+ {
+ {0,1,1,0},
+ {0,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,1,1,0},
+ {0,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,1,1,0},
+ {0,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,1,1,0},
+ {0,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ }
+};
+
+
+char tetromino_S[4][4][4] = {
+ {
+ {0,1,1,0},
+ {1,1,0,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,1,0,0},
+ {0,1,1,0},
+ {0,0,1,0},
+ {0,0,0,0}
+ },{
+ {0,0,0,0},
+ {0,1,1,0},
+ {1,1,0,0},
+ {0,0,0,0}
+ },{
+ {1,0,0,0},
+ {1,1,0,0},
+ {0,1,0,0},
+ {0,0,0,0}
+ }
+};
+
+
+char tetromino_T[4][4][4] = {
+ {
+ {1,1,1,0},
+ {0,1,0,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,0,1,0},
+ {0,1,1,0},
+ {0,0,1,0},
+ {0,0,0,0}
+ },{
+ {0,0,0,0},
+ {0,1,0,0},
+ {1,1,1,0},
+ {0,0,0,0}
+ },{
+ {1,0,0,0},
+ {1,1,0,0},
+ {1,0,0,0},
+ {0,0,0,0}
+ }
+};
+
+char tetromino_Z[4][4][4] = {
+ {
+ {1,1,0,0},
+ {0,1,1,0},
+ {0,0,0,0},
+ {0,0,0,0}
+ },{
+ {0,0,1,0},
+ {0,1,1,0},
+ {0,1,0,0},
+ {0,0,0,0}
+ },{
+ {0,0,0,0},
+ {1,1,0,0},
+ {0,1,1,0},
+ {0,0,0,0}
+ },{
+ {0,1,0,0},
+ {1,1,0,0},
+ {1,0,0,0},
+ {0,0,0,0}
+ }
+};
+
+
+
+
+char (*tetrominoes[])[4][4][4] = {
+ &tetromino_I,
+ &tetromino_J,
+ &tetromino_L,
+ &tetromino_O,
+ &tetromino_S,
+ &tetromino_T,
+ &tetromino_Z
+};
diff --git a/window.c b/window.c
new file mode 100644
index 0000000..2128f1c
--- /dev/null
+++ b/window.c
@@ -0,0 +1,44 @@
+#include "window.h"
+
+#include <SDL.h>
+
+int display_init(struct window *wobj)
+{
+ if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0)
+ {
+ fprintf(stderr,"Couldn't init SDL: %s\n", SDL_GetError());
+ return EXIT_FAILURE;
+ }
+
+ /* Create run-of-the-mill window at specified size */
+ wobj->window = SDL_CreateWindow(
+ wobj->title,
+ SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+ wobj->width, wobj->height,
+ SDL_WINDOW_SHOWN
+ );
+ if (wobj->window == NULL)
+ {
+ fprintf(stderr, "Couldn't create window: %s\n", SDL_GetError());
+ return EXIT_FAILURE;
+ }
+
+ /* Grab window surface */
+ wobj->surface = SDL_GetWindowSurface(wobj->window);
+ if (wobj->surface == NULL)
+ {
+ fprintf(stderr, "Couldn't grab window surface: %s\n", SDL_GetError());
+ return EXIT_FAILURE;
+ }
+
+ /* Clear/blank surface with grey, and update it */
+ SDL_FillRect(wobj->surface, NULL, SDL_MapRGB(wobj->surface->format, 0x33, 0x33, 0x33));
+ SDL_UpdateWindowSurface(wobj->window);
+ return EXIT_SUCCESS;
+}
+
+void display_stop(struct window *wobj)
+{
+ SDL_DestroyWindow(wobj->window);
+ SDL_Quit();
+}
diff --git a/window.h b/window.h
new file mode 100644
index 0000000..0c97b86
--- /dev/null
+++ b/window.h
@@ -0,0 +1,20 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <SDL.h>
+#include <stdbool.h>
+
+struct window {
+ SDL_Window *window;
+ SDL_Renderer *renderer;
+ SDL_Surface *surface;
+ unsigned int height;
+ unsigned int width;
+ char* title;
+};
+
+int display_init(struct window *wobj);
+void display_stop(struct window *wobj);
+
+
+#endif