/* Geometry rendering. */ #ifndef COM_GEM_H #define COM_GEM_H #include "mat.h" #include /* Projects vertex position to a clip space via reordered row-major MVP matrix. It skips calculation of z depth component, as we assume to never use it. Instead, 3rd returned component is w value, for future projection. We must never render from inside geometry, as it will break no Z clipping assumption (see com_gem_clip_vis_project()). */ static inline com_vec_t com_gem_vec_project_clip(com_mat_t a, com_vec_t b) { com_vec_t result; #define CASE(m_c, m_n) \ result.a[m_c] = (((int64_t)a.a[m_n * 4 + 0] * b.s.x) + \ ((int64_t)a.a[m_n * 4 + 1] * b.s.y) + \ ((int64_t)a.a[m_n * 4 + 2] * b.s.z) + a.a[m_n * 4 + 3]) >> \ COM_FIX_FRACBITS; CASE(0, 0); CASE(1, 1); CASE(2, 3); #undef CASE return result; } /* TODO: Move to separate render-specific file. */ /* TODO: If we clip test bounding volume of a model first we can skip * all clipping whatsoever, which might hold true more often, than the cost of * testing the volume. */ #define COM_GEM_VERTEX_UNCLIPPED (0 << 0) #define COM_GEM_VERTEX_CLIPPED_X (1 << 0) #define COM_GEM_VERTEX_CLIPPED_Y (1 << 1) /* Attempt to project clip space vertex to NDC, reporting which component lies * outside of view. Bit test against those per component. This is needed for * determining new view-lying clipped triangles. */ static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_vec_t *out) { uint8_t mask; if (a.s.x < -a.s.z || a.s.x > a.s.z) mask ^= COM_GEM_VERTEX_CLIPPED_X; if (a.s.y < -a.s.z || a.s.y > a.s.z) mask ^= COM_GEM_VERTEX_CLIPPED_Y; out->a[0] = com_fix_div(a.a[0], a.a[2]); out->a[1] = com_fix_div(a.a[1], a.a[2]); return mask; } #endif