/* * CS5600 University of Utah * Charles McGarvey * mcgarvey@eng.utah.edu */ #ifndef _TRI_H_ #define _TRI_H_ #include "aabb.h" #include "mat.h" #include "vert.h" /* * A triangle is a polygon of three vertices. */ struct tri { vert_t a; vert_t b; vert_t c; }; typedef struct tri tri_t; /* * Initialize a triangle. */ INLINE_MAYBE void tri_init(tri_t* t, vert_t a, vert_t b, vert_t c) { t->a = a; t->b = b; t->c = c; } /* * Create a new triangle. */ INLINE_MAYBE tri_t tri_new(vert_t a, vert_t b, vert_t c) { tri_t t; tri_init(&t, a, b, c); return t; } #define TRI_ZERO tri_new(VERT_ZERO, VERT_ZERO, VERT_ZERO) /* * Create a new triangle on the heap. */ INLINE_MAYBE tri_t* tri_alloc(vert_t a, vert_t b, vert_t c) { tri_t* t = (tri_t*)mem_alloc(sizeof(tri_t)); tri_init(t, a, b, c); return t; } /* * Apply a transformation matrix to alter the triangle geometry. */ INLINE_MAYBE tri_t tri_transform(tri_t t, mat_t m) { t.a.v = mat_apply(m, t.a.v); t.b.v = mat_apply(m, t.b.v); t.c.v = mat_apply(m, t.c.v); t.a.n.w = t.b.n.w = t.c.n.w = S(0.0); t.a.n = vec_normalize(mat_apply(m, t.a.n)); t.b.n = vec_normalize(mat_apply(m, t.b.n)); t.c.n = vec_normalize(mat_apply(m, t.c.n)); return t; } /* * Perform a homogeneous divide on the geometry. */ INLINE_MAYBE tri_t tri_homodiv(tri_t t) { t.a.v = vec_homodiv(t.a.v); t.b.v = vec_homodiv(t.b.v); t.c.v = vec_homodiv(t.c.v); return t; } /* * Calculate a normal vector. */ INLINE_MAYBE vec_t tri_normal(tri_t t) { vec_t n = vec_cross(vec_sub(t.b.v, t.a.v), vec_sub(t.c.v, t.a.v)); return n; } /* * Calculate the AABB for the triangle. */ INLINE_MAYBE aabb_t tri_aabb(tri_t t) { aabb_t b; b.min = vec_new(scal_min2(t.a.v.x, t.b.v.x, t.c.v.x), scal_min2(t.a.v.y, t.b.v.y, t.c.v.y), scal_min2(t.a.v.z, t.b.v.z, t.c.v.z)); b.max = vec_new(scal_max2(t.a.v.x, t.b.v.x, t.c.v.x), scal_max2(t.a.v.y, t.b.v.y, t.c.v.y), scal_max2(t.a.v.z, t.b.v.z, t.c.v.z)); return b; } /* * Get the barycentric coordinates of a vector against a triangle. The * returned coordinates will be a linear combination, but they may not * actually be barycentric coordinates. Use the function vec_is_barycentric * to check if they really are barycentric coordinates, meaning the point * vector v is inside the triangle, ignoring the Z components. */ INLINE_MAYBE bool tri_barycentric(tri_t t, scal_t* b, vec_t v) { scal_t denom = (t.b.v.y - t.c.v.y) * (t.a.v.x - t.c.v.x) + (t.c.v.x - t.b.v.x) * (t.a.v.y - t.c.v.y); b[0] = ((t.b.v.y - t.c.v.y) * (v.x - t.c.v.x) + (t.c.v.x - t.b.v.x) * (v.y - t.c.v.y)) / denom; b[1] = ((t.c.v.y - t.a.v.y) * (v.x - t.c.v.x) + (t.a.v.x - t.c.v.x) * (v.y - t.c.v.y)) / denom; b[2] = S(1.0) - b[0] - b[1]; if (S(0.0) <= b[0] && b[0] <= S(1.0) && S(0.0) <= b[1] && b[1] <= S(1.0) && S(0.0) <= b[2] && b[2] <= S(1.0)) { return true; } return false; } /* * Find the midpoint of the triangle. */ INLINE_MAYBE vec_t tri_midpoint(tri_t t) { return vec_new((t.a.v.x + t.b.v.x + t.c.v.x) * S(0.333), (t.a.v.y + t.b.v.y + t.c.v.y) * S(0.333), (t.a.v.z + t.b.v.z + t.c.v.z) * S(0.333)); } /* * Get the average color of the triangle. */ INLINE_MAYBE color_t tri_color(tri_t t) { scal_t b[] = {S(0.333), S(0.333), S(0.333)}; return color_interp2(t.a.c, t.b.c, t.c.c, b); } /* * Get an interpolated z-value at the barycentric coordinates. */ INLINE_MAYBE scal_t tri_z(tri_t t, scal_t b[3]) { return t.a.v.z * b[0] + t.b.v.z * b[1] + t.c.v.z * b[2]; } /* * Calculate an interpolated point. */ INLINE_MAYBE vec_t tri_point(tri_t t, scal_t b[3]) { return vec_interp(t.a.v, t.b.v, t.c.v, b); } /* * Calculate an interpolated normal. */ INLINE_MAYBE vec_t tri_normal2(tri_t t, scal_t b[3]) { return vec_normalize(vec_interp(t.a.n, t.b.n, t.c.n, b)); } /* * Calculate an entirely new vertex within the triangle based on barycentric * coordinates. */ INLINE_MAYBE vert_t tri_interp(tri_t t, scal_t b[3]) { vert_t v = vert_new(tri_point(t, b)); v.c = color_interp2(t.a.c, t.b.c, t.c.c, b); v.n = tri_normal2(t, b); return v; } #endif // _TRI_H_