diff options
Diffstat (limited to 'src/core/clip.c')
-rw-r--r-- | src/core/clip.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/core/clip.c b/src/core/clip.c new file mode 100644 index 0000000..8fe1eeb --- /dev/null +++ b/src/core/clip.c @@ -0,0 +1,201 @@ +#include "clip.h" +#include "shader.h" + +typedef enum { + POSITIVE_W, + POSITIVE_X, + NEGATIVE_X, + POSITIVE_Y, + NEGATIVE_Y, + POSITIVE_Z, + NEGATIVE_Z +} Plane; + +static bool is_inside_plane(Vec4* c, Plane plane) { + switch (plane) { + case POSITIVE_W: + return c->w >= EPSILON; + case POSITIVE_X: + return c->x <= +c->w; + case NEGATIVE_X: + return c->x >= -c->w; + case POSITIVE_Y: + return c->y <= +c->w; + case NEGATIVE_Y: + return c->y >= -c->w; + case POSITIVE_Z: + return c->z <= +c->w; + case NEGATIVE_Z: + return c->z >= -c->w; + default: + ssr_assert(0); + return 0; + } +} + +static bool is_vertex_visible(Vec4* v) { + return absf(v->x) <= v->w + && absf(v->y) <= v->w + && absf(v->z) <= v->w; +} + +static float get_intersect_ratio(Vec4* prev, Vec4* curr, Plane plane) { + switch (plane) { + case POSITIVE_W: + return (prev->w - EPSILON) / (prev->w - curr->w); + case POSITIVE_X: + return (prev->w - prev->x) / ((prev->w - prev->x) - (curr->w - curr->x)); + case NEGATIVE_X: + return (prev->w + prev->x) / ((prev->w + prev->x) - (curr->w + curr->x)); + case POSITIVE_Y: + return (prev->w - prev->y) / ((prev->w - prev->y) - (curr->w - curr->y)); + case NEGATIVE_Y: + return (prev->w + prev->y) / ((prev->w + prev->y) - (curr->w + curr->y)); + case POSITIVE_Z: + return (prev->w - prev->z) / ((prev->w - prev->z) - (curr->w - curr->z)); + case NEGATIVE_Z: + return (prev->w + prev->z) / ((prev->w + prev->z) - (curr->w + curr->z)); + default: + assert(0); + return 0; + } +} + +static bool clip_against_plane(Plane plane, uint varying_flag, ClippedBuffer* src_buffer, ClippedBuffer* dst_buffer) { + int idx = 0; + for (int i = 0; i < src_buffer->count; ++i) { + ClippedVert* prev = &src_buffer->vertices[(i - 1 + src_buffer->count) % src_buffer->count]; + ClippedVert* curr = &src_buffer->vertices[i]; + + bool prev_inside = is_inside_plane(&prev->clip_coord, plane); + bool curr_inside = is_inside_plane(&curr->clip_coord, plane); + + if (prev_inside != curr_inside) { + ClippedVert* dst = &dst_buffer->vertices[idx]; + float t = get_intersect_ratio(&prev->clip_coord, &curr->clip_coord, plane); + ssrS_lerpvec4(t, &prev->clip_coord, &curr->clip_coord, &dst->clip_coord); + /*set varying varibles*/ + if (varying_flag & VARYING_BASIC) { + if (varying_flag & VARYING_POSITION) ssrS_lerpvec3(t, &prev->vertex.position, &curr->vertex.position, &dst->vertex.position); + if (varying_flag & VARYING_NORMAL) ssrS_lerpvec3(t, &prev->vertex.normal, &curr->vertex.normal, &dst->vertex.normal); + if (varying_flag & VARYING_TANGENT) ssrS_lerpvec3(t, &prev->vertex.tangent, &curr->vertex.tangent, &dst->vertex.tangent); + if (varying_flag & VARYING_TEXCOORD) ssrS_lerpvec2(t, &prev->vertex.texcoord, &curr->vertex.texcoord, &dst->vertex.texcoord); + if (varying_flag & VARYING_COLOR) ssrS_lerpcolor(t, prev->vertex.color, curr->vertex.color, &dst->vertex.color); + if (varying_flag & VARYING_JOINT) ssrS_lerpvec4(t, &prev->vertex.joint, &curr->vertex.joint, &dst->vertex.joint); + if (varying_flag & VARYING_WEIGHT) ssrS_lerpvec4(t, &prev->vertex.weight, &curr->vertex.weight, &dst->vertex.weight); + } + if (varying_flag & VARYING_EXTRA) { + int j = 0; + if (varying_flag & VARYING_NUM) { + for (j = 0; j < REG_NUM_COUNT; ++j) { + if (varying_flag & (VARYING_NUM_00 << j)) { + ssrS_lerpnum(t, prev->num[j], curr->num[j], &dst->num[j]); + } + } + } + if (varying_flag & VARYING_V2) { + for (j = 0; j < REG_V2_COUNT; ++j) { + if (varying_flag & (VARYING_V2_00 << j)) { + ssrS_lerpvec2(t, &prev->v2[j], &curr->v2[j], &dst->v2[j]); + } + } + } + if (varying_flag & VARYING_V3) { + for (j = 0; j < REG_V3_COUNT; ++j) { + if (varying_flag & (VARYING_V3_00 << j)) { + ssrS_lerpvec3(t, &prev->v3[j], &curr->v3[j], &dst->v3[j]); + } + } + } + if (varying_flag & VARYING_V4) { + for (j = 0; j < REG_V4_COUNT; ++j) { + if (varying_flag & (VARYING_V4_00 << j)) { + ssrS_lerpvec4(t, &prev->v4[j], &curr->v4[j], &dst->v4[j]); + } + } + } + } + ++idx; + } + + if (curr_inside) { + ClippedVert* dst = &dst_buffer->vertices[idx]; + *dst = *curr; + ++idx; + } + } + dst_buffer->count = idx; + return idx < 3; +} + +#define CLIP(plane, from, to) \ +do { \ +is_cull = clip_against_plane(plane, varying_flag, from, to); \ +if (is_cull) { \ + buffer->count = 0;/*cull this triangle*/ \ + return 1; \ +} \ +}while(0) + +bool clip_triangle(Vec4* c0, Vec4* c1, Vec4* c2, Vert* v0, Vert* v1, Vert* v2, uint varying_flag, ClippedBuffer* buffer) { + bool is_visible = is_vertex_visible(c0) + && is_vertex_visible(c1) + && is_vertex_visible(c2); + + if (is_visible) { + return 0; /*no need to clip*/ + } + + /*clipping it*/ + + static ClippedBuffer temp; + + /*copy vert data to temp*/ + temp.count = 3; +#define INIT_CLIP_VERT(idx) \ + temp.vertices[idx].clip_coord = *c##idx; \ + temp.vertices[idx].vertex = *v##idx; \ + if (varying_flag & VARYING_EXTRA) { \ + int i = 0; \ + if(varying_flag && VARYING_NUM) { \ + for (i = 0; i < REG_NUM_COUNT; ++i) { \ + if (varying_flag & (VARYING_NUM_00 << i)) \ + temp.vertices[idx].num[i] = reg_num[i].num[v##idx->index]; \ + } \ + } \ + if(varying_flag && VARYING_V2) { \ + for (i = 0; i < REG_V2_COUNT; ++i) { \ + if (varying_flag & (VARYING_V2_00 << i)) \ + temp.vertices[idx].v2[i] = reg_v2[i].v2[v##idx->index]; \ + } \ + } \ + if(varying_flag && VARYING_V3) { \ + for (i = 0; i < REG_V3_COUNT; ++i) { \ + if (varying_flag & (VARYING_V3_00 << i)) \ + temp.vertices[idx].v3[i] = reg_v3[i].v3[v##idx->index]; \ + } \ + } \ + if(varying_flag && VARYING_V4) { \ + for (i = 0; i < REG_V4_COUNT; ++i) { \ + if (varying_flag & (VARYING_V4_00 << i)) \ + temp.vertices[idx].v4[i] = reg_v4[i].v4[v##idx->index]; \ + } \ + } \ + } + INIT_CLIP_VERT(0); + INIT_CLIP_VERT(1); + INIT_CLIP_VERT(2); +#undef INIT_CLIP_VERT + + bool is_cull = FALSE; + + CLIP(POSITIVE_W, &temp, buffer); + CLIP(POSITIVE_X, buffer, &temp); + CLIP(NEGATIVE_X, &temp, buffer); + CLIP(POSITIVE_Y, buffer, &temp); + CLIP(NEGATIVE_Y, &temp, buffer); + CLIP(POSITIVE_Z, buffer, &temp); + CLIP(NEGATIVE_Z, &temp, buffer); + + return 1; +} |