shithub: libgraphics

Download patch

ref: db4fa883438f3910a3287320f42ae4aae42cc73b
parent: 524e19eee808837873435f908fd9b80a372673f8
author: rodri <rgl@antares-labs.eu>
date: Sun Jul 18 11:18:55 EDT 2021

add a line clipping procedure based on the Liang-Barsky algorithm. (thanks jmi2k!)

--- a/graphics.h
+++ b/graphics.h
@@ -67,6 +67,7 @@
 Point3 vcs2ndc(Camera*, Point3);
 Point3 world2ndc(Camera*, Point3);
 int isclipping(Point3);
+int clipline3(Point3*, Point3*);
 Point toviewport(Camera*, Point3);
 Point2 fromviewport(Camera*, Point);
 void perspective(Matrix3, double, double, double, double);
--- a/render.c
+++ b/render.c
@@ -55,6 +55,68 @@
 	return 0;
 }
 
+/* Liang-Barsky algorithm, requires p0, p1 to be in NDC */
+int
+clipline3(Point3 *p0, Point3 *p1)
+{
+	Point3 q0, q1, v;
+	int m0, m1, i;
+	double ti, to, th;
+	double c0[3*2] = {
+		p0->w + p0->x, p0->w - p0->x, p0->w + p0->y,
+		p0->w - p0->y,         p0->z, p0->w - p0->z,
+	}, c1[3*2] = {
+		p1->w + p1->x, p1->w - p1->x, p1->w + p1->y,
+		p1->w - p1->y,         p1->z, p1->w - p1->z,
+	};
+
+	/* bit-encoded regions */
+	m0 = (c0[0] < 0) << 0 |
+	     (c0[1] < 0) << 1 |
+	     (c0[2] < 0) << 2 |
+	     (c0[3] < 0) << 3 |
+	     (c0[4] < 0) << 4 |
+	     (c0[5] < 0) << 5;
+	m1 = (c1[0] < 0) << 0 |
+	     (c1[1] < 0) << 1 |
+	     (c1[2] < 0) << 2 |
+	     (c1[3] < 0) << 3 |
+	     (c1[4] < 0) << 4 |
+	     (c1[5] < 0) << 5;
+
+	if((m0 & m1) != 0)
+		return 1;	/* trivially rejected */
+	if((m0 | m1) == 0)
+		return 0;	/* trivially accepted */
+
+	ti = 0;
+	to = 1;
+	for(i = 0; i < 3*2; i++){
+		if(c1[i] < 0){
+			th = c0[i] / (c0[i]-c1[i]);
+			if(th < to)
+				to = th;
+		}else if(c0[i] < 0){
+			th = c0[i] / (c0[i]-c1[i]);
+			if(th < ti)
+				ti = th;
+		}
+		if(ti > to)
+			return 1;
+	}
+
+	/* chop line to fit inside NDC */
+	q0 = *p0;
+	q1 = *p1;
+	v = subpt3(q1, q0);
+	if(m0 != 0)
+		*p0 = addpt3(q0, mulpt3(v, ti));
+	if(m1 != 0)
+		*p1 = addpt3(q0, mulpt3(v, to));
+
+	return 0;
+}
+
 Point
 toviewport(Camera *c, Point3 p)
 {
@@ -112,7 +174,7 @@
 {
 	p0 = world2ndc(c, p0);
 	p1 = world2ndc(c, p1);
-	if(isclipping(p0) || isclipping(p1))
+	if(clipline3(&p0, &p1))
 		return;
 	line(c->viewport, toviewport(c, p0), toviewport(c, p1), end0, end1, 0, src, ZP);
 }