ref: 50f15bac90638da401d27229969dc502c75d1320
parent: 3bf0f4fdcf9e1a61881c20ee8162924f952ba8e0
author: rodri <rgl@antares-labs.eu>
date: Fri Aug 2 13:57:42 EDT 2024
fix line interpolation during rasterization. vertex attributes were not being updated after clipping with their corresponding work rectangles, nor when reordering the points before rasterization, which caused serious artifacts.
--- a/clip.c
+++ b/clip.c
@@ -193,11 +193,37 @@
return code;
}
+/* lerp vertex attributes to match the new positions */
+void
+adjustverts(Point *p0, Point *p1, Vertex *v0, Vertex *v1)
+{
+ Vertex v[2];
+ Point3 dp;
+ Point Δp;
+ double len, perc;
+
+ dp = subpt3(v1->p, v0->p);
+ len = hypot(dp.x, dp.y);
+
+ Δp = subpt(Pt(v0->p.x, v0->p.y), *p0);
+ perc = len == 0? 0: hypot(Δp.x, Δp.y)/len;
+ lerpvertex(&v[0], v0, v1, perc);
+
+ Δp = subpt(Pt(v0->p.x, v0->p.y), *p1);
+ perc = len == 0? 0: hypot(Δp.x, Δp.y)/len;
+ lerpvertex(&v[1], v0, v1, perc);
+
+ delvattrs(v0);
+ delvattrs(v1);
+ *v0 = dupvertex(&v[0]);
+ *v1 = dupvertex(&v[1]);
+}
+
/*
* Cohen-Sutherland rectangle-line clipping
*/
int
-rectclipline(Rectangle r, Point *p0, Point *p1)
+rectclipline(Rectangle r, Point *p0, Point *p1, Vertex *v0, Vertex *v1)
{
int code0, code1;
int Δx, Δy;
@@ -211,14 +237,16 @@
code0 = outcode(*p0, r);
code1 = outcode(*p1, r);
- if(lineisinside(code0, code1))
+ if(lineisinside(code0, code1)){
+ adjustverts(p0, p1, v0, v1);
return 0;
- else if(lineisoutside(code0, code1))
+ }else if(lineisoutside(code0, code1))
return -1;
if(ptisinside(code0)){
swappt(p0, p1);
swapi(&code0, &code1);
+ swapvertex(v0, v1);
}
if(code0 & CLIPL){
--- a/internal.h
+++ b/internal.h
@@ -45,6 +45,7 @@
/* vertex */
Vertex dupvertex(Vertex*);
+void swapvertex(Vertex*, Vertex*);
void lerpvertex(Vertex*, Vertex*, Vertex*, double);
void berpvertex(Vertex*, Vertex*, Vertex*, Vertex*, Point3);
void delvattrs(Vertex*);
@@ -52,7 +53,7 @@
/* clip */
int clipprimitive(Primitive*, Primitive*);
-int rectclipline(Rectangle, Point*, Point*);
+int rectclipline(Rectangle, Point*, Point*, Vertex*, Vertex*);
/* util */
int min(int, int);
--- a/render.c
+++ b/render.c
@@ -128,7 +128,7 @@
p0 = Pt(prim.v[0].p.x, prim.v[0].p.y);
p1 = Pt(prim.v[1].p.x, prim.v[1].p.y);
/* clip it against our wr */
- if(rectclipline(task->wr, &p0, &p1) < 0)
+ if(rectclipline(task->wr, &p0, &p1, &prim.v[0], &prim.v[1]) < 0)
break;
/* transpose the points */
@@ -140,8 +140,8 @@
/* make them left-to-right */
if(p0.x > p1.x){
- swapi(&p0.x, &p1.x);
- swapi(&p0.y, &p1.y);
+ swappt(&p0, &p1);
+ swapvertex(&prim.v[0], &prim.v[1]);
}
dp = subpt(p1, p0);
--- a/vertex.c
+++ b/vertex.c
@@ -43,6 +43,16 @@
return nv;
}
+void
+swapvertex(Vertex *a, Vertex *b)
+{
+ Vertex t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+
/*
* linear attribute interpolation
*/