commit 3cb9c2e9dcce76027f75676cf67f2d3d8e9978ff
parent d19dde4b3b3e1c4982ef4d9f787c3e2c8a306c39
Author: krasjet
Date: 2020-12-25 17:26Z
add sdl
Diffstat:
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;
+}