some work on x11 ext

This commit is contained in:
veclavtlica
2026-10-13 04:30:06 +03:00
parent 964e623644
commit 5789cafd4e
13 changed files with 262 additions and 144 deletions
+1 -1
View File
@@ -71,6 +71,6 @@ bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) {
return NULL;
}
void com_std_exit(uint32_t status) { exit(status); }
void com_std_exit(int32_t status) { exit(status); }
void com_std_close(com_std_fd fd) { fclose(fd); }
+1 -1
View File
@@ -101,7 +101,7 @@ inline bool com_std_connect(com_std_fd fd, bool isnetwork,
return NULL;
}
inline void com_std_exit(uint32_t status) {
inline void com_std_exit(int32_t status) {
__asm__ volatile("syscall" : : "a"(60), "D"(status) : "rcx", "r11", "memory");
__builtin_unreachable();
}
+1 -1
View File
@@ -101,7 +101,7 @@ inline bool com_std_connect(com_std_fd fd, bool isnetwork,
return NULL;
}
inline void com_std_exit(uint32_t status) {
inline void com_std_exit(int32_t status) {
__asm__ volatile("int $0x80" : : "a"(1), "b"(status) : "memory", "cc");
__builtin_unreachable();
}
+2
View File
@@ -12,3 +12,5 @@ void *com_std_alloc(void *ptr, size_t size) { return NULL; }
double com_std_sqrt(double v) { return __builtin_sqrt(v); }
double com_std_fabs(double v) { return __builtin_fabs(v); }
double com_std_sin(double v) { return __builtin_sin(v); }
double com_std_cos(double v) { return __builtin_cos(v); }
+22 -17
View File
@@ -24,23 +24,28 @@ size_t strlen(char const *s) {
return p - s;
}
double com_std_sin(double v) {
double result;
__asm__ __volatile__("fldl %1\n\t"
"fsin\n\t"
"fstpl %0"
: "=g"(result)
: "m"(v)
: "st", "st(1)");
return result;
double sin(double v) {
double r;
__asm__ __volatile__("fsin" : "=t"(r) : "0"(v));
return r;
}
double com_std_cos(double v) {
double result;
__asm__ __volatile__("fldl %1\n\t"
"fcos\n\t"
"fstpl %0"
: "=g"(result)
: "m"(v));
return result;
double cos(double v) {
double r;
__asm__ __volatile__("fcos" : "=t"(r) : "0"(v));
return r;
}
void sincos(double v, double *s, double *c) {
double sv, cv;
__asm__ __volatile__("fsincos" : "=t"(cv), "=u"(sv) : "0"(v));
*s = sv;
*c = cv;
}
double sqrt(double v) {
double r;
__asm__ volatile("sqrtss %1, %0" : "=x"(r) : "x"(v));
return r;
}
+1 -1
View File
@@ -37,7 +37,7 @@ typedef struct com_buf {
struct com_buf *p_v = (struct com_buf *)&p_v##_buf; \
p_v->cap = (p_c); \
p_v->flags = p_f | COM_BUF_STACK; \
p_v->typesz = sizeof(p_t);
p_v->typesz = sizeof(p_t)
#define com_buf_index_as(p_t, p_v, p_i) \
(p_t *)(&(p_v)->data[sizeof(p_t) * (p_i)])
+2 -6
View File
@@ -57,12 +57,7 @@ static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_pnt_t *out) {
mask ^= COM_GEM_VERTEX_CLIPPED_X;
if (a.a[1] < -a.a[2] || a.a[1] > a.a[2])
mask ^= COM_GEM_VERTEX_CLIPPED_Y;
// out->a[0] = com_fix_mul((com_fix_div(a.a[0], a.a[2]) + COM_FIX_FRACUNIT) >>
// 1,
// COM_CFG_WIDTH * COM_FIX_FRACUNIT);
// out->a[1] = com_fix_mul((com_fix_div(a.a[1], a.a[2]) + COM_FIX_FRACUNIT) >>
// 1,
// COM_CFG_HEIGHT * COM_FIX_FRACUNIT);
out->a[0] = (com_fix_mul(com_fix_div(a.a[0], a.a[2]),
COM_CFG_WIDTH * COM_FIX_FRACUNIT) >>
COM_FIX_FRACBITS) +
@@ -71,6 +66,7 @@ static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_pnt_t *out) {
COM_CFG_HEIGHT * COM_FIX_FRACUNIT) >>
COM_FIX_FRACBITS) +
(COM_CFG_HEIGHT / 2);
return mask;
}
+2 -1
View File
@@ -26,12 +26,13 @@ typedef void *com_std_fd;
#define COM_STD_OPEN_WRITE (1 << 1)
com_std_fd com_std_open(char const *path, uint32_t flags);
bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes);
/* TODO: Return unit32_t, error on ZERO? Separate EOF check? */
int32_t com_std_read(com_std_fd fd, void *data, uint32_t upto);
bool com_std_has_data(com_std_fd);
bool com_std_sfwd(com_std_fd fd, uint32_t bytes);
com_std_fd com_std_socket(bool isnetwork);
bool com_std_connect(com_std_fd sock, bool isnetwork, char const *address);
void com_std_exit(uint32_t status) __attribute__((noreturn));
void com_std_exit(int32_t status) __attribute__((noreturn));
void com_std_close(com_std_fd fd);
/* TODO: Remove, use buffer semantics instead. */
+3 -3
View File
@@ -47,9 +47,9 @@ static inline int32_t com_str_ext_find_char(char const *s, char ch) {
/* Returns true if string 'a' is prefixed by 'b'. */
static inline bool com_str_ext_prefixed(char const *__restrict a,
struct com_str prefix) {
uint32_t n = prefix.len;
char *b = prefix.data;
struct com_str const *prefix) {
uint32_t n = prefix->len;
char *b = prefix->data;
while (n && *a && (*a == *b)) {
++a;
++b;
+30 -5
View File
@@ -4,6 +4,7 @@
#include "bits.h"
#include "fix.h"
#include "mat.h"
#include "std.h"
#include <stdbool.h>
@@ -18,7 +19,7 @@
static bool com_test_fix(void) {
bool anyfail = false;
{
double max_sqrt_deviation = 0.0f;
double max_sqrt_deviation = 0.0;
com_fix_t sqrt_accumulator = 0;
com_fix_t sqrt_test_step = COM_FIX_FRACUNIT >> 2; /* Quarter step */
for (int i = 0; i < COM_FIX_FRACUNIT << 1; ++i) {
@@ -34,7 +35,7 @@ static bool com_test_fix(void) {
}
{
double max_sin_deviation = 0.0f;
double max_sin_deviation = 0.0;
com_fix_t sin_accumulator = -COM_FIX_PI * 4;
com_fix_t sin_test_step = (COM_FIX_PI << 1) >> 10;
for (int i = 0; i < 1024 * 32; ++i) {
@@ -50,7 +51,7 @@ static bool com_test_fix(void) {
}
{
double max_cos_deviation = 0.0f;
double max_cos_deviation = 0.0;
com_fix_t cos_accumulator = -COM_FIX_PI * 4;
com_fix_t cos_test_step = (COM_FIX_PI << 1) >> 10;
for (int i = 0; i < 1024 * 32; ++i) {
@@ -66,8 +67,8 @@ static bool com_test_fix(void) {
}
{
double max_sin_deviation = 0.0f;
double max_cos_deviation = 0.0f;
double max_sin_deviation = 0.0;
double max_cos_deviation = 0.0;
com_fix_t sincos_accumulator = -COM_FIX_PI * 4;
com_fix_t sincos_test_step = (COM_FIX_PI << 1) >> 10;
for (int i = 0; i < 1024 * 32; ++i) {
@@ -105,6 +106,26 @@ static bool com_test_bits(void) {
return anyfail;
}
static bool com_test_mat(void) {
bool anyfail = false;
com_mat_t const m0 = com_mat_identity();
com_mat_t m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
for (int i = 0; i < 16; ++i)
m1.a[i] *= COM_FIX_FRACUNIT;
com_mat_t const mul = com_mat_mul(m1, m0);
com_mat_t const mul_reordered = com_mat_mul_reodered(com_mat_reoder(m1), m0);
for (int i = 0; i < 16; ++i) {
TEST(mul.a[i] == mul_reordered.a[i]);
if (mul.a[i] != mul_reordered.a[i])
break;
}
return anyfail;
}
static bool com_test_run(void) {
bool anyfail = false;
if (com_test_fix()) {
@@ -115,6 +136,10 @@ static bool com_test_run(void) {
com_std_print('c', "com_bits tests failed!");
anyfail = true;
}
if (com_test_mat()) {
com_std_print('c', "com_mat tests failed!");
anyfail = true;
}
return !anyfail;
}
+128 -53
View File
@@ -10,7 +10,6 @@
#include "../../Common/cfg.h"
#include "../../Common/def.h"
#include "../../Common/lzw.h"
#include "../../Common/mat.h"
#include "../../Common/std.h"
#include "../../Common/str.h"
#include "../../Common/test.h"
@@ -53,13 +52,13 @@ static struct {
uint32_t resource_id_mask;
} plr_x11_connection;
bool quited = false;
bool fileread(void *ctx, char *into, uint32_t bytes) {
static bool fileread(void *ctx, char *into, uint32_t bytes) {
return com_std_read(ctx, into, bytes) == bytes;
}
bool fileskip(void *ctx, uint32_t bytes) { return com_std_sfwd(ctx, bytes); }
static bool fileskip(void *ctx, uint32_t bytes) {
return com_std_sfwd(ctx, bytes);
}
#define AUTH_ENTRY_MAGIC_COOKIE "MIT-MAGIC-COOKIE-1"
@@ -145,6 +144,8 @@ static bool plr_x11_handshake(com_std_fd xfd,
if (response.success != 1)
return false;
/* https://xorg.freedesktop.org/archive/X11R7.7-RC1/doc/xproto/x11protocol.html#server_response
*/
struct {
uint32_t release_number;
uint32_t resource_id_base;
@@ -175,8 +176,13 @@ static bool plr_x11_handshake(com_std_fd xfd,
return false;
if (!com_std_read(xfd, scratch, 8 * dyn_response.formats_count))
return false;
/* Read first and hope it is what we need. */
if (!com_std_read(xfd, &plr_x11_root_screen, sizeof plr_x11_root_screen))
return false;
/* Then drop all the things that proceed, such as other screens and their
* visual profiles. */
while (com_std_has_data(xfd))
com_std_read(xfd, scratch, sizeof scratch);
plr_x11_connection.resource_id_base = dyn_response.resource_id_base;
plr_x11_connection.resource_id_mask = dyn_response.resource_id_mask;
@@ -184,9 +190,7 @@ static bool plr_x11_handshake(com_std_fd xfd,
return true;
}
/* TODO: Instead have a poll_events function instead. */
static inline bool plr_x11_poll_errors(com_std_fd xfd) {
union {
union plr_x11_response {
struct {
uint8_t type;
uint8_t errcode;
@@ -203,32 +207,49 @@ static inline bool plr_x11_poll_errors(com_std_fd xfd) {
uint32_t length;
char pad[24];
} __attribute__((packed)) reply;
} response;
};
while (com_std_has_data(xfd)) {
if (!com_std_read(xfd, &response, sizeof response))
static bool plr_x11_poll(com_std_fd xfd, bool wait,
union plr_x11_response *response) {
if (!wait && !com_std_has_data(xfd))
return false;
/* Exhaust variable length data of reply. */
if (response.reply.type == 1) {
char buf[1024];
com_std_assert(response.reply.length * 4 <= sizeof buf);
if (!com_std_read(xfd, &buf, response.reply.length * 4))
return false;
com_std_read(xfd, response, sizeof(union plr_x11_response));
return true;
}
if (response.reply.type == 0 && response.error.errcode != 0) {
static bool plr_x11_poll_reply(com_std_fd xfd, uint16_t seqid,
union plr_x11_response *response) {
while (plr_x11_poll(xfd, true, response)) {
/* Wait for match. */
if (response->reply.type == 1 && response->reply.sequenceid == seqid)
break;
/* Errors could be encountered here, report along the way. */
if (response->reply.type == 0) {
com_std_print('c', "X11 error code=", 'u', response->error.errcode, 'c',
" for seqid=", 'u', response->error.sequenceid);
}
}
return true;
}
/* TODO: Instead we should poll for events, errors are only byproduct. */
static bool plr_x11_poll_errors(com_std_fd xfd) {
union plr_x11_response response;
while (plr_x11_poll(xfd, false, &response)) {
/* There should be no replies unhandled. */
/* TODO: Write down encountered events. */
if (response.reply.type == 1)
return false;
if (response.reply.type == 0)
com_std_print('c', "X11 error code=", 'u', response.error.errcode, 'c',
" for seqid=", 'u', response.error.sequenceid);
/* This means X11 closed the connection. */
// if (response.error.errcode == 0)
// return false;
}
/* TODO: Save polled events, as they might be used later. */
};
return true;
}
@@ -322,6 +343,7 @@ static uint32_t plr_x11_create_window(com_std_fd xfd) {
}
static bool plr_x11_show_window(com_std_fd xfd, uint32_t window_id) {
uint32_t const seq = plr_x11_next_seqid();
struct {
uint8_t opcode;
uint8_t pad1;
@@ -361,16 +383,82 @@ static uint32_t plr_x11_create_pixmap(com_std_fd xfd, uint32_t window_id) {
return pixmap_id;
}
/* Returns opcode for given extension. */
static uint8_t plr_x11_query_extension(com_std_fd xfd, com_str const *ext) {
uint32_t const seq = plr_x11_next_seqid();
uint16_t const pad = com_bits_nalign(ext->len, 4);
struct {
uint8_t opcode;
uint8_t pad1;
uint16_t request_length;
uint16_t name_length;
uint16_t pad2;
} __attribute__((packed)) request = {
.opcode = 98,
.request_length = sizeof request / 4 + pad / 4,
.name_length = ext->len,
};
if (!com_std_write(xfd, &request, sizeof request))
return 0;
if (!com_std_write(xfd, ext->data, ext->len))
return 0;
if ((pad - ext->len) && !com_std_write(xfd, ext->data, pad - ext->len))
return 0;
union plr_x11_response response;
plr_x11_poll_reply(xfd, seq, &response);
return response.reply.pad[1];
}
/*
This is needed as base X11 doesn't allow passing more than 16bit x 4bytes.
https://xorg.freedesktop.org/archive/current/doc/bigreqsproto/bigreq.html
*/
static bool plr_x11_enable_big_requests(com_std_fd xfd) {
static com_str bigreqext = com_str_lit("BIG-REQUESTS");
uint8_t const opcode = plr_x11_query_extension(xfd, &bigreqext);
/* Request the thing. */
struct {
uint8_t opcode;
uint8_t micode;
uint16_t request_length;
} __attribute__((packed)) request = {
.opcode = opcode,
.request_length = sizeof request / 4,
};
uint32_t const seq = plr_x11_next_seqid();
if (!com_std_write(xfd, &request, sizeof request))
return 0;
/* Read the response. */
union plr_x11_response response;
plr_x11_poll_reply(xfd, seq, &response);
uint32_t const limit = *(uint32_t *)response.reply.pad;
com_std_print('c', "Request limit: ", 'u', limit);
if (limit < COM_CFG_FBSIZE) {
com_std_print('c', "Big request can't accommodate for framebuffer.");
return false;
}
return true;
}
static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
uint32_t pixmap_id,
uint8_t pixels[COM_CFG_FBSIZE]) {
uint32_t const seq = plr_x11_next_seqid();
uint32_t const padded = com_bits_nalign(COM_CFG_FBSIZE, 4);
uint32_t const seq = plr_x11_next_seqid();
struct {
uint8_t opcode;
uint8_t format;
uint16_t request_length;
uint16_t bigreq; /* Marked zero so that 32bit could be used. */
uint32_t request_length;
uint32_t drawable_id;
uint32_t gc_id;
uint16_t width;
@@ -398,8 +486,8 @@ static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
if (!com_std_write(xfd, pixels, COM_CFG_FBSIZE))
return false;
/* Use request memory for pad, it doesn't matter what we write. */
uint32_t const padfinal = padded - COM_CFG_FBSIZE;
if (padfinal && !com_std_write(xfd, &pixels, padfinal))
if ((padded - COM_CFG_FBSIZE) &&
!com_std_write(xfd, &pixels, padded - COM_CFG_FBSIZE))
return false;
return true;
}
@@ -418,7 +506,7 @@ static bool plr_x11_establish_connection(com_std_fd xfd, int argc,
char const *xauthpath = NULL;
for (char const *const *envp = &argv[argc + 1]; *envp != NULL; ++envp) {
static const struct com_str xauthlit = com_str_lit("XAUTHORITY=");
if (com_str_ext_prefixed(*envp, xauthlit)) {
if (com_str_ext_prefixed(*envp, &xauthlit)) {
xauthpath = &((*envp)[xauthlit.len]);
break;
}
@@ -473,29 +561,11 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
com_lzw_free_table(&table);
com_std_assert(test);
com_mat_t m0 = com_mat_identity();
com_mat_t m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
for (int i = 0; i < 16; ++i)
m1.a[i] *= COM_FIX_FRACUNIT;
com_mat_t t0 = com_mat_mul(m1, m0);
com_mat_t t1 = com_mat_mul_reodered(com_mat_reoder(m1), m0);
com_std_print('f', t0.a[4]);
com_std_print('f', t1.a[4]);
// com_vec_t v0 = com_mat_vec_project(com_mat_reoder(m0), com_vec_identity());
// com_fix_print(v0.a[0]);
/* TODO: Move to separate executable maybe? */
#ifndef NDEBUG
// com_test_run();
com_test_run();
#endif
// com_fix_run_tests();
// com_fix_run_bench();
// com_mat_run_bench();
/* TODO: Move init to separate func. */
/* Open X11 socket for communication. */
com_std_fd const xfd = com_std_socket(false);
if (!xfd) {
@@ -513,6 +583,11 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
return -1;
}
if (!plr_x11_enable_big_requests(xfd)) {
com_std_print('c', "Big requests unsupported for your X11");
return -1;
}
uint32_t const gc = plr_x11_create_graphical_context(xfd);
if (!gc) {
com_std_print('c', "Failure to initialize X11");
@@ -629,10 +704,10 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
uint8_t *fbm = plr_draw_get_pixel_buffer();
plr_draw_screen(fbm);
// if (!plr_x11_put_framebuffer(xfd, gc, fb, fbm)) {
// com_std_print('c', "Failure to drive X11");
// return -1;
// }
if (!plr_x11_put_framebuffer(xfd, gc, fb, fbm)) {
com_std_print('c', "Failure to drive X11");
return -1;
}
if (!plr_x11_show_window(xfd, win)) {
com_std_print('c', "Failure to drive X11");
+23 -10
View File
@@ -1,27 +1,37 @@
CC = clang
CC ?= clang
RELEASE ?= 0 # Optimize.
DEBUG ?= 1 # Emit debug info.
SQUEEZE ?= 0 # Nuclear option to save space.
BITS ?= 64
RUN ?= 0
ISCLANG = 1
CFLAGS = -Wall -std=gnu99 -ffast-math -fno-ident -fvisibility=hidden
# Set cosmopolitan toolchain.
ifeq ($(MAKECMDGOALS),cosmo)
ISCLANG = 0
CC = ./Cosmo/bin/cosmocc -mclang
ifeq ($(DEBUG), 1)
CFLAGS += -mdbg
else
CFLAGS += -mtiny
endif
endif
CFLAGS = -Wall -std=gnu99 -ffast-math -fno-ident -fvisibility=hidden
ifeq ($(ISCLANG), 1)
CFLAGS = -flto=thin -fuse-ld=lld
# Provide LTO where it's applicable.
ifeq ($(CC),clang)
ISCLANG = 1
CFLAGS += -flto=thin -fuse-ld=lld
else
ifneq ($(MAKECMDGOALS),cosmo)
CFLAGS += -flto
endif
endif
# Linux specific options.
ifeq ($(MAKECMDGOALS),linux)
CFLAGS += -fno-pic -fno-pie
ifeq ($(RELEASE), 1)
CFLAGS += -Wl,--ignore-data-address-equality -Wl,--ignore-function-address-equality \
# CFLAGS += -Wl,--ignore-data-address-equality -Wl,--ignore-function-address-equality \
-Wl,--optimize-bb-jumps
endif
ifeq ($(SQUEEZE), 1)
@@ -37,11 +47,15 @@ ifeq ($(MAKECMDGOALS),linux)
CFLAGS += -m32 -msse2
endif
endif
# WASM specific options.
ifeq ($(MAKECMDGOALS),wasm)
ifeq ($(RELEASE), 1)
CFLAGS += -Wl,--compress-relocations
endif
endif
# Separate debug and release switches.
ifeq ($(DEBUG), 1)
CFLAGS += -g3
else
@@ -50,7 +64,7 @@ endif
ifeq ($(RELEASE), 1)
CFLAGS += -O3 -fmerge-all-constants -Wl,-O3 \
-ffunction-sections -fdata-sections -Wl,--gc-sections
ifeq ($(ISCLANG), 1)
ifeq ($(CC),clang)
CFLAGS += -Wl,-mllvm,--vectorize-slp=true \
-Wl,-mllvm,--enable-gvn-hoist=true
endif
@@ -66,8 +80,7 @@ wasm:
$(CC) -o player.wasm ./amalgam.c $(CFLAGS)
# todo: Add -mtiny for release without debug
cosmo: CC = ./Cosmo/bin/cosmocc
cosmo: CFLAGS += -I /usr/include/X11 -mclang
cosmo: CFLAGS += -I /usr/include/X11
cosmo: ./amalgam.c
$(CC) $(CFLAGS) -o ./Out/Cosmo/player $^
ifeq ($(RUN), 1)
+27 -26
View File
@@ -29,36 +29,37 @@ com_def_export_sym("plr_draw_screen") void plr_draw_screen(
}
}
com_mat_t proj = com_mat_perspective(COM_CFG_WIDTH, COM_CFG_HEIGHT, 1,
100 * COM_FIX_FRACUNIT, COM_FIX_PIHALF);
com_mat_t view = com_mat_look_at(com_vec_from(0, 0, 0),
com_vec_from(0, COM_FIX_FRACUNIT, 0),
com_vec_from(-COM_FIX_FRACUNIT, 0, 0));
com_mat_t mvp = com_mat_reoder(com_mat_mul(proj, view));
// com_mat_t proj = com_mat_perspective(COM_CFG_WIDTH, COM_CFG_HEIGHT, 1,
// 100 * COM_FIX_FRACUNIT,
// COM_FIX_PIHALF);
// com_mat_t view = com_mat_look_at(com_vec_from(0, 0, 0),
// com_vec_from(0, COM_FIX_FRACUNIT, 0),
// com_vec_from(-COM_FIX_FRACUNIT, 0, 0));
// com_mat_t mvp = com_mat_reoder(com_mat_mul(proj, view));
com_vec_t v0 = com_vec_from(0 * COM_FIX_FRACUNIT, 0, 1 * COM_FIX_FRACUNIT);
com_vec_t v1 = com_vec_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT,
1 * COM_FIX_FRACUNIT);
com_vec_t v2 = com_vec_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT,
1 * COM_FIX_FRACUNIT);
com_vec_t v3 = com_vec_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT,
-1 * COM_FIX_FRACUNIT);
// com_vec_t v0 = com_vec_from(0 * COM_FIX_FRACUNIT, 0, 1 * COM_FIX_FRACUNIT);
// com_vec_t v1 = com_vec_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT,
// 1 * COM_FIX_FRACUNIT);
// com_vec_t v2 = com_vec_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT,
// 1 * COM_FIX_FRACUNIT);
// com_vec_t v3 = com_vec_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT,
// -1 * COM_FIX_FRACUNIT);
com_pnt_t uv0 = com_pnt_from(0 * COM_FIX_FRACUNIT, 0 * COM_FIX_FRACUNIT);
com_pnt_t uv1 = com_pnt_from(1 * COM_FIX_FRACUNIT, 0 * COM_FIX_FRACUNIT);
com_pnt_t uv2 = com_pnt_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT);
com_pnt_t uv3 = com_pnt_from(0 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT);
// com_pnt_t uv0 = com_pnt_from(0 * COM_FIX_FRACUNIT, 0 * COM_FIX_FRACUNIT);
// com_pnt_t uv1 = com_pnt_from(1 * COM_FIX_FRACUNIT, 0 * COM_FIX_FRACUNIT);
// com_pnt_t uv2 = com_pnt_from(1 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT);
// com_pnt_t uv3 = com_pnt_from(0 * COM_FIX_FRACUNIT, 1 * COM_FIX_FRACUNIT);
com_vec_t c0 = com_gem_vec_project_clip(mvp, v0);
com_vec_t c1 = com_gem_vec_project_clip(mvp, v1);
com_vec_t c2 = com_gem_vec_project_clip(mvp, v2);
com_vec_t c3 = com_gem_vec_project_clip(mvp, v3);
// com_vec_t c0 = com_gem_vec_project_clip(mvp, v0);
// com_vec_t c1 = com_gem_vec_project_clip(mvp, v1);
// com_vec_t c2 = com_gem_vec_project_clip(mvp, v2);
// com_vec_t c3 = com_gem_vec_project_clip(mvp, v3);
com_pnt_t p0, p1, p2, p3;
uint8_t cc0 = com_gem_clip_vis_project(c0, &p0);
uint8_t cc1 = com_gem_clip_vis_project(c1, &p1);
uint8_t cc2 = com_gem_clip_vis_project(c2, &p2);
uint8_t cc3 = com_gem_clip_vis_project(c3, &p3);
// com_pnt_t p0, p1, p2, p3;
// uint8_t cc0 = com_gem_clip_vis_project(c0, &p0);
// uint8_t cc1 = com_gem_clip_vis_project(c1, &p1);
// uint8_t cc2 = com_gem_clip_vis_project(c2, &p2);
// uint8_t cc3 = com_gem_clip_vis_project(c3, &p3);
// com_std_printf("%i, %i\n", p0.a[0], p0.a[1]);
// com_std_printf("%i, %i\n", p1.a[0], p1.a[1]);