ref: 4819492ec36eec749bf6ee0550e69038265ead26
parent: b99349490192aa284dbf1cde3d5f86154e3c9c9d
author: David <gek@katherine>
date: Tue Feb 23 08:37:19 EST 2021
Performance update by inlining functions
--- a/src/clip.c
+++ b/src/clip.c
@@ -10,164 +10,10 @@
#define CLIP_ZMIN (1 << 4)
#define CLIP_ZMAX (1 << 5)
-void gl_transform_to_viewport(GLContext* c, GLVertex* v) {
- /* coordinates */
- {
- GLfloat winv = 1.0 / v->pc.W;
- v->zp.x = (GLint)(v->pc.X * winv * c->viewport.scale.X + c->viewport.trans.X);
- v->zp.y = (GLint)(v->pc.Y * winv * c->viewport.scale.Y + c->viewport.trans.Y);
- v->zp.z = (GLint)(v->pc.Z * winv * c->viewport.scale.Z + c->viewport.trans.Z);
- }
- /* color */
- v->zp.r = (GLuint)(v->color.v[0] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
- v->zp.g = (GLuint)(v->color.v[1] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
- v->zp.b = (GLuint)(v->color.v[2] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
- /* texture */
-
- if (c->texture_2d_enabled) {
- v->zp.s = (GLint)(v->tex_coord.X * (ZB_POINT_S_MAX - ZB_POINT_S_MIN) + ZB_POINT_S_MIN); //MARKED
- v->zp.t = (GLint)(v->tex_coord.Y * (ZB_POINT_T_MAX - ZB_POINT_T_MIN) + ZB_POINT_T_MIN); //MARKED
- }
-}
-
-static void gl_add_select1(GLContext* c, GLint z1, GLint z2, GLint z3) {
- GLint min, max;
- min = max = z1;
- if (z2 < min)
- min = z2;
- if (z3 < min)
- min = z3;
- if (z2 > max)
- max = z2;
- if (z3 > max)
- max = z3;
-
- gl_add_select(c, 0xffffffff - min, 0xffffffff - max);
-}
-
-/* point */
-
-void gl_draw_point(GLContext* c, GLVertex* p0) {
- if (p0->clip_code == 0) {
- if (c->render_mode == GL_SELECT) {
- gl_add_select(c, p0->zp.z, p0->zp.z);
- }else if (c->render_mode == GL_FEEDBACK){
- gl_add_feedback(c,GL_POINT_TOKEN,p0,NULL,NULL,0);
- } else {
- ZB_plot(c->zb, &p0->zp);
- }
- }
-}
-
-/* line */
-//Used only for lines.
-static inline void GLinterpolate(GLVertex* q, GLVertex* p0, GLVertex* p1, GLfloat t) {
- q->pc.X = p0->pc.X + (p1->pc.X - p0->pc.X) * t;
- q->pc.Y = p0->pc.Y + (p1->pc.Y - p0->pc.Y) * t;
- q->pc.Z = p0->pc.Z + (p1->pc.Z - p0->pc.Z) * t;
- q->pc.W = p0->pc.W + (p1->pc.W - p0->pc.W) * t;
-
- for(int i = 0; i < 3; i++)
- q->color.v[i] = p0->color.v[i] + (p1->color.v[i] - p0->color.v[i]) * t;
-}
-
-/*
- * Line Clipping
- */
-
-/* Line Clipping algorithm from 'Computer Graphics', Principles and
- Practice */
-static inline GLint ClipLine1(GLfloat denom, GLfloat num, GLfloat* tmin, GLfloat* tmax) {
- GLfloat t;
-
- if (denom > 0) {
- t = num / denom;
- if (t > *tmax)
- return 0;
- if (t > *tmin)
- *tmin = t;
- } else if (denom < 0) {
- t = num / denom;
- if (t < *tmin)
- return 0;
- if (t < *tmax)
- *tmax = t;
- } else if (num > 0)
- return 0;
- return 1;
-}
-
-void gl_draw_line(GLContext* c, GLVertex* p1, GLVertex* p2) {
- GLfloat dx, dy, dz, dw, x1, y1, z1, w1;
-
- GLVertex q1, q2;
- GLint cc1, cc2;
-
- cc1 = p1->clip_code;
- cc2 = p2->clip_code;
-
- if ((cc1 | cc2) == 0) {
- if (c->render_mode == GL_SELECT) {
- gl_add_select1(c, p1->zp.z, p2->zp.z, p2->zp.z);
- }else if (c->render_mode == GL_FEEDBACK){
- gl_add_feedback(
- c, GL_LINE_TOKEN,
- p1,
- p2,
- NULL,
- 0
- );
- } else {
- if (c->zb->depth_test)
- ZB_line_z(c->zb, &p1->zp, &p2->zp);
- else
- ZB_line(c->zb, &p1->zp, &p2->zp);
- }
- } else if ((cc1 & cc2) != 0) {
- return;
- } else {
- dx = p2->pc.X - p1->pc.X;
- dy = p2->pc.Y - p1->pc.Y;
- dz = p2->pc.Z - p1->pc.Z;
- dw = p2->pc.W - p1->pc.W;
- x1 = p1->pc.X;
- y1 = p1->pc.Y;
- z1 = p1->pc.Z;
- w1 = p1->pc.W;
-
- GLfloat tmin = 0;
- GLfloat tmax = 1;
- if (ClipLine1(dx + dw, -x1 - w1, &tmin, &tmax) && ClipLine1(-dx + dw, x1 - w1, &tmin, &tmax) && ClipLine1(dy + dw, -y1 - w1, &tmin, &tmax) &&
- ClipLine1(-dy + dw, y1 - w1, &tmin, &tmax) && ClipLine1(dz + dw, -z1 - w1, &tmin, &tmax) && ClipLine1(-dz + dw, z1 - w1, &tmin, &tmax)) {
-
- GLinterpolate(&q1, p1, p2, tmin);
- GLinterpolate(&q2, p1, p2, tmax);
- gl_transform_to_viewport(c, &q1);
- gl_transform_to_viewport(c, &q2);
-
- if (c->zb->depth_test)
- ZB_line_z(c->zb, &q1.zp, &q2.zp);
- else
- ZB_line(c->zb, &q1.zp, &q2.zp);
- }
- }
-}
-
-/* triangle */
-
-/*
- * Clipping
- */
-
-/* We clip the segment [a,b] against the 6 planes of the normal volume.
- * We compute the point 'c' of GLintersection and the value of the parameter 't'
- * of the GLintersection if x=a+t(b-a).
- */
-//MARK <POSSIBLE_PERF_BONUS>
-#define clip_func(name, sign, dir, dir1, dir2) \
- static GLfloat name(V4* c, V4* a, V4* b) { \
+#define clip_funcdef(name, sign, dir, dir1, dir2) \
+ GLfloat name(V4* c, V4* a, V4* b) { \
GLfloat t, dX, dY, dZ, dW, den; \
dX = (b->X - a->X); \
dY = (b->Y - a->Y); \
@@ -185,192 +31,39 @@
return t; \
}
//MARK <POSSIBLE_PERF_BONUS>
-clip_func(clip_xmin, -, X, Y, Z)
+clip_funcdef(clip_xmin, -, X, Y, Z)
- clip_func(clip_xmax, +, X, Y, Z)
+ clip_funcdef(clip_xmax, +, X, Y, Z)
- clip_func(clip_ymin, -, Y, X, Z)
+ clip_funcdef(clip_ymin, -, Y, X, Z)
- clip_func(clip_ymax, +, Y, X, Z)
+ clip_funcdef(clip_ymax, +, Y, X, Z)
//MARK <POSSIBLE_PERF_BONUS>
- clip_func(clip_zmin, -, Z, X, Y)
+ clip_funcdef(clip_zmin, -, Z, X, Y)
- clip_func(clip_zmax, +, Z, X, Y)
+ clip_funcdef(clip_zmax, +, Z, X, Y)
- GLfloat (*clip_proc[6])(V4*, V4*, V4*) = {clip_xmin, clip_xmax, clip_ymin, clip_ymax, clip_zmin, clip_zmax};
+GLfloat (*clip_proc[6])(V4*, V4*, V4*) = {clip_xmin, clip_xmax, clip_ymin, clip_ymax, clip_zmin, clip_zmax};
+/* point */
-static inline void updateTmp(GLContext* c, GLVertex* q, GLVertex* p0, GLVertex* p1, GLfloat t) {
- {
- q->color.v[0] = p0->color.v[0] + (p1->color.v[0] - p0->color.v[0]) * t;
- q->color.v[1] = p0->color.v[1] + (p1->color.v[1] - p0->color.v[1]) * t;
- q->color.v[2] = p0->color.v[2] + (p1->color.v[2] - p0->color.v[2]) * t;
- }
- // */
- if (c->texture_2d_enabled) {
- q->tex_coord.X = p0->tex_coord.X + (p1->tex_coord.X - p0->tex_coord.X) * t;
- q->tex_coord.Y = p0->tex_coord.Y + (p1->tex_coord.Y - p0->tex_coord.Y) * t;
- }
+/* line */
+//Used only for lines.
- q->clip_code = gl_clipcode(q->pc.X, q->pc.Y, q->pc.Z, q->pc.W);
- if (q->clip_code == 0)
- gl_transform_to_viewport(c, q);
-}
-static void gl_draw_triangle_clip(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2, GLint clip_bit);
+/*
+ * Line Clipping
+ */
-inline void gl_draw_triangle(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2) {
- GLint co, cc[3], front;
-
+/* Line Clipping algorithm from 'Computer Graphics', Principles and
+ Practice */
- cc[0] = p0->clip_code;
- cc[1] = p1->clip_code;
- cc[2] = p2->clip_code;
- co = cc[0] | cc[1] | cc[2];
- /* we handle the non clipped case here to go faster */
- if (co == 0) {
- GLfloat norm;
- norm = (GLfloat)(p1->zp.x - p0->zp.x) * (GLfloat)(p2->zp.y - p0->zp.y) - (GLfloat)(p2->zp.x - p0->zp.x) * (GLfloat)(p1->zp.y - p0->zp.y);
- if (norm == 0) //MARK <POSSIBLE_PERF_BONUS>
- return;
- front = norm < 0.0;
- front = front ^ c->current_front_face; //I don't know how this works, but it does, GL_CCW is 0x901 and CW is 900.
- /* back face culling */
- if (c->cull_face_enabled) {
- /* most used case first */
- if (c->current_cull_face == GL_BACK) {
- if (front == 0)
- return;
- c->draw_triangle_front(c, p0, p1, p2);
- } else if (c->current_cull_face == GL_FRONT) {
- if (front != 0)
- return;
- c->draw_triangle_back(c, p0, p1, p2);
- } else {
- return;
- }
- } else {
- /* no culling */
- if (front) {
- c->draw_triangle_front(c, p0, p1, p2);
- } else {
- c->draw_triangle_back(c, p0, p1, p2);
- }
- }
- } else {
- //GLint c_and = cc[0] & cc[1] & cc[2];
- if ((cc[0] & cc[1] & cc[2]) == 0) { // Don't draw a triangle with no points
- gl_draw_triangle_clip(c, p0, p1, p2, 0);
- }
- }
-}
-
-static void gl_draw_triangle_clip(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2, GLint clip_bit) {
- GLint co, c_and, co1, cc[3], edge_flag_tmp, clip_mask;
- //GLVertex tmp1, tmp2, *q[3];
- GLVertex *q[3];
-
-
- cc[0] = p0->clip_code;
- cc[1] = p1->clip_code;
- cc[2] = p2->clip_code;
-
- co = cc[0] | cc[1] | cc[2];
- if (co == 0) {
- gl_draw_triangle(c, p0, p1, p2);
- } else {
-
- c_and = cc[0] & cc[1] & cc[2];
- /* the triangle is completely outside */
- if (c_and != 0)
- return;
-
- /* find the next direction to clip */
- while (clip_bit < 6 && (co & (1 << clip_bit)) == 0) {
- clip_bit++;
- }
-
- /* this test can be true only in case of rounding errors */
- if (clip_bit == 6) { //The 2 bit and the 4 bit.
-#if 0
- tgl_warning("Error:\n");tgl_warning("%f %f %f %f\n",p0->pc.X,p0->pc.Y,p0->pc.Z,p0->pc.W);tgl_warning("%f %f %f %f\n",p1->pc.X,p1->pc.Y,p1->pc.Z,p1->pc.W);tgl_warning("%f %f %f %f\n",p2->pc.X,p2->pc.Y,p2->pc.Z,p2->pc.W);
-#endif
- return;
- }
-
- clip_mask = 1 << clip_bit;
- co1 = (cc[0] ^ cc[1] ^ cc[2]) & clip_mask;
-
- if (co1) {
- /* one point outside */
-
- if (cc[0] & clip_mask) {
- q[0] = p0;
- q[1] = p1;
- q[2] = p2;
- } else if (cc[1] & clip_mask) {
- q[0] = p1;
- q[1] = p2;
- q[2] = p0;
- } else {
- q[0] = p2;
- q[1] = p0;
- q[2] = p1;
- }
- {GLVertex tmp1, tmp2;GLfloat tt;
- tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
- updateTmp(c, &tmp1, q[0], q[1], tt);
-
- tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
- updateTmp(c, &tmp2, q[0], q[2], tt);
-
- tmp1.edge_flag = q[0]->edge_flag;
- edge_flag_tmp = q[2]->edge_flag;
- q[2]->edge_flag = 0;
- gl_draw_triangle_clip(c, &tmp1, q[1], q[2], clip_bit + 1);
-
- tmp2.edge_flag = 1;
- tmp1.edge_flag = 0;
- q[2]->edge_flag = edge_flag_tmp;
- gl_draw_triangle_clip(c, &tmp2, &tmp1, q[2], clip_bit + 1);
- }
- } else {
- /* two points outside */
-
- if ((cc[0] & clip_mask) == 0) {
- q[0] = p0;
- q[1] = p1;
- q[2] = p2;
- } else if ((cc[1] & clip_mask) == 0) {
- q[0] = p1;
- q[1] = p2;
- q[2] = p0;
- } else {
- q[0] = p2;
- q[1] = p0;
- q[2] = p1;
- }
- {GLVertex tmp1, tmp2;GLfloat tt;
- tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
- updateTmp(c, &tmp1, q[0], q[1], tt);
-
- tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
- updateTmp(c, &tmp2, q[0], q[2], tt);
-
- tmp1.edge_flag = 1;
- tmp2.edge_flag = q[2]->edge_flag;
- gl_draw_triangle_clip(c, q[0], &tmp1, &tmp2, clip_bit + 1);
- }
- }
- }
-}
-
//see vertex.c to see how the draw functions are assigned.
void gl_draw_triangle_select(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2) {
gl_add_select1(c, p0->zp.z, p1->zp.z, p2->zp.z);
@@ -391,7 +84,7 @@
#endif
//see vertex.c to see how the draw functions are assigned.
-void gl_draw_triangle_fill(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2) {
+void gl_draw_triangle_fill(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2) { //Must be function pointer!
if (c->texture_2d_enabled) {
//if(c->current_texture)
@@ -406,7 +99,7 @@
p0->zp.b = p2->zp.b;
}
#endif
- {
+
//#ifdef PROFILE
// count_triangles_textured++;
//#endif
@@ -419,7 +112,6 @@
#else
ZB_fillTriangleMappingPerspectiveNOBLEND(c->zb, &p0->zp, &p1->zp, &p2->zp);
#endif
- }
} else if (c->current_shade_model == GL_SMOOTH) {
//ZB_fillTriangleSmooth(c->zb, &p0->zp, &p1->zp, &p2->zp);
#if TGL_FEATURE_BLEND == 1
--- a/src/image_util.c
+++ b/src/image_util.c
@@ -38,7 +38,7 @@
#define INTERP_NORM_BITS 16
#define INTERP_NORM (1 << INTERP_NORM_BITS)
-static inline GLint GLinterpolate(GLint v00, GLint v01, GLint v10, GLint xf, GLint yf) {
+static inline GLint GLinterpolate_imutil(GLint v00, GLint v01, GLint v10, GLint xf, GLint yf) {
return v00 + (((v01 - v00) * xf + (v10 - v00) * yf) >> INTERP_NORM_BITS);
}
@@ -68,7 +68,7 @@
if ((xf + yf) <= INTERP_NORM) {
for (j = 0; j < 3; j++) {
- pix[j] = GLinterpolate(pix_src[(yi * xsize_src + xi) * 3 + j], pix_src[(yi * xsize_src + xi + 1) * 3 + j],
+ pix[j] = GLinterpolate_imutil(pix_src[(yi * xsize_src + xi) * 3 + j], pix_src[(yi * xsize_src + xi + 1) * 3 + j],
pix_src[((yi + 1) * xsize_src + xi) * 3 + j], xf, yf);
}
} else {
@@ -75,7 +75,7 @@
xf = INTERP_NORM - xf;
yf = INTERP_NORM - yf;
for (j = 0; j < 3; j++) {
- pix[j] = GLinterpolate(pix_src[((yi + 1) * xsize_src + xi + 1) * 3 + j], pix_src[((yi + 1) * xsize_src + xi) * 3 + j],
+ pix[j] = GLinterpolate_imutil(pix_src[((yi + 1) * xsize_src + xi + 1) * 3 + j], pix_src[((yi + 1) * xsize_src + xi) * 3 + j],
pix_src[(yi * xsize_src + xi + 1) * 3 + j], xf, yf);
}
}
--- a/src/vertex.c
+++ b/src/vertex.c
@@ -134,6 +134,29 @@
}
}
+static inline void gl_transform_to_viewport_vertex_c(GLContext* c, GLVertex* v) {
+
+ /* coordinates */
+ {
+ GLfloat winv = 1.0 / v->pc.W;
+ v->zp.x = (GLint)(v->pc.X * winv * c->viewport.scale.X + c->viewport.trans.X);
+ v->zp.y = (GLint)(v->pc.Y * winv * c->viewport.scale.Y + c->viewport.trans.Y);
+ v->zp.z = (GLint)(v->pc.Z * winv * c->viewport.scale.Z + c->viewport.trans.Z);
+ }
+ /* color */
+ v->zp.r = (GLuint)(v->color.v[0] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
+ v->zp.g = (GLuint)(v->color.v[1] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
+ v->zp.b = (GLuint)(v->color.v[2] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
+
+ /* texture */
+
+ if (c->texture_2d_enabled) {
+ v->zp.s = (GLint)(v->tex_coord.X * (ZB_POINT_S_MAX - ZB_POINT_S_MIN) + ZB_POINT_S_MIN); //MARKED
+ v->zp.t = (GLint)(v->tex_coord.Y * (ZB_POINT_T_MAX - ZB_POINT_T_MIN) + ZB_POINT_T_MIN); //MARKED
+ }
+}
+
+
/* coords, tranformation , clip code and projection */
/* TODO : handle all cases */
static inline void gl_vertex_transform(GLContext* c, GLVertex* v) {
@@ -253,7 +276,7 @@
}
/* precompute the mapping to the viewport */
if (v->clip_code == 0)
- gl_transform_to_viewport(c, v);
+ gl_transform_to_viewport_vertex_c(c, v);
/* edge flag */
--- a/src/zgl.h
+++ b/src/zgl.h
@@ -328,7 +328,7 @@
extern void (*op_table_func[])(GLContext*, GLParam*);
extern GLint op_table_size[];
extern void gl_compile_op(GLContext* c, GLParam* p);
-static inline void gl_add_op(GLParam* p) {
+inline void gl_add_op(GLParam* p) {
GLContext* c = gl_ctx;
#include "error_check.h"
GLint op;
@@ -346,18 +346,385 @@
}
}
+/* select.c */
+void gl_add_select(GLContext* c, GLuint zmin, GLuint zmax);
+void gl_add_feedback(GLContext* c, GLfloat token,
+ GLVertex* v1,
+ GLVertex* v2,
+ GLVertex* v3,
+ GLfloat passthrough_token_value
+);
+
/* clip.c */
-void gl_transform_to_viewport(GLContext* c, GLVertex* v);
-void gl_draw_triangle(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
-void gl_draw_line(GLContext* c, GLVertex* p0, GLVertex* p1);
-void gl_draw_point(GLContext* c, GLVertex* p0);
-void gl_draw_triangle_point(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
-void gl_draw_triangle_line(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
-void gl_draw_triangle_fill(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
-void gl_draw_triangle_select(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
-void gl_draw_triangle_feedback(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
+#define CLIP_EPSILON (1E-5)
+//Many of Clip.c's functions are inlined.
+static inline GLint gl_clipcode(GLfloat x, GLfloat y, GLfloat z, GLfloat w1) {
+ GLfloat w;
+ w = w1 * (1.0 + CLIP_EPSILON);
+ return (x < -w) | ((x > w) << 1) | ((y < -w) << 2) | ((y > w) << 3) | ((z < -w) << 4) | ((z > w) << 5);
+}
+
+#define CLIP_XMIN (1 << 0)
+#define CLIP_XMAX (1 << 1)
+#define CLIP_YMIN (1 << 2)
+#define CLIP_YMAX (1 << 3)
+#define CLIP_ZMIN (1 << 4)
+#define CLIP_ZMAX (1 << 5)
+
+static inline GLfloat clampf(GLfloat a, GLfloat min, GLfloat max) {
+ if (a < min)
+ return min;
+ else if (a > max)
+ return max;
+ else
+ return a;
+}
+
+static inline void gl_transform_to_viewport_clip_c(GLContext* c, GLVertex* v) {
+
+ /* coordinates */
+ {
+ GLfloat winv = 1.0 / v->pc.W;
+ v->zp.x = (GLint)(v->pc.X * winv * c->viewport.scale.X + c->viewport.trans.X);
+ v->zp.y = (GLint)(v->pc.Y * winv * c->viewport.scale.Y + c->viewport.trans.Y);
+ v->zp.z = (GLint)(v->pc.Z * winv * c->viewport.scale.Z + c->viewport.trans.Z);
+ }
+ /* color */
+ v->zp.r = (GLuint)(v->color.v[0] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
+ v->zp.g = (GLuint)(v->color.v[1] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
+ v->zp.b = (GLuint)(v->color.v[2] * COLOR_CORRECTED_MULT_MASK + COLOR_MIN_MULT) & COLOR_MASK;
+
+ /* texture */
+
+ if (c->texture_2d_enabled) {
+ v->zp.s = (GLint)(v->tex_coord.X * (ZB_POINT_S_MAX - ZB_POINT_S_MIN) + ZB_POINT_S_MIN); //MARKED
+ v->zp.t = (GLint)(v->tex_coord.Y * (ZB_POINT_T_MAX - ZB_POINT_T_MIN) + ZB_POINT_T_MIN); //MARKED
+ }
+}
+//void gl_transform_to_viewport(GLContext* c, GLVertex* v);
+//inline void gl_draw_triangle(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2);
+
+/* triangle */
+
+/*
+ * Clipping
+ */
+
+/* We clip the segment [a,b] against the 6 planes of the normal volume.
+ * We compute the point 'c' of GLintersection and the value of the parameter 't'
+ * of the GLintersection if x=a+t(b-a).
+ */
+//MARK <POSSIBLE_PERF_BONUS>
+#define clip_func(name, sign, dir, dir1, dir2) GLfloat name(V4* c, V4* a, V4* b);
+//MARK <POSSIBLE_PERF_BONUS>
+clip_func(clip_xmin, -, X, Y, Z)
+
+ clip_func(clip_xmax, +, X, Y, Z)
+
+ clip_func(clip_ymin, -, Y, X, Z)
+
+ clip_func(clip_ymax, +, Y, X, Z)
+//MARK <POSSIBLE_PERF_BONUS>
+ clip_func(clip_zmin, -, Z, X, Y)
+
+ clip_func(clip_zmax, +, Z, X, Y)
+
+extern GLfloat (*clip_proc[6])(V4*, V4*, V4*);// = {clip_xmin, clip_xmax, clip_ymin, clip_ymax, clip_zmin, clip_zmax};
+
+static inline void updateTmp(GLContext* c, GLVertex* q, GLVertex* p0, GLVertex* p1, GLfloat t) {
+ {
+
+
+ q->color.v[0] = p0->color.v[0] + (p1->color.v[0] - p0->color.v[0]) * t;
+ q->color.v[1] = p0->color.v[1] + (p1->color.v[1] - p0->color.v[1]) * t;
+ q->color.v[2] = p0->color.v[2] + (p1->color.v[2] - p0->color.v[2]) * t;
+ }
+ // */
+ if (c->texture_2d_enabled) {
+ q->tex_coord.X = p0->tex_coord.X + (p1->tex_coord.X - p0->tex_coord.X) * t;
+ q->tex_coord.Y = p0->tex_coord.Y + (p1->tex_coord.Y - p0->tex_coord.Y) * t;
+ }
+
+ q->clip_code = gl_clipcode(q->pc.X, q->pc.Y, q->pc.Z, q->pc.W);
+ if (q->clip_code == 0)
+ gl_transform_to_viewport_clip_c(c, q);
+}
+
+//inline void gl_draw_triangle_clip(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2, GLint clip_bit);
+
+static inline void gl_draw_triangle_clip(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2, GLint clip_bit);
+
+static inline void gl_draw_triangle(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2) {
+ GLint co, cc[3], front;
+
+
+ cc[0] = p0->clip_code;
+ cc[1] = p1->clip_code;
+ cc[2] = p2->clip_code;
+
+ co = cc[0] | cc[1] | cc[2];
+
+ /* we handle the non clipped case here to go faster */
+ if (co == 0) {
+ GLfloat norm;
+ norm = (GLfloat)(p1->zp.x - p0->zp.x) * (GLfloat)(p2->zp.y - p0->zp.y) - (GLfloat)(p2->zp.x - p0->zp.x) * (GLfloat)(p1->zp.y - p0->zp.y);
+
+ if (norm == 0) //MARK <POSSIBLE_PERF_BONUS>
+ return;
+
+ front = norm < 0.0;
+ front = front ^ c->current_front_face; //I don't know how this works, but it does, GL_CCW is 0x901 and CW is 900.
+
+ /* back face culling */
+ if (c->cull_face_enabled) {
+ /* most used case first */
+ if (c->current_cull_face == GL_BACK) {
+ if (front == 0)
+ return;
+ c->draw_triangle_front(c, p0, p1, p2);
+ } else if (c->current_cull_face == GL_FRONT) {
+ if (front != 0)
+ return;
+ c->draw_triangle_back(c, p0, p1, p2);
+ } else {
+ return;
+ }
+ } else {
+ /* no culling */
+ if (front) {
+ c->draw_triangle_front(c, p0, p1, p2);
+ } else {
+ c->draw_triangle_back(c, p0, p1, p2);
+ }
+ }
+ } else {
+ //GLint c_and = cc[0] & cc[1] & cc[2];
+ if ((cc[0] & cc[1] & cc[2]) == 0) { // Don't draw a triangle with no points
+ gl_draw_triangle_clip(c, p0, p1, p2, 0);
+ }
+ }
+}
+
+
+static inline void gl_draw_triangle_clip(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2, GLint clip_bit) {
+ GLint co, c_and, co1, cc[3], edge_flag_tmp, clip_mask;
+ //GLVertex tmp1, tmp2, *q[3];
+ GLVertex *q[3];
+
+
+ cc[0] = p0->clip_code;
+ cc[1] = p1->clip_code;
+ cc[2] = p2->clip_code;
+
+ co = cc[0] | cc[1] | cc[2];
+ if (co == 0) {
+ gl_draw_triangle(c, p0, p1, p2);
+ } else {
+
+ c_and = cc[0] & cc[1] & cc[2];
+ /* the triangle is completely outside */
+ if (c_and != 0)
+ return;
+
+ /* find the next direction to clip */
+ while (clip_bit < 6 && (co & (1 << clip_bit)) == 0) {
+ clip_bit++;
+ }
+
+ /* this test can be true only in case of rounding errors */
+ if (clip_bit == 6) { //The 2 bit and the 4 bit.
+#if 0
+ tgl_warning("Error:\n");tgl_warning("%f %f %f %f\n",p0->pc.X,p0->pc.Y,p0->pc.Z,p0->pc.W);tgl_warning("%f %f %f %f\n",p1->pc.X,p1->pc.Y,p1->pc.Z,p1->pc.W);tgl_warning("%f %f %f %f\n",p2->pc.X,p2->pc.Y,p2->pc.Z,p2->pc.W);
+#endif
+ return;
+ }
+
+ clip_mask = 1 << clip_bit;
+ co1 = (cc[0] ^ cc[1] ^ cc[2]) & clip_mask;
+
+ if (co1) {
+ /* one point outside */
+
+ if (cc[0] & clip_mask) {
+ q[0] = p0;
+ q[1] = p1;
+ q[2] = p2;
+ } else if (cc[1] & clip_mask) {
+ q[0] = p1;
+ q[1] = p2;
+ q[2] = p0;
+ } else {
+ q[0] = p2;
+ q[1] = p0;
+ q[2] = p1;
+ }
+ {GLVertex tmp1, tmp2;GLfloat tt;
+ tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
+ updateTmp(c, &tmp1, q[0], q[1], tt);
+
+ tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
+ updateTmp(c, &tmp2, q[0], q[2], tt);
+
+ tmp1.edge_flag = q[0]->edge_flag;
+ edge_flag_tmp = q[2]->edge_flag;
+ q[2]->edge_flag = 0;
+ gl_draw_triangle_clip(c, &tmp1, q[1], q[2], clip_bit + 1);
+
+ tmp2.edge_flag = 1;
+ tmp1.edge_flag = 0;
+ q[2]->edge_flag = edge_flag_tmp;
+ gl_draw_triangle_clip(c, &tmp2, &tmp1, q[2], clip_bit + 1);
+ }
+ } else {
+ /* two points outside */
+
+ if ((cc[0] & clip_mask) == 0) {
+ q[0] = p0;
+ q[1] = p1;
+ q[2] = p2;
+ } else if ((cc[1] & clip_mask) == 0) {
+ q[0] = p1;
+ q[1] = p2;
+ q[2] = p0;
+ } else {
+ q[0] = p2;
+ q[1] = p0;
+ q[2] = p1;
+ }
+ {GLVertex tmp1, tmp2;GLfloat tt;
+ tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
+ updateTmp(c, &tmp1, q[0], q[1], tt);
+
+ tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
+ updateTmp(c, &tmp2, q[0], q[2], tt);
+
+ tmp1.edge_flag = 1;
+ tmp2.edge_flag = q[2]->edge_flag;
+ gl_draw_triangle_clip(c, q[0], &tmp1, &tmp2, clip_bit + 1);
+ }
+ }
+ }
+}
+
+//inline void gl_draw_line(GLContext* c, GLVertex* p0, GLVertex* p1);
+static inline void gl_add_select1(GLContext* c, GLint z1, GLint z2, GLint z3) {
+ GLint min, max;
+ min = max = z1;
+ if (z2 < min)
+ min = z2;
+ if (z3 < min)
+ min = z3;
+ if (z2 > max)
+ max = z2;
+ if (z3 > max)
+ max = z3;
+
+ gl_add_select(c, 0xffffffff - min, 0xffffffff - max);
+}
+static inline void GLinterpolate(GLVertex* q, GLVertex* p0, GLVertex* p1, GLfloat t) {
+ q->pc.X = p0->pc.X + (p1->pc.X - p0->pc.X) * t;
+ q->pc.Y = p0->pc.Y + (p1->pc.Y - p0->pc.Y) * t;
+ q->pc.Z = p0->pc.Z + (p1->pc.Z - p0->pc.Z) * t;
+ q->pc.W = p0->pc.W + (p1->pc.W - p0->pc.W) * t;
+
+ for(int i = 0; i < 3; i++)
+ q->color.v[i] = p0->color.v[i] + (p1->color.v[i] - p0->color.v[i]) * t;
+}
+static inline GLint ClipLine1(GLfloat denom, GLfloat num, GLfloat* tmin, GLfloat* tmax) {
+ GLfloat t;
+
+ if (denom > 0) {
+ t = num / denom;
+ if (t > *tmax)
+ return 0;
+ if (t > *tmin)
+ *tmin = t;
+ } else if (denom < 0) {
+ t = num / denom;
+ if (t < *tmin)
+ return 0;
+ if (t < *tmax)
+ *tmax = t;
+ } else if (num > 0)
+ return 0;
+ return 1;
+}
+static inline void gl_draw_line(GLContext* c, GLVertex* p1, GLVertex* p2) {
+ GLfloat dx, dy, dz, dw, x1, y1, z1, w1;
+
+ GLVertex q1, q2;
+ GLint cc1, cc2;
+
+ cc1 = p1->clip_code;
+ cc2 = p2->clip_code;
+
+ if ((cc1 | cc2) == 0) {
+ if (c->render_mode == GL_SELECT) {
+ gl_add_select1(c, p1->zp.z, p2->zp.z, p2->zp.z);
+ }else if (c->render_mode == GL_FEEDBACK){
+ gl_add_feedback(
+ c, GL_LINE_TOKEN,
+ p1,
+ p2,
+ NULL,
+ 0
+ );
+ } else {
+ if (c->zb->depth_test)
+ ZB_line_z(c->zb, &p1->zp, &p2->zp);
+ else
+ ZB_line(c->zb, &p1->zp, &p2->zp);
+ }
+ } else if ((cc1 & cc2) != 0) {
+ return;
+ } else {
+ dx = p2->pc.X - p1->pc.X;
+ dy = p2->pc.Y - p1->pc.Y;
+ dz = p2->pc.Z - p1->pc.Z;
+ dw = p2->pc.W - p1->pc.W;
+ x1 = p1->pc.X;
+ y1 = p1->pc.Y;
+ z1 = p1->pc.Z;
+ w1 = p1->pc.W;
+
+ GLfloat tmin = 0;
+ GLfloat tmax = 1;
+ if (ClipLine1(dx + dw, -x1 - w1, &tmin, &tmax) && ClipLine1(-dx + dw, x1 - w1, &tmin, &tmax) && ClipLine1(dy + dw, -y1 - w1, &tmin, &tmax) &&
+ ClipLine1(-dy + dw, y1 - w1, &tmin, &tmax) && ClipLine1(dz + dw, -z1 - w1, &tmin, &tmax) && ClipLine1(-dz + dw, z1 - w1, &tmin, &tmax)) {
+
+ GLinterpolate(&q1, p1, p2, tmin);
+ GLinterpolate(&q2, p1, p2, tmax);
+ gl_transform_to_viewport_clip_c(c, &q1);
+ gl_transform_to_viewport_clip_c(c, &q2);
+
+ if (c->zb->depth_test)
+ ZB_line_z(c->zb, &q1.zp, &q2.zp);
+ else
+ ZB_line(c->zb, &q1.zp, &q2.zp);
+ }
+ }
+}
+
+//inline void gl_draw_point(GLContext* c, GLVertex* p0);
+inline void gl_draw_point(GLContext* c, GLVertex* p0) {
+ if (p0->clip_code == 0) {
+ if (c->render_mode == GL_SELECT) {
+ gl_add_select(c, p0->zp.z, p0->zp.z);
+ }else if (c->render_mode == GL_FEEDBACK){
+ gl_add_feedback(c,GL_POINT_TOKEN,p0,NULL,NULL,0);
+ } else {
+ ZB_plot(c->zb, &p0->zp);
+ }
+ }
+}
+
+void gl_draw_triangle_point(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2); //MUST BE FUNCTION POINTER
+void gl_draw_triangle_line(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2); //MUST BE FUNCTION POINTER
+void gl_draw_triangle_fill(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2); //MUST BE FUNCTION POINTER
+void gl_draw_triangle_select(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2); //MUST BE FUNCTION POINTER
+void gl_draw_triangle_feedback(GLContext* c, GLVertex* p0, GLVertex* p1, GLVertex* p2); //MUST BE FUNCTION POINTER
/* matrix.c */
void gl_print_matrix(const GLfloat* m);
/*
@@ -364,15 +731,8 @@
void glopLoadIdentity(GLContext *c,GLParam *p);
void glopTranslate(GLContext *c,GLParam *p);*/
-/* select.c */
-void gl_add_select(GLContext* c, GLuint zmin, GLuint zmax);
-void gl_add_feedback(GLContext* c, GLfloat token,
- GLVertex* v1,
- GLVertex* v2,
- GLVertex* v3,
- GLfloat passthrough_token_value
-);
+
/* light.c */
void gl_enable_disable_light(GLContext* c, GLint light, GLint v);
void gl_shade_vertex(GLContext* c, GLVertex* v);
@@ -418,23 +778,9 @@
/* this clip epsilon is needed to avoid some rounding errors after
several clipping stages */
-#define CLIP_EPSILON (1E-5)
-static inline GLint gl_clipcode(GLfloat x, GLfloat y, GLfloat z, GLfloat w1) {
- GLfloat w;
- w = w1 * (1.0 + CLIP_EPSILON);
- return (x < -w) | ((x > w) << 1) | ((y < -w) << 2) | ((y > w) << 3) | ((z < -w) << 4) | ((z > w) << 5);
-}
-static inline GLfloat clampf(GLfloat a, GLfloat min, GLfloat max) {
- if (a < min)
- return min;
- else if (a > max)
- return max;
- else
- return a;
-}
#endif /* _tgl_zgl_h_ */