194 lines
4.2 KiB
C
194 lines
4.2 KiB
C
#include "renderer.h"
|
|
|
|
#include "fb.h"
|
|
|
|
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <xf86drm.h>
|
|
|
|
float aspect;
|
|
|
|
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 bool wrap;
|
|
|
|
static vec3_t vert_buf[MAX_VERTS];
|
|
|
|
static void page_flip_handler(int, unsigned, unsigned, unsigned, void *)
|
|
{
|
|
}
|
|
|
|
static void set_pixel(uint32_t x, uint32_t y)
|
|
{
|
|
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)
|
|
{
|
|
v1.x /= v1.z;
|
|
v1.y /= v1.z;
|
|
v1.z = 1;
|
|
v2.x /= v2.z;
|
|
v2.y /= v2.z;
|
|
v2.z = 1;
|
|
|
|
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) {
|
|
float x = roundf(v1.x + i * step_x);
|
|
float y = roundf(v1.y + i * step_y);
|
|
|
|
if (wrap) {
|
|
if (x >= width)
|
|
x -= width;
|
|
else if (x < 0)
|
|
x += width;
|
|
if (y >= height)
|
|
y -= height;
|
|
else if (y < 0)
|
|
y += height;
|
|
} else if (x >= width || x < 0 || y >= height || y < 0) {
|
|
continue;
|
|
}
|
|
|
|
set_pixel(x, y);
|
|
}
|
|
} else {
|
|
set_pixel(roundf(v1.x), roundf(v1.y));
|
|
}
|
|
}
|
|
|
|
int 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;
|
|
|
|
wrap = true;
|
|
|
|
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 drm_fd;
|
|
}
|
|
|
|
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_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_set_wrap(bool enable)
|
|
{
|
|
wrap = enable;
|
|
}
|
|
|
|
void renderer_clear()
|
|
{
|
|
memset(fbs[back].buf, 0, fbs[back].size);
|
|
}
|
|
|
|
void renderer_clear_rect(vec2_t centre, vec2_t size)
|
|
{
|
|
const vec2_t tl_world = { centre.x - size.x / 2, centre.y + size.y / 2 };
|
|
const vec2_t br_world = { centre.x + size.x / 2, centre.y - size.y / 2 };
|
|
const vec3_t tl = mat3_mul_vec3(view, vec2_extend(tl_world));
|
|
const vec3_t br = mat3_mul_vec3(view, vec2_extend(br_world));
|
|
|
|
const unsigned width = (unsigned)roundf(br.x / br.z - tl.x / tl.z);
|
|
const unsigned x1 = (unsigned)roundf(tl.x / tl.z);
|
|
const unsigned y1 = (unsigned)roundf(tl.y / tl.z);
|
|
const unsigned y2 = (unsigned)roundf(br.y / br.z);
|
|
|
|
for (unsigned y = y1; y < y2; ++y) {
|
|
uint32_t *row = fbs[back].buf + y * (fbs[back].pitch / 4) + x1;
|
|
memset(row, 0, width * sizeof(uint32_t));
|
|
}
|
|
}
|
|
|
|
void renderer_draw(
|
|
const vec2_t *vs, unsigned count, mat3_t model, bool connect)
|
|
{
|
|
mat3_t transform = mat3_mul_mat3(view, model);
|
|
assert(count < MAX_VERTS);
|
|
|
|
for (unsigned i = 0; i < count; ++i)
|
|
vert_buf[i] = mat3_mul_vec3(transform, vec2_extend(vs[i]));
|
|
for (unsigned i = 1; i < count; ++i)
|
|
draw_line(vert_buf[i - 1], vert_buf[i]);
|
|
if (connect)
|
|
draw_line(vert_buf[count - 1], vert_buf[0]);
|
|
}
|