Files
asteroids/renderer.c
2025-10-13 16:22:10 +01:00

144 lines
3.1 KiB
C

#include "renderer.h"
#include "fb.h"
#include <assert.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <xf86drm.h>
#define MAX_VERTS_PER_DRAW 8U
static int drm_fd;
static drmModeConnector *conn;
static drmModeCrtc *crtc;
static uint32_t conn_id;
static fb_info_t fbs[2];
static int front, back;
static uint32_t width, height;
static mat3_t view;
static vec3_t vert_buf[MAX_VERTS_PER_DRAW];
static void page_flip_handler(int, unsigned, unsigned, unsigned, void *)
{
}
static void set_pixel(uint32_t x, uint32_t y)
{
x %= width;
y %= height;
const uint32_t offset = y * (fbs[back].pitch / 4) + x;
fbs[back].buf[offset] = 0xff'ff'ff;
}
static void draw_line(vec3_t v1, vec3_t v2)
{
const float delta_x = v2.x - v1.x;
const float delta_y = v2.y - v1.y;
const float step = fmaxf(fabsf(delta_x), fabsf(delta_y));
if (step != 0.0) {
const float step_x = delta_x / step;
const float step_y = delta_y / step;
for (unsigned i = 0; i <= step; ++i)
set_pixel(roundf(v1.x + i * step_x), roundf(v1.y + i * step_y));
} else {
set_pixel(roundf(v1.x), roundf(v1.y));
}
}
renderer_params_t renderer_init()
{
drm_fd = open("/dev/dri/card1", O_RDWR | O_CLOEXEC);
assert(drm_fd != -1);
drmModeRes *res = drmModeGetResources(drm_fd);
assert(res != nullptr);
conn = drmModeGetConnector(drm_fd, res->connectors[0]);
assert(conn != nullptr);
drmModeModeInfo mode = conn->modes[0];
conn_id = conn->connector_id;
fbs[0] = fb_init(drm_fd, mode);
fbs[1] = fb_init(drm_fd, mode);
front = 0;
back = 1;
const int err = drmModeSetCrtc(
drm_fd, res->crtcs[0], fbs[front].id, 0, 0, &conn_id, 1, &mode);
assert(err == 0);
crtc = drmModeGetCrtc(drm_fd, res->crtcs[0]);
assert(crtc != nullptr);
drmModeFreeResources(res);
width = mode.hdisplay;
height = mode.vdisplay;
const float aspect = (float)width / (float)height;
const float scale = (float)height / 2.0f;
view = (mat3_t) {
{ scale, 0, 0 },
{ 0, -scale, 0 },
{ aspect * scale, scale, 1 },
};
return (renderer_params_t) {
.drm_fd = drm_fd,
.aspect = aspect,
};
}
void renderer_cleanup()
{
drmModeSetCrtc(
drm_fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &conn_id,
1, &crtc->mode);
fb_cleanup(drm_fd, fbs[0]);
fb_cleanup(drm_fd, fbs[1]);
drmModeFreeCrtc(crtc);
drmModeFreeConnector(conn);
close(drm_fd);
}
void renderer_handle()
{
drmEventContext ev = {
.version = DRM_EVENT_CONTEXT_VERSION,
.page_flip_handler = page_flip_handler,
};
drmHandleEvent(drm_fd, &ev);
}
void renderer_clear()
{
memset(fbs[back].buf, 0, fbs[back].size);
}
void renderer_swap()
{
const int err = drmModePageFlip(
drm_fd, crtc->crtc_id, fbs[back].id, DRM_MODE_PAGE_FLIP_EVENT,
nullptr);
assert(err == 0);
front = (front + 1) & 1;
back = (back + 1) & 1;
}
void renderer_draw(const vec2_t *vs, unsigned count)
{
assert(count < MAX_VERTS_PER_DRAW);
for (unsigned i = 0; i < count; ++i)
vert_buf[i] = mat3_mul_vec3(view, vec2_extend(vs[i]));
for (unsigned i = 1; i < count; ++i)
draw_line(vert_buf[i - 1], vert_buf[i]);
draw_line(vert_buf[count - 1], vert_buf[0]);
}