Files
brightstone/Common/pnt.h
T
2026-10-04 11:13:07 +03:00

120 lines
3.9 KiB
C

/*
Fixed point implementation of 2 dimensional pnttors.
*/
#ifndef COM_PNT_H
#define COM_PNT_H
#include "def.h"
#include "fix.h"
#include "vec.h"
#include <stdint.h>
typedef struct {
com_def_alignedas(16) com_def_vector(com_fix_t, a, 2);
} com_pnt_t;
static inline com_pnt_t com_pnt_from(com_fix_t x, com_fix_t y) {
return (com_pnt_t){.a = {x, y}};
}
static inline com_pnt_t com_pnt_from_vec(com_vec_t a) {
return (com_pnt_t){.a = {a.a[0], a.a[1]}};
}
static inline com_pnt_t com_pnt_identity(void) {
return (com_pnt_t){.a = {
COM_FIX_FRACUNIT,
COM_FIX_FRACUNIT,
}};
}
static inline com_pnt_t com_pnt_add(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.a = {com_fix_add(a.a[0], b.a[0]), com_fix_add(a.a[1], b.a[1])}};
}
static inline com_pnt_t com_pnt_sub(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.a = {com_fix_sub(a.a[0], b.a[0]), com_fix_sub(a.a[1], b.a[1])}};
}
static inline com_pnt_t com_pnt_mul(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.a = {com_fix_mul(a.a[0], b.a[0]), com_fix_mul(a.a[1], b.a[1])}};
}
/* Note: this does not clamp for over/underflow cases */
static inline com_pnt_t com_pnt_div(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.a = {com_fix_div(a.a[0], b.a[0]), com_fix_div(a.a[1], b.a[1])}};
}
/* Scale pnttor by a fixed point number */
static inline com_pnt_t com_pnt_scl(com_pnt_t a, com_fix_t b) {
return (com_pnt_t){.a = {com_fix_mul(a.a[0], b), com_fix_mul(a.a[1], b)}};
}
static inline com_fix_t com_pnt_min(com_pnt_t a) {
return com_fix_min(a.a[0], a.a[1]);
}
static inline com_fix_t com_pnt_max(com_pnt_t a) {
return com_fix_max(a.a[0], a.a[1]);
}
/* Tests whether a point is lying right to a line produced by l0 and l1.
This assumes that l0 and l1 are in clockwise order.
Result is positive or zero if it holds true, otherwise it's negative.
This also produces area of a triangle!
Somehow this is faster than counter clockwise ordering? In case tested.
*/
static inline com_fix_t com_pnt_edge_orient(com_pnt_t l0, com_pnt_t l1,
com_pnt_t p) {
return (l0.a[0] - l1.a[0]) * (p.a[1] - l1.a[1]) -
(l0.a[1] - l1.a[1]) * (p.a[0] - l1.a[0]);
}
#define com_pnt_area(m_p0, m_p1, m_p2) (com_pnt_edge_orient(m_p0, m_p1, m_p2))
static inline com_vec_t com_pnt_edge_weight(com_pnt_t v0, com_pnt_t v1,
com_pnt_t v2, com_pnt_t p) {
return (com_vec_t){.a = {com_pnt_edge_orient(v1, v2, p),
com_pnt_edge_orient(v2, v0, p),
com_pnt_edge_orient(v0, v1, p)}};
}
/* As terms are constant over pixel steps, we can use precalculated values.
See: (l0.a[0] - l1.a[0]) and (l0.a[1] - l1.a[1])
Optimizer seems to be smart enough to figure this out already? And even more
optimal. Delete this later.
*/
static inline void com_pnt_edge_weight_calc_precomp_table(com_pnt_t v0,
com_pnt_t v1,
com_pnt_t v2,
com_pnt_t out[3]) {
out[0] = com_pnt_sub(v1, v2);
out[1] = com_pnt_sub(v2, v0);
out[2] = com_pnt_sub(v0, v1);
}
static inline com_vec_t
com_pnt_edge_weight_calc_precomp(com_pnt_t v0, com_pnt_t v1, com_pnt_t v2,
com_pnt_t p, com_pnt_t precomp[3]) {
return (com_vec_t){.a = {precomp[0].a[0] * (p.a[1] - v2.a[1]) -
precomp[0].a[1] * (p.a[0] - v2.a[0]),
precomp[1].a[0] * (p.a[1] - v0.a[1]) -
precomp[1].a[1] * (p.a[0] - v0.a[0]),
precomp[2].a[0] * (p.a[1] - v0.a[1]) -
precomp[2].a[1] * (p.a[0] - v0.a[0])}};
}
static inline void com_pnt_print(com_pnt_t a) {
com_fix_print(a.a[0]);
com_fix_print(a.a[1]);
}
#endif