shithub: tinygl

Download patch

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_ */