summaryrefslogtreecommitdiff
path: root/src/core/clip.c
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-12-08 00:24:22 +0800
committerchai <chaifix@163.com>2019-12-08 00:24:22 +0800
commit0c4b1e68d64996a4aa5b136ddb6ee5643e159ef2 (patch)
tree0a263567be678f8b945b1472392f09b77b31b9eb /src/core/clip.c
parent3df29dc54c509c983dc8a0e23eab4160d48144f2 (diff)
+test
Diffstat (limited to 'src/core/clip.c')
-rw-r--r--src/core/clip.c201
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;
+}