commit 3cb9c2e9dcce76027f75676cf67f2d3d8e9978ff
parent d19dde4b3b3e1c4982ef4d9f787c3e2c8a306c39
Author: krasjet
Date: 2020-12-25 17:26Z

add sdl

Diffstat:
MREADME | 3++-
Asdl/Makefile | 16++++++++++++++++
Asdl/README | 18++++++++++++++++++
Asdl/configure | 16++++++++++++++++
Asdl/pixel.c | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 217 insertions(+), 1 deletion(-)

diff --git a/README b/README @@ -28,7 +28,8 @@ In particular, a minimal working example should be 5. Correct The program should work as intended on valid inputs, and valgrind should be - clean unless a fatal error occurs. No memory leaks should be possible. + clean unless a fatal error occurs or the library itself has memory leak + issues (many graphics libraries, including xlib, do). Many people seem to restrict the use of this term to describe the preferred code style for bug reports, but I hope more developers could adopt this style diff --git a/sdl/Makefile b/sdl/Makefile @@ -0,0 +1,16 @@ +CC = cc +CFLAGS = -std=c99 -Wall -Wextra -pedantic -Os + +include config.mk + +BINS = pixel + +all: $(BINS) + +pixel: pixel.c + $(CC) $(CFLAGS) $(SDL2_CFLAGS) -o $@ pixel.c $(SDL2_LDLIBS) -lm + +clean: + rm -f $(BINS) *.o + +.PHONY: all clean diff --git a/sdl/README b/sdl/README @@ -0,0 +1,18 @@ +sdl +=== + +pixel.c: + render pixel graphics in SDL + +Build +----- + +First run + + $ ./configure + +to generate `config.mk`, then use + + $ make + +to build the binary. diff --git a/sdl/configure b/sdl/configure @@ -0,0 +1,16 @@ +#!/bin/sh + +printf "Checking for sdl2..." +if ! pkg-config sdl2; then + echo "NOT FOUND" + echo "Please make sure sdl2 is installed." + exit 1 +fi +echo "OK" +SDL2_CFLAGS=$(pkg-config --cflags sdl2) +SDL2_LDLIBS=$(pkg-config --libs sdl2) + +cat <<-EOF > config.mk +SDL2_CFLAGS=${SDL2_CFLAGS} +SDL2_LDLIBS=${SDL2_LDLIBS} +EOF diff --git a/sdl/pixel.c b/sdl/pixel.c @@ -0,0 +1,165 @@ +/* pixel.c: render pixel graphics in sdl */ +#include <SDL2/SDL.h> +#include <signal.h> + +static volatile int done = 0; + +/* pixel defined by BGRA32 */ +struct Pixel { + Uint8 b; + Uint8 g; + Uint8 r; + Uint8 a; +}; + +/* global data, you might want to encapsulate it into a struct */ +static SDL_Window *win = NULL; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; + +static void +sig_handler(int signum) +{ + (void) signum; + done = 1; +} + +/* forward declaration */ +static void sdl_finish(void); + +static void +die(const char *msg) +{ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", msg); + sdl_finish(); + exit(EXIT_FAILURE); +} + +/* init sdl */ +static void +sdl_init(const char *name, int width, int height, int scale) { + /* init sdl */ + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "fail to init sdl\n"); + exit(EXIT_FAILURE); + } + + /* create main window */ + win = SDL_CreateWindow(name, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + width * scale, height * scale, + SDL_WINDOW_SHOWN); + if (!win) + die("fail to create window"); + + /* create renderer */ + renderer = SDL_CreateRenderer(win, -1, 0); + if (!renderer) + die("fail to create renderer"); + + /* create texture */ + texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_BGRA32, + SDL_TEXTUREACCESS_STATIC, + width, height); + if (!texture) + die("fail to create texture"); +} + +/* handle sdl events */ +static void +sdl_handle_events(void) { + SDL_Event event; + + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) + done = 1; + } +} + +/* redraw frame with data in framebuffer */ +static void +sdl_redraw(struct Pixel *fb, int width) { + /* 1. clear previous frame */ + SDL_RenderClear(renderer); + /* 2. update texture */ + SDL_UpdateTexture(texture, NULL, fb, width * sizeof(struct Pixel)); + /* 3. copy texture to frame */ + SDL_RenderCopy(renderer, texture, NULL, NULL); + /* 4. present current frame */ + SDL_RenderPresent(renderer); +} + +/* clean up sdl resources */ +static void +sdl_finish(void) { + if (texture) + SDL_DestroyTexture(texture); + if (renderer) + SDL_DestroyRenderer(renderer); + if (win) + SDL_DestroyWindow(win); + SDL_Quit(); +} + +/* generate a new frame */ +static void +gen_frame(struct Pixel *fb, int width, int height, Uint32 frame) +{ + float cx = width / 2.0, cy = height / 2.0; + float t = frame / 1000.0; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + float xx = x - cx, yy = y - cy; + + /* you are not expected to understand this */ + float shade = 0.5 + 0.5 * + sin(hypot(xx*hypot(xx,yy), yy*hypot(xx,yy)) + 6.2832*t); + fb[y*width + x].r = 255 * shade; + fb[y*width + x].g = 255 * shade; + fb[y*width + x].b = 255 * shade; + fb[y*width + x].a = 255; + } + } +} + +int +main(void) +{ + int width = 128, height = 128, fps = 60, scale = 2; + Uint32 ntick = 0; + const Uint32 framedelay = 1000 / fps; + struct Pixel *fb = NULL; + + sdl_init("pattern", width, height, scale); + + /* allocate framebuffer */ + fb = calloc(width * height, sizeof(struct Pixel)); + if (!fb) + die("can't allocate framebuffer"); + + /* install sig handler for grace shutdown (Ctrl-C) */ + signal(SIGINT, sig_handler); + + while (!done) { + /* cap fps */ + Uint32 tick = SDL_GetTicks(); + if (tick < ntick) + SDL_Delay(ntick - tick); + ntick = SDL_GetTicks() + framedelay; + + sdl_handle_events(); + + /* generate new frame to fb */ + gen_frame(fb, width, height, SDL_GetTicks()); + /* and redraw */ + sdl_redraw(fb, width); + } + + sdl_finish(); + free(fb); + + return 0; +}