i made a swapchain
This commit is contained in:
parent
06389e7a7e
commit
0aa6e65ea6
4 changed files with 176 additions and 68 deletions
3
Makefile
3
Makefile
|
@ -2,12 +2,13 @@ CC = gcc
|
|||
|
||||
INCFLAGS = -Isrc
|
||||
|
||||
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
|
||||
CCFLAGS = -std=gnu99 -Wall -Wextra -pedantic -O2
|
||||
CCFLAGS += $(INCFLAGS)
|
||||
|
||||
LDFLAGS += $(INCFLAGS)
|
||||
LDFLAGS += -lX11
|
||||
LDFLAGS += -lm
|
||||
LDFLAGS += -lpthread
|
||||
|
||||
BIN = bin
|
||||
APP = $(BIN)/app
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "ray.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
@ -80,10 +82,11 @@ void update_camera(Camera* camera, Screen* screen) {
|
|||
if (movey) camera->pos.y += move.y * MOVE_SPEED * screen->delta;
|
||||
}
|
||||
|
||||
static void verline(Screen* screen, int x, int y0, int y1, uint32_t color) {
|
||||
static void verline(Swapchain* swapchain, int x, int y0, int y1, uint32_t color) {
|
||||
for (int y = y0; y <= y1; y++) {
|
||||
screen->pixels[(y * screen->width) + x] = color;
|
||||
swapchain->images[swapchain->image_current][(y * swapchain->width) + x] = color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void render(Screen* screen, const Camera* camera) {
|
||||
|
@ -93,9 +96,13 @@ void render(Screen* screen, const Camera* camera) {
|
|||
cos(camera->angle)
|
||||
};
|
||||
|
||||
for (int x = 0; x < screen->width; x++) {
|
||||
Swapchain* swapchain = &screen->swapchain;
|
||||
|
||||
const float xcam = (2 * (x / (float) (screen->width))) - 1;
|
||||
swapchain_next(swapchain);
|
||||
|
||||
for (int x = 0; x < screen->swapchain.width; x++) {
|
||||
|
||||
const float xcam = (2 * (x / (float) (swapchain->width))) - 1;
|
||||
const float change = fov * atan(xcam);
|
||||
const float theta = camera->angle + change;
|
||||
|
||||
|
@ -126,15 +133,18 @@ void render(Screen* screen, const Camera* camera) {
|
|||
// }
|
||||
|
||||
const int
|
||||
h = (int) (screen->height / len),
|
||||
y0 = max((screen->height / 2) - (h / 2), 0),
|
||||
y1 = min((screen->height / 2) + (h / 2), screen->height - 1);
|
||||
h = (int) (swapchain->height / len),
|
||||
y0 = max((swapchain->height / 2) - (h / 2), 0),
|
||||
y1 = min((swapchain->height / 2) + (h / 2), swapchain->height - 1);
|
||||
|
||||
verline(swapchain, x, 0, y0, 0xFF202020);
|
||||
verline(swapchain, x, y0, y1, color);
|
||||
verline(swapchain, x, y1, swapchain->height - 1, 0xFF505050);
|
||||
|
||||
verline(screen, x, 0, y0, 0xFF202020);
|
||||
verline(screen, x, y0, y1, color);
|
||||
verline(screen, x, y1, screen->height - 1, 0xFF505050);
|
||||
// verline(screen, x, 0, y0, 0x202020FF);
|
||||
// verline(screen, x, y0, y1, color);
|
||||
// verline(screen, x, y1, screen->height - 1, 0x505050FF);
|
||||
}
|
||||
|
||||
swapchain_submit(swapchain);
|
||||
}
|
||||
|
|
190
src/screen.c
190
src/screen.c
|
@ -1,4 +1,5 @@
|
|||
#include "screen.h"
|
||||
#include <sched.h>
|
||||
#undef Screen
|
||||
|
||||
#include <math.h>
|
||||
|
@ -7,6 +8,8 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/select.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define XLIB_ILLEGAL_ACCESS
|
||||
#include <X11/X.h>
|
||||
|
@ -28,8 +31,9 @@ typedef struct {
|
|||
Window window;
|
||||
GC graphics_ctx;
|
||||
Pixmap pixel_map;
|
||||
XImage* image;
|
||||
int width, height;
|
||||
XImage** images;
|
||||
pthread_t update_thread;
|
||||
pthread_mutex_t recreate_lock;
|
||||
} WindowState;
|
||||
|
||||
static void init_x() {
|
||||
|
@ -89,43 +93,144 @@ static XImage* create_image(int width, int height, void* data) {
|
|||
);
|
||||
}
|
||||
|
||||
static Swapchain create_swapchain(int width, int height, int frames, int bit_depth, WindowState* state) {
|
||||
Swapchain swapchain;
|
||||
swapchain.width = width;
|
||||
swapchain.height = height;
|
||||
swapchain.image_count = frames;
|
||||
swapchain.image_front = 0;
|
||||
swapchain.image_recent = 0;
|
||||
swapchain.image_current = 0;
|
||||
swapchain.images = malloc(sizeof(uint32_t*) * frames);
|
||||
|
||||
state->images = malloc(sizeof(XImage*) * frames);
|
||||
state->pixel_map = XCreatePixmap(dpy, state->window, width, height, bit_depth);
|
||||
state->graphics_ctx = XCreateGC(dpy, state->pixel_map, 0, NULL);
|
||||
|
||||
size_t pixel_count = width * height;
|
||||
for (int i = 0; i < frames; i++) {
|
||||
uint32_t* data = malloc(pixel_count * bit_depth / 8);
|
||||
memset(data, 0, pixel_count * bit_depth / 8);
|
||||
|
||||
swapchain.images[i] = data;
|
||||
state->images[i] = create_image(width, height, data);
|
||||
|
||||
}
|
||||
|
||||
pthread_mutex_init(&state->recreate_lock, NULL);
|
||||
pthread_mutex_init(&swapchain.lock, NULL);
|
||||
|
||||
return swapchain;
|
||||
}
|
||||
|
||||
static void free_swapchain(Swapchain swapchain, WindowState* state) {
|
||||
for (uint8_t i = 0; i < swapchain.image_count; i++) {
|
||||
XDestroyImage(state->images[i]); // also frees pixel buffer :3
|
||||
}
|
||||
|
||||
free(swapchain.images);
|
||||
free(state->images);
|
||||
|
||||
XFreePixmap(dpy, state->pixel_map);
|
||||
XFreeGC(dpy, state->graphics_ctx);
|
||||
}
|
||||
|
||||
static void recreate_swapchain(int width, int height, int bit_depth, Swapchain* swapchain, WindowState* state) {
|
||||
pthread_mutex_lock(&state->recreate_lock);
|
||||
|
||||
swapchain->width = width;
|
||||
swapchain->height = height;
|
||||
|
||||
XFreePixmap(dpy, state->pixel_map);
|
||||
XFreeGC(dpy, state->graphics_ctx);
|
||||
|
||||
state->pixel_map = XCreatePixmap(dpy, state->window, width, height, bit_depth);
|
||||
state->graphics_ctx = XCreateGC(dpy, state->pixel_map, 0, NULL);
|
||||
|
||||
size_t pixel_count = width * height;
|
||||
for (uint8_t i = 0; i < swapchain->image_count; i++) {
|
||||
XDestroyImage(state->images[i]); // also frees pixel buffer :3
|
||||
|
||||
uint32_t* data = malloc(pixel_count * bit_depth / 8);
|
||||
memset(data, 0, pixel_count * bit_depth / 8);
|
||||
|
||||
swapchain->images[i] = data;
|
||||
state->images[i] = create_image(width, height, data);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&state->recreate_lock);
|
||||
}
|
||||
|
||||
void swapchain_next(Swapchain* swapchain) {
|
||||
pthread_mutex_lock(&swapchain->lock);
|
||||
uint8_t next = swapchain->image_current + 1;
|
||||
next %= swapchain->image_count;
|
||||
|
||||
if (next == swapchain->image_front) {
|
||||
next += 1;
|
||||
next %= 3;
|
||||
}
|
||||
|
||||
swapchain->image_current = next;
|
||||
pthread_mutex_unlock(&swapchain->lock);
|
||||
}
|
||||
|
||||
void swapchain_submit(Swapchain* swapchain) {
|
||||
pthread_mutex_lock(&swapchain->lock);
|
||||
swapchain->image_recent = swapchain->image_current;
|
||||
pthread_mutex_unlock(&swapchain->lock);
|
||||
}
|
||||
|
||||
static void* swapchain_thread(void* arg) {
|
||||
struct Screen* screen = (struct Screen*) arg;
|
||||
WindowState* state = (WindowState*) screen->internal;
|
||||
|
||||
while (1) {
|
||||
pthread_mutex_lock(&state->recreate_lock);
|
||||
|
||||
pthread_mutex_lock(&screen->swapchain.lock);
|
||||
int index = screen->swapchain.image_recent;
|
||||
screen->swapchain.image_front = index;
|
||||
pthread_mutex_unlock(&screen->swapchain.lock);
|
||||
|
||||
XPutImage(
|
||||
dpy,
|
||||
state->window,
|
||||
state->graphics_ctx,
|
||||
state->images[index],
|
||||
0, 0, 0, 0,
|
||||
screen->swapchain.width,
|
||||
screen->swapchain.height
|
||||
);
|
||||
XSync(dpy, 0);
|
||||
|
||||
pthread_mutex_unlock(&state->recreate_lock);
|
||||
|
||||
usleep(1000 * 1000 / 60);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define FRAMES 3
|
||||
|
||||
void init_screen(struct Screen* screen, uint16_t width, uint16_t height, const char* title) {
|
||||
|
||||
if (dpy == NULL) {
|
||||
init_x();
|
||||
}
|
||||
|
||||
screen->width = width;
|
||||
screen->height = height;
|
||||
screen->delta = 0;
|
||||
|
||||
size_t pixel_count = screen->width * screen->height;
|
||||
|
||||
screen->pixels = malloc(pixel_count * bit_depth / 8);
|
||||
memset(screen->pixels, 0, pixel_count * bit_depth / 8);
|
||||
|
||||
Window window = create_window(0, 0, width, height, bit_depth, title);
|
||||
XMapWindow(dpy, window);
|
||||
|
||||
Pixmap pixel_map = XCreatePixmap(dpy, window, width, height, bit_depth);
|
||||
|
||||
GC gc = XCreateGC(dpy, pixel_map, 0, NULL);
|
||||
|
||||
WindowState* state = malloc(sizeof(WindowState));
|
||||
state->window = window;
|
||||
state->graphics_ctx = gc;
|
||||
state->pixel_map = pixel_map;
|
||||
|
||||
XWindowAttributes xwa;
|
||||
XGetWindowAttributes(dpy, window, &xwa);
|
||||
state->width = xwa.width;
|
||||
state->height = xwa.height;
|
||||
screen->swapchain = create_swapchain(width, height, FRAMES, bit_depth, state);
|
||||
pthread_create(&state->update_thread, NULL, &swapchain_thread, screen);
|
||||
|
||||
screen->delta = 0;
|
||||
screen->internal = state;
|
||||
|
||||
XImage* image = create_image(state->width, state->height, screen->pixels);
|
||||
state->image = image;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
|
@ -147,27 +252,10 @@ static void update_delta(struct Screen* screen) {
|
|||
last = now;
|
||||
}
|
||||
|
||||
static void draw_screen(struct Screen* screen) {
|
||||
WindowState* state = (WindowState*) screen->internal;
|
||||
|
||||
XPutImage(
|
||||
dpy,
|
||||
state->window,
|
||||
state->graphics_ctx,
|
||||
state->image,
|
||||
0, 0, 0, 0,
|
||||
state->width,
|
||||
state->height
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static void handle_event(WindowState* state) {
|
||||
static void handle_event(struct Screen* screen) {
|
||||
XEvent event;
|
||||
XNextEvent(dpy, &event);
|
||||
|
||||
switch(event.type) {
|
||||
|
||||
case KeyPress: {
|
||||
XKeyEvent xkpe = event.xkey;
|
||||
uint32_t code = xkpe.keycode - dpy->min_keycode;
|
||||
|
@ -185,9 +273,8 @@ static void handle_event(WindowState* state) {
|
|||
|
||||
case ConfigureNotify: {
|
||||
XConfigureEvent xce = event.xconfigure;
|
||||
state->width = xce.width;
|
||||
state->height = xce.height;
|
||||
|
||||
if (xce.width != screen->swapchain.width || xce.height != screen->swapchain.height)
|
||||
recreate_swapchain(xce.width, xce.height, bit_depth, &screen->swapchain, (WindowState*) screen->internal);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -196,13 +283,9 @@ static void handle_event(WindowState* state) {
|
|||
}
|
||||
|
||||
bool poll_screen(struct Screen* screen) {
|
||||
|
||||
draw_screen(screen);
|
||||
|
||||
WindowState* state = (WindowState*) screen->internal;
|
||||
|
||||
while (XPending(dpy))
|
||||
handle_event(state);
|
||||
handle_event(screen);
|
||||
|
||||
update_delta(screen);
|
||||
return true;
|
||||
|
@ -211,10 +294,9 @@ bool poll_screen(struct Screen* screen) {
|
|||
void free_screen(struct Screen* screen) {
|
||||
WindowState* state = (WindowState*) screen->internal;
|
||||
|
||||
pthread_exit(&state->update_thread);
|
||||
XUnmapWindow(dpy, state->window);
|
||||
XFreePixmap(dpy, state->pixel_map);
|
||||
XDestroyImage(state->image);
|
||||
XFreeGC(dpy, state->graphics_ctx);
|
||||
free_swapchain(screen->swapchain, state);
|
||||
XDestroyWindow(dpy, state->window);
|
||||
free(screen->internal);
|
||||
|
||||
|
|
21
src/screen.h
21
src/screen.h
|
@ -1,13 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
// #define _POSIX_C_SOURCE 200809L
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
|
||||
struct Screen {
|
||||
typedef struct {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint32_t* pixels;
|
||||
uint8_t image_count; // amount of frames in flight
|
||||
uint8_t image_front; // image being drawn to screen
|
||||
uint8_t image_recent; // last image that finished drawing
|
||||
uint8_t image_current; // current image being drawn
|
||||
pthread_mutex_t lock;
|
||||
uint32_t** images;
|
||||
} Swapchain;
|
||||
|
||||
void swapchain_next(Swapchain* swapchain);
|
||||
void swapchain_submit(Swapchain* swapchain);
|
||||
|
||||
struct Screen {
|
||||
Swapchain swapchain;
|
||||
float delta;
|
||||
void* internal;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue