I am learning programming by making a Tetris game, my example code below references that but really my problems is so much more trivial than Tetris, as a test I am painting random colors on a 640x480 buffer, and already I am screwing up, how people make Call of Duty I just can’t imagine…
I can’t describe what the problem is so I took a video and posted it here: https://drive.google.com/open?id=13LbsmVtk1zBervDJRy8ofu__CC41iFwi
It is quite hard to see, but I see a horizontal zig-zag line flash up about 5 times during this video of my “game”. I have no idea why it’s happening, any keywords I can educate myself with would be amazing.
My code is here,
/* To compile:
* First compile SDL from hg checkout using "mkdir build; cd build; cmake .. -DCMAKE_BUILD_TYPE=Debug"
* cc -g -I./SDL/include tetris.c ./SDL/build/libSDL2d.a /usr/lib/x86_64-linux-gnu/libsndio.so -ldl -lm -lpthread -o tetris
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <SDL.h>
#define LOGICAL_WIDTH 640
#define LOGICAL_HEIGHT 480
// The screen is divided into blocks of this many square pixels.
// BLOCK_WIDTH_HEIGHT must be a factor of LOGICAL_WIDTH and LOGICAL_HEIGHT.
// Valid widths for 640x480: 1,2,4,5,8,10,16,20,32,40,80,160
#define BLOCK_WIDTH_HEIGHT 80
#define BLOCK_NUM_PIXELS (BLOCK_WIDTH_HEIGHT * BLOCK_WIDTH_HEIGHT)
#define NUM_BLOCKS_ACROSS (LOGICAL_WIDTH / BLOCK_WIDTH_HEIGHT)
#define NUM_BLOCKS_DOWN (LOGICAL_HEIGHT / BLOCK_WIDTH_HEIGHT)
#define NUM_BLOCKS (NUM_BLOCKS_ACROSS * NUM_BLOCKS_DOWN)
// Taken from stb.h
static uint32_t tetris__random_seed = 0;
uint32_t tetris_srandLCG()
{
tetris__random_seed = tetris__random_seed * 2147001325 + 715136305; // BCPL generator
// shuffle non-random bits to the middle, and xor to decorrelate with seed
return 0x31415926 ^ ((tetris__random_seed >> 16) + (tetris__random_seed << 16));
}
#define tetris_rng tetris_srandLCG
// Where the frames are drawn.
static uint32_t *frame_buffer_start;
static uint32_t frame_buffer_n_pixels;
static uint32_t frame_buffer_pitch;
static void
tetris_render_solid(uint32_t color)
{
uint32_t *pixel = frame_buffer_start;
uint32_t pixels_left_to_paint = frame_buffer_n_pixels;
while (pixels_left_to_paint--) {
*pixel++ = color;
}
}
static void
tetris_render_random_colored_pixels()
{
uint32_t *pixel = frame_buffer_start;
uint32_t pixels_left_to_paint = frame_buffer_n_pixels;
while (pixels_left_to_paint--) {
*pixel++ = tetris_rng();
}
}
static void
tetris_render_block_solid_color_at (uint32_t block_color, uint32_t block_n)
{
uint32_t block_row_start_pixel =
BLOCK_WIDTH_HEIGHT * block_n + ((block_n / NUM_BLOCKS_ACROSS) * (NUM_BLOCKS_ACROSS * BLOCK_NUM_PIXELS));
for (int i = 0; i < BLOCK_WIDTH_HEIGHT; i++) {
uint32_t *pixels = frame_buffer_start + block_row_start_pixel;
// Render a row
for (int j = 0; j < BLOCK_WIDTH_HEIGHT; j++)
*pixels++ = block_color;
block_row_start_pixel += LOGICAL_WIDTH;
}
}
// #include "test_block.data"
void
tetris_render_test_blocks()
{
for (int block_num = 0; block_num < NUM_BLOCKS; block_num++)
tetris_render_block_solid_color_at (0xFF0000FF, block_num);
}
int
main(int argc, char *argv[])
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture; // The texture on the GPU.
SDL_Event event;
int quit = 0;
// Note: most SDL calls must happen on the same thread as this call.
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf (stderr, "failed to initialize SDL: [SDL error: %s]", SDL_GetError());
exit (1);
}
// Setup frame buffer memory.
// Width * Height * (r, g, b, a)
frame_buffer_pitch = LOGICAL_WIDTH * sizeof(uint32_t);
uint32_t frame_buffer_size_in_bytes = frame_buffer_pitch * LOGICAL_HEIGHT;
frame_buffer_start = malloc(frame_buffer_size_in_bytes);
if (!frame_buffer_start) {
fprintf (stderr, "failed to create frame buffer\n");
exit (1);
}
frame_buffer_n_pixels = frame_buffer_size_in_bytes / sizeof(uint32_t);
printf("blocks across: %d\n", NUM_BLOCKS_ACROSS);
printf("blocks down: %d\n", NUM_BLOCKS_DOWN);
window = SDL_CreateWindow ("Tetris!",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
0, 0,
SDL_WINDOW_FULLSCREEN_DESKTOP);
if (!window) {
fprintf (stderr, "failed to create a game window: [SDL error: %s]\n", SDL_GetError());
exit (1);
}
renderer = SDL_CreateRenderer (window, -1, 0);
if (!renderer) {
fprintf (stderr, "failed to create a game renderer: [SDL error: %s]\n", SDL_GetError());
exit (1);
}
// Create a texture on the GPU.
texture = SDL_CreateTexture (renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
LOGICAL_WIDTH, LOGICAL_HEIGHT);
// Make the scaled rendering look smoother.
SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, "linear");
SDL_RenderSetLogicalSize (renderer, LOGICAL_WIDTH, LOGICAL_HEIGHT);
tetris_render_solid (0xFF000000);
while (!quit) {
fprintf (stderr,".");
while (SDL_PollEvent (&event)) {
switch (event.type) {
case SDL_QUIT:
quit = 1;
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_q) {
quit = 1;
}
break;
}
}
tetris_render_solid (tetris_rng());
SDL_UpdateTexture (texture, NULL, frame_buffer_start, frame_buffer_pitch);
SDL_RenderClear (renderer);
SDL_RenderCopy (renderer, texture, NULL, NULL);
SDL_RenderPresent (renderer);
SDL_Delay (500);
}
SDL_DestroyWindow (window);
SDL_Quit ();
return 0;
}