summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2023-12-16 21:03:52 +0000
committerrodri <rgl@antares-labs.eu>2023-12-16 21:03:52 +0000
commit79a8452ad57167a94d3be991a666b8f96d6fb5b4 (patch)
treecbc6a34b469bec0938dae26e85b091027676c0ae
parent4923947f638c4bad0a4e02dc8ccde0db4d795571 (diff)
downloadtinyrend-79a8452ad57167a94d3be991a666b8f96d6fb5b4.tar.gz
tinyrend-79a8452ad57167a94d3be991a666b8f96d6fb5b4.tar.bz2
tinyrend-79a8452ad57167a94d3be991a666b8f96d6fb5b4.zip
got stuck and skipped to Lesson 6: Shaders for the software renderer.
i was unable to find a fix for the rendering artifacts i was getting and decided to skip to a later chapter, with a new architecture based on actual shaders, that made things easier to understand. right after the move i spotted the problem (and others that showed up) and was finally able to fix them. it's working now!
-rw-r--r--main.c492
-rw-r--r--mdl/def.obj6
2 files changed, 225 insertions, 273 deletions
diff --git a/main.c b/main.c
index 6d3f736..c4a5535 100644
--- a/main.c
+++ b/main.c
@@ -12,25 +12,40 @@
#define HZ2MS(hz) (1000/(hz))
typedef Point Triangle[3];
-typedef struct Sparams Sparams;
+typedef struct VSparams VSparams;
+typedef struct FSparams FSparams;
typedef struct SUparams SUparams;
/* shader params */
-struct Sparams
+struct VSparams
{
+ SUparams *su;
+ Point3 p;
+ Point3 n;
+ uint idx;
+};
+
+struct FSparams
+{
+ SUparams *su;
Memimage *frag;
Point p;
+ Point3 bc;
+ uchar *cbuf;
};
/* shader unit params */
struct SUparams
{
Memimage *dst;
- Rectangle r;
OBJElem **b, **e;
int id;
Channel *donec;
- Memimage *(*shader)(Sparams*);
+
+ double var_intensity[3];
+
+ Point3 (*vshader)(VSparams*);
+ Memimage *(*fshader)(FSparams*);
};
@@ -43,22 +58,13 @@ Memimage *modeltex;
Channel *drawc;
int nprocs;
int rendering;
-int flag2;
int shownormals;
char winspec[32];
Point3 camera = {0,0,3,1};
-Matrix3 proj = {
- 1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1,
-}, view = {
- 800/2.0, 0, 0, 800/2.0,
- 0, 800/2.0, 0, 800/2.0,
- 0, 0, 1/2.0, 1/2.0,
- 0, 0, 0, 1,
-}, rota;
+Point3 center = {0,0,0,1};
+Point3 up = {0,1,0,0};
+Matrix3 view, proj, rota;
void resized(void);
uvlong nanosec(void);
@@ -75,6 +81,18 @@ max(int a, int b)
return a > b? a: b;
}
+double
+fmin(double a, double b)
+{
+ return a < b? a: b;
+}
+
+double
+fmax(double a, double b)
+{
+ return a > b? a: b;
+}
+
void
swap(int *a, int *b)
{
@@ -333,24 +351,89 @@ filltriangle(Memimage *dst, Point p0, Point p1, Point p2, Memimage *src)
}
void
-filltriangle2(Memimage *dst, Triangle3 st, Triangle3 nt, Triangle2 tt, double intensity, Memimage *frag)
+viewport(Rectangle r)
{
+ identity3(view);
+ view[0][3] = r.max.x/2.0;
+ view[1][3] = r.max.y/2.0;
+ view[2][3] = 1.0/2.0;
+ view[0][0] = Dx(r)/2.0;
+ view[1][1] = -Dy(r)/2.0;
+ view[2][2] = 1.0/2.0;
+}
+
+void
+projection(double c)
+{
+ identity3(proj);
+ proj[3][2] = c;
+}
+
+void
+lookat(Point3 eye, Point3 o, Point3 up)
+{
+ Point3 x, y, z;
+
+ z = normvec3(subpt3(eye, o));
+ x = normvec3(crossvec3(up, z));
+ y = normvec3(crossvec3(z, x));
+ identity3(rota);
+ rota[0][0] = x.x; rota[0][1] = x.y; rota[0][2] = x.z; rota[0][3] = -o.x;
+ rota[1][0] = y.x; rota[1][1] = y.y; rota[1][2] = y.z; rota[1][3] = -o.y;
+ rota[2][0] = z.x; rota[2][1] = z.y; rota[2][2] = z.z; rota[2][3] = -o.z;
+}
+
+Point3
+vertshader(VSparams *sp)
+{
+ static Point3 light = {1,1,1,0}; /* global light field */
+ light = subpt3(camera, center);
+
+ sp->su->var_intensity[sp->idx] = fmax(0, dotvec3(sp->n, normvec3(light)));
+ return xform3(sp->p, view);
+}
+
+Memimage *
+fragshader(FSparams *sp)
+{
+ double intens;
+
+ intens = sp->su->var_intensity[0]*sp->bc.x;
+ intens += sp->su->var_intensity[1]*sp->bc.y;
+ intens += sp->su->var_intensity[2]*sp->bc.z;
+ sp->cbuf[1] *= intens;
+ sp->cbuf[2] *= intens;
+ sp->cbuf[3] *= intens;
+ memfillcolor(sp->frag, *(ulong*)sp->cbuf);
+
+ return sp->frag;
+}
+
+void
+rasterize(SUparams *params, Triangle3 st, Triangle2 tt, Memimage *frag)
+{
+ FSparams fsp;
+ Triangle2 st₂, tt₂;
Rectangle bbox;
Point p, tp;
- Triangle2 st₂, tt₂;
Point3 bc;
- static Point3 light = {0,0,-1,0}; /* global light field */
- double z, intens[3];
+ double z, w, depth;
uchar cbuf[4];
+ st₂.p0 = Pt2(st.p0.x/st.p0.w, st.p0.y/st.p0.w, 1);
+ st₂.p1 = Pt2(st.p1.x/st.p1.w, st.p1.y/st.p1.w, 1);
+ st₂.p2 = Pt2(st.p2.x/st.p2.w, st.p2.y/st.p2.w, 1);
+ /* find the triangle's bbox and clip it against the fb */
bbox = Rect(
- min(min(st.p0.x, st.p1.x), st.p2.x), min(min(st.p0.y, st.p1.y), st.p2.y),
- max(max(st.p0.x, st.p1.x), st.p2.x)+1, max(max(st.p0.y, st.p1.y), st.p2.y)+1
+ min(min(st₂.p0.x, st₂.p1.x), st₂.p2.x), min(min(st₂.p0.y, st₂.p1.y), st₂.p2.y),
+ max(max(st₂.p0.x, st₂.p1.x), st₂.p2.x)+1, max(max(st₂.p0.y, st₂.p1.y), st₂.p2.y)+1
);
- st₂.p0 = Pt2(st.p0.x, st.p0.y, 1);
- st₂.p1 = Pt2(st.p1.x, st.p1.y, 1);
- st₂.p2 = Pt2(st.p2.x, st.p2.y, 1);
+ bbox.min.x = max(bbox.min.x, fb->r.min.x); bbox.min.y = max(bbox.min.y, fb->r.min.y);
+ bbox.max.x = min(bbox.max.x, fb->r.max.x); bbox.max.y = min(bbox.max.y, fb->r.max.y);
cbuf[0] = 0xFF;
+ fsp.su = params;
+ fsp.frag = frag;
+ fsp.cbuf = cbuf;
for(p.y = bbox.min.y; p.y < bbox.max.y; p.y++)
for(p.x = bbox.min.x; p.x < bbox.max.x; p.x++){
@@ -358,31 +441,25 @@ filltriangle2(Memimage *dst, Triangle3 st, Triangle3 nt, Triangle2 tt, double in
if(bc.x < 0 || bc.y < 0 || bc.z < 0)
continue;
- intens[0] = dotvec3(nt.p0, light);
- intens[1] = dotvec3(nt.p1, light);
- intens[2] = dotvec3(nt.p2, light);
- intensity = intens[0]*bc.x + intens[1]*bc.y + intens[2]*bc.z;
- /* back-face culling */
- if(intensity <= 0)
- continue;
-
z = st.p0.z*bc.x + st.p1.z*bc.y + st.p2.z*bc.z;
+ w = st.p0.w*bc.x + st.p1.w*bc.y + st.p2.w*bc.z;
+ depth = fclamp(z/w, 0, 1);
lock(&zbuflk);
- if(z <= zbuf[p.x + p.y*Dx(dst->r)]){
+ if(depth <= zbuf[p.x + p.y*Dx(params->dst->r)]){
unlock(&zbuflk);
continue;
}
- zbuf[p.x + p.y*Dx(dst->r)] = z;
+ zbuf[p.x + p.y*Dx(params->dst->r)] = depth;
- cbuf[1] = 0xFF*z;
- cbuf[2] = 0xFF*z;
- cbuf[3] = 0xFF*z;
+ cbuf[1] = 0xFF*depth;
+ cbuf[2] = 0xFF*depth;
+ cbuf[3] = 0xFF*depth;
memfillcolor(frag, *(ulong*)cbuf);
pixel(zfb, p, frag);
unlock(&zbuflk);
cbuf[0] = 0xFF;
- if(tt.p0.w != 0 && tt.p1.w != 0 && tt.p2.w != 0){
+ if((tt.p0.w + tt.p1.w + tt.p2.w) != 0){
tt₂.p0 = mulpt2(tt.p0, bc.x);
tt₂.p1 = mulpt2(tt.p1, bc.y);
tt₂.p2 = mulpt2(tt.p2, bc.z);
@@ -394,12 +471,9 @@ filltriangle2(Memimage *dst, Triangle3 st, Triangle3 nt, Triangle2 tt, double in
}else
memset(cbuf+1, 0xFF, sizeof cbuf - 1);
- cbuf[1] *= intensity;
- cbuf[2] *= intensity;
- cbuf[3] *= intensity;
-
- memfillcolor(frag, *(ulong*)cbuf);
- pixel(dst, p, frag);
+ fsp.p = p;
+ fsp.bc = bc;
+ pixel(params->dst, p, params->fshader(&fsp));
}
}
@@ -407,75 +481,20 @@ void
shaderunit(void *arg)
{
SUparams *params;
- Sparams sp;
- Point p;
- Memimage *c;
-
- params = arg;
- sp.frag = rgb(DBlack);
-
- threadsetname("shader unit #%d", params->id);
-
- for(p.y = params->r.min.y; p.y < params->r.max.y; p.y++)
- for(p.x = params->r.min.x; p.x < params->r.max.x; p.x++){
- sp.p = p;
- if((c = params->shader(&sp)) != nil)
- pixel(params->dst, p, c);
- }
-
- freememimage(sp.frag);
- sendp(params->donec, nil);
- free(params);
- threadexits(nil);
-}
-
-void
-shade(Memimage *dst, Memimage *(*shader)(Sparams*))
-{
- int i;
- Point dim;
- SUparams *params;
- Channel *donec;
-
- /* shitty approach until i find a better algo */
- dim.x = Dx(dst->r)/nprocs;
-
- donec = chancreate(sizeof(void*), 0);
-
- for(i = 0; i < nprocs; i++){
- params = emalloc(sizeof *params);
- params->dst = dst;
- params->r = Rect(i*dim.x,0,min((i+1)*dim.x, dst->r.max.x),dst->r.max.y);
- params->id = i;
- params->donec = donec;
- params->shader = shader;
- proccreate(shaderunit, params, mainstacksize);
- fprint(2, "spawned su %d for %R\n", params->id, params->r);
- }
-
- while(i--)
- recvp(donec);
- chanfree(donec);
-}
-
-void
-shaderunit2(void *arg)
-{
- SUparams *params;
- Sparams sp;
+ VSparams vsp;
+ Memimage *frag;
OBJVertex *verts, *tverts, *nverts; /* geometric, texture and normals vertices */
OBJIndexArray *idxtab;
OBJElem **ep;
Triangle3 t, st, nt; /* world-, screen-space and normals triangles */
Triangle2 tt; /* texture triangle */
Point3 n; /* surface normal */
-// static Point3 light = {0,0,-1,0}; /* global light field */
-// double intensity, intens[3];
Point3 np0, np1, bc;
Triangle2 st₂;
params = arg;
- sp.frag = rgb(DBlack);
+ vsp.su = params;
+ frag = rgb(DBlack);
threadsetname("shader unit #%d", params->id);
@@ -490,60 +509,44 @@ shaderunit2(void *arg)
t.p1 = Pt3(verts[idxtab->indices[1]].x,verts[idxtab->indices[1]].y,verts[idxtab->indices[1]].z,verts[idxtab->indices[1]].w);
t.p2 = Pt3(verts[idxtab->indices[2]].x,verts[idxtab->indices[2]].y,verts[idxtab->indices[2]].z,verts[idxtab->indices[2]].w);
- t.p0 = xform3(t.p0, rota);
- t.p1 = xform3(t.p1, rota);
- t.p2 = xform3(t.p2, rota);
-
- st.p0 = xform3(t.p0, view);
- st.p1 = xform3(t.p1, view);
- st.p2 = xform3(t.p2, view);
- st.p0 = divpt3(st.p0, st.p0.w);
- st.p1 = divpt3(st.p1, st.p1.w);
- st.p2 = divpt3(st.p2, st.p2.w);
-
-// n = normvec3(crossvec3(subpt3(t.p2, t.p0), subpt3(t.p1, t.p0)));
-// intensity = dotvec3(n, light);
-// /* back-face culling */
-// if(intensity <= 0)
-// continue;
-
-// np0 = centroid3(st);
-// np1 = addpt3(np0, mulpt3(n, 50));
-// bresenham(nfb, Pt(np0.x,np0.y), Pt(np1.x,np1.y), memwhite);
-
idxtab = &(*ep)->indextab[OBJVNormal];
- if(modeltex != nil && idxtab->nindex == 3){
+ if(idxtab->nindex == 3){
nt.p0 = Vec3(nverts[idxtab->indices[0]].i, nverts[idxtab->indices[0]].j, nverts[idxtab->indices[0]].k);
nt.p1 = Vec3(nverts[idxtab->indices[1]].i, nverts[idxtab->indices[1]].j, nverts[idxtab->indices[1]].k);
nt.p2 = Vec3(nverts[idxtab->indices[2]].i, nverts[idxtab->indices[2]].j, nverts[idxtab->indices[2]].k);
- nt.p0 = normvec3(nt.p0); nt.p0.z *= -1;
- nt.p1 = normvec3(nt.p1); nt.p1.z *= -1;
- nt.p2 = normvec3(nt.p2); nt.p2.z *= -1;
-// nt.p0 = mulpt3(normvec3(nt.p0), -1);
-// nt.p1 = mulpt3(normvec3(nt.p1), -1);
-// nt.p2 = mulpt3(normvec3(nt.p2), -1);
-// intens[0] = dotvec3(nt.p0, light);
-// intens[1] = dotvec3(nt.p1, light);
-// intens[2] = dotvec3(nt.p2, light);
-
- st₂.p0 = Pt2(st.p0.x, st.p0.y, 1);
- st₂.p1 = Pt2(st.p1.x, st.p1.y, 1);
- st₂.p2 = Pt2(st.p2.x, st.p2.y, 1);
- bc = barycoords(st₂, centroid(st₂));
- np0 = centroid3(st);
- np1 = Vec3(
- nt.p0.x*bc.x + nt.p1.x*bc.y + nt.p2.x*bc.z,
- nt.p0.y*bc.x + nt.p1.y*bc.y + nt.p2.y*bc.z,
- nt.p0.z*bc.x + nt.p1.z*bc.y + nt.p2.z*bc.z);
-// intensity = intens[0]*bc.x + intens[1]*bc.y + intens[2]*bc.z;
-// /* back-face culling */
-// if(intensity <= 0)
-// continue;
- np1 = addpt3(np0, mulpt3(np1, 50));
- triangle(nfb, Pt(st.p0.x,st.p0.y), Pt(st.p1.x,st.p1.y), Pt(st.p2.x,st.p2.y), red);
- bresenham(nfb, Pt(np0.x,np0.y), Pt(np1.x,np1.y), green);
- }else
- memset(&nt, 0, sizeof nt);
+ nt.p0 = xform3(normvec3(nt.p0), rota);
+ nt.p1 = xform3(normvec3(nt.p1), rota);
+ nt.p2 = xform3(normvec3(nt.p2), rota);
+ }else{
+ n = normvec3(crossvec3(subpt3(t.p2, t.p0), subpt3(t.p1, t.p0)));
+ nt.p0 = nt.p1 = nt.p2 = xform3(mulpt3(n, -1), rota);
+ }
+
+ vsp.p = t.p0;
+ vsp.n = nt.p0;
+ vsp.idx = 0;
+ st.p0 = params->vshader(&vsp);
+ vsp.p = t.p1;
+ vsp.n = nt.p1;
+ vsp.idx = 1;
+ st.p1 = params->vshader(&vsp);
+ vsp.p = t.p2;
+ vsp.n = nt.p2;
+ vsp.idx = 2;
+ st.p2 = params->vshader(&vsp);
+
+ st₂.p0 = Pt2(st.p0.x/st.p0.w, st.p0.y/st.p0.w, 1);
+ st₂.p1 = Pt2(st.p1.x/st.p1.w, st.p1.y/st.p1.w, 1);
+ st₂.p2 = Pt2(st.p2.x/st.p2.w, st.p2.y/st.p2.w, 1);
+ bc = barycoords(st₂, centroid(st₂));
+ np0 = centroid3((Triangle3){divpt3(st.p0, st.p0.w),divpt3(st.p1, st.p1.w),divpt3(st.p2, st.p2.w)});
+ np1 = Vec3(
+ nt.p0.x*bc.x + nt.p1.x*bc.y + nt.p2.x*bc.z,
+ nt.p0.y*bc.x + nt.p1.y*bc.y + nt.p2.y*bc.z,
+ nt.p0.z*bc.x + nt.p1.z*bc.y + nt.p2.z*bc.z);
+ np1 = addpt3(np0, mulpt3(np1, 50));
+ triangle(nfb, Pt(st₂.p0.x,st₂.p0.y), Pt(st₂.p1.x,st₂.p1.y), Pt(st₂.p2.x,st₂.p2.y), red);
+ bresenham(nfb, Pt(np0.x,np0.y), Pt(np1.x,np1.y), green);
idxtab = &(*ep)->indextab[OBJVTexture];
if(modeltex != nil && idxtab->nindex == 3){
@@ -553,19 +556,19 @@ shaderunit2(void *arg)
}else
memset(&tt, 0, sizeof tt);
- filltriangle2(params->dst, st, nt, tt, 0, sp.frag);
+ rasterize(params, st, tt, frag);
}
- freememimage(sp.frag);
+ freememimage(frag);
sendp(params->donec, nil);
free(params);
threadexits(nil);
}
void
-shade2(Memimage *dst)
+shade(Memimage *dst, Point3 (*vs)(VSparams*), Memimage *(*fs)(FSparams*))
{
- int i, nelems, nparts;
+ int i, nelems, nparts, nworkers;
OBJObject *o;
OBJElem **elems, *e;
OBJIndexArray *idxtab;
@@ -584,19 +587,27 @@ shade2(Memimage *dst)
elems = erealloc(elems, ++nelems*sizeof(*elems));
elems[nelems-1] = e;
}
- nparts = nelems/nprocs;
+ if(nelems < nprocs){
+ nworkers = nelems;
+ nparts = 1;
+ }else{
+ nworkers = nprocs;
+ nparts = nelems/nprocs;
+ }
donec = chancreate(sizeof(void*), 0);
- for(i = 0; i < nprocs; i++){
+ for(i = 0; i < nworkers; i++){
params = emalloc(sizeof *params);
params->dst = dst;
params->b = &elems[i*nparts];
params->e = params->b + nparts;
params->id = i;
params->donec = donec;
- proccreate(shaderunit2, params, mainstacksize);
- fprint(2, "spawned su %d for elems %d to %d\n", params->id, i*nparts, i*nparts+nparts);
+ params->vshader = vs;
+ params->fshader = fs;
+ proccreate(shaderunit, params, mainstacksize);
+ fprint(2, "spawned su %d for elems [%d, %d)\n", params->id, i*nparts, i*nparts+nparts);
}
while(i--)
@@ -605,7 +616,7 @@ shade2(Memimage *dst)
}
Memimage *
-triangleshader(Sparams *sp)
+triangleshader(FSparams *sp)
{
Triangle2 t;
Rectangle bbox;
@@ -636,7 +647,7 @@ triangleshader(Sparams *sp)
}
Memimage *
-circleshader(Sparams *sp)
+circleshader(FSparams *sp)
{
Point2 uv;
double r;
@@ -661,7 +672,7 @@ circleshader(Sparams *sp)
/* some shaping functions from The Book of Shaders, Chapter 5 */
Memimage *
-sfshader(Sparams *sp)
+sfshader(FSparams *sp)
{
Point2 uv;
double y, pct;
@@ -688,116 +699,39 @@ sfshader(Sparams *sp)
}
Memimage *
-modelshader(Sparams *sp)
+boxshader(FSparams *sp)
{
- OBJObject *o;
- OBJElem *e;
- OBJVertex *verts, *tverts; /* geometric and texture vertices */
- OBJIndexArray *idxtab;
- Triangle3 t, t₂;
- Triangle2 st, tt; /* screen and texture triangles */
- Rectangle bbox;
- Point3 bc, n; /* barycentric coords and surface normal */
- static Point3 light = {0,0,-1,0}; /* global light field */
- Point tp; /* texture point */
- int i;
+ Point2 uv, p;
+ Point2 r;
uchar cbuf[4];
- double z, intensity;
- verts = model->vertdata[OBJVGeometric].verts;
- tverts = model->vertdata[OBJVTexture].verts;
- cbuf[0] = 0xFF;
-
- for(i = 0; i < nelem(model->objtab); i++)
- for(o = model->objtab[i]; o != nil; o = o->next)
- for(e = o->child; e != nil; e = e->next){
- idxtab = &e->indextab[OBJVGeometric];
-
- /* discard non-triangles */
- if(e->type != OBJEFace || idxtab->nindex != 3)
- continue;
+ uv = Pt2(sp->p.x,sp->p.y,1);
+ uv.x /= Dx(fb->r);
+ uv.y /= Dy(fb->r);
+ r = Vec2(0.2,0.4);
- t.p0 = Pt3(verts[idxtab->indices[0]].x,verts[idxtab->indices[0]].y,verts[idxtab->indices[0]].z,verts[idxtab->indices[0]].w);
- t.p1 = Pt3(verts[idxtab->indices[1]].x,verts[idxtab->indices[1]].y,verts[idxtab->indices[1]].z,verts[idxtab->indices[1]].w);
- t.p2 = Pt3(verts[idxtab->indices[2]].x,verts[idxtab->indices[2]].y,verts[idxtab->indices[2]].z,verts[idxtab->indices[2]].w);
-
- t.p0 = xform3(t.p0, rota);
- t.p1 = xform3(t.p1, rota);
- t.p2 = xform3(t.p2, rota);
-
- t₂.p0 = xform3(t.p0, view);
- t₂.p1 = xform3(t.p1, view);
- t₂.p2 = xform3(t.p2, view);
- t₂.p0 = divpt3(t₂.p0, t₂.p0.w);
- t₂.p1 = divpt3(t₂.p1, t₂.p1.w);
- t₂.p2 = divpt3(t₂.p2, t₂.p2.w);
-
- st.p0 = Pt2(t₂.p0.x, t₂.p0.y, 1);
- st.p1 = Pt2(t₂.p1.x, t₂.p1.y, 1);
- st.p2 = Pt2(t₂.p2.x, t₂.p2.y, 1);
-
- bbox = Rect(
- min(min(st.p0.x, st.p1.x), st.p2.x), min(min(st.p0.y, st.p1.y), st.p2.y),
- max(max(st.p0.x, st.p1.x), st.p2.x)+1, max(max(st.p0.y, st.p1.y), st.p2.y)+1
- );
- if(!ptinrect(sp->p, bbox))
- continue;
+ p = Pt2(fabs(uv.x - 0.5), fabs(uv.y - 0.5), 1);
+ p = subpt2(p, r);
+ p.x = fmax(p.x, 0);
+ p.y = fmax(p.y, 0);
- bc = barycoords(st, Pt2(sp->p.x,sp->p.y,1));
- if(bc.x < 0 || bc.y < 0 || bc.z < 0)
- continue;
+ if(vec2len(p) > 0)
+ return nil;
- z = t₂.p0.z*bc.x + t₂.p1.z*bc.y + t₂.p2.z*bc.z;
- if(z <= zbuf[sp->p.x+sp->p.y*Dx(fb->r)])
- continue;
- zbuf[sp->p.x+sp->p.y*Dx(fb->r)] = z;
-
- cbuf[1] = 0xFF*z;
- cbuf[2] = 0xFF*z;
- cbuf[3] = 0xFF*z;
- memfillcolor(sp->frag, *(ulong*)cbuf);
- pixel(zfb, sp->p, sp->frag);
-
- n = normvec3(crossvec3(subpt3(t.p2, t.p0), subpt3(t.p1, t.p0)));
- intensity = dotvec3(n, light);
- /* back-face culling */
- if(intensity <= 0)
- continue;
+ cbuf[0] = 0xFF;
+ cbuf[1] = 0xFF*smoothstep(0,1,uv.x+uv.y);
+ cbuf[2] = 0xFF*uv.y;
+ cbuf[3] = 0xFF*uv.x;
- idxtab = &e->indextab[OBJVTexture];
- if(modeltex != nil && idxtab->nindex == 3){
- tt.p0 = Pt2(tverts[idxtab->indices[0]].u, tverts[idxtab->indices[0]].v, 1);
- tt.p1 = Pt2(tverts[idxtab->indices[1]].u, tverts[idxtab->indices[1]].v, 1);
- tt.p2 = Pt2(tverts[idxtab->indices[2]].u, tverts[idxtab->indices[2]].v, 1);
-
- tt.p0 = mulpt2(tt.p0, bc.x);
- tt.p1 = mulpt2(tt.p1, bc.y);
- tt.p2 = mulpt2(tt.p2, bc.z);
-
- tp.x = (tt.p0.x + tt.p1.x + tt.p2.x)*Dx(modeltex->r);
- tp.y = (1 - (tt.p0.y + tt.p1.y + tt.p2.y))*Dy(modeltex->r);
-
- unloadmemimage(modeltex, rectaddpt(Rect(0,0,1,1), tp), cbuf+1, sizeof cbuf - 1);
- }else{
- cbuf[1] = 0xFF;
- cbuf[2] = 0xFF;
- cbuf[3] = 0xFF;
- }
- cbuf[1] *= intensity;
- cbuf[2] *= intensity;
- cbuf[3] *= intensity;
-
- memfillcolor(sp->frag, *(ulong*)cbuf);
- return sp->frag;
- }
- return nil;
+ memfillcolor(sp->frag, *(ulong*)cbuf);
+ return sp->frag;
}
void
redraw(void)
{
lockdisplay(display);
- memfillcolor(screenfb, DBlack);
+ memfillcolor(screenfb, 0x888888FF);
memimagedraw(screenfb, screenfb->r, curfb, ZP, nil, ZP, SoverD);
if(shownormals)
memimagedraw(screenfb, screenfb->r, nfb, ZP, nil, ZP, SoverD);
@@ -812,10 +746,7 @@ render(void)
uvlong t0, t1;
t0 = nanosec();
- if(flag2)
- shade2(fb);
- else
- shade(fb, model != nil? modelshader: sfshader);
+ shade(fb, vertshader, fragshader);
t1 = nanosec();
fprint(2, "shader took %lludns\n", t1-t0);
}
@@ -915,7 +846,7 @@ key(Rune r)
void
usage(void)
{
- fprint(2, "usage: %s [-2] [-n nprocs] [-m objfile] [-t texfile] [-a yrotangle] [-z camzpos]\n", argv0);
+ fprint(2, "usage: %s [-n nprocs] [-m objfile] [-t texfile] [-a yrotangle] [-z camzpos]\n", argv0);
exits("usage");
}
@@ -933,9 +864,6 @@ threadmain(int argc, char *argv[])
texpath = nil;
θ = 0;
ARGBEGIN{
- case '2':
- flag2++;
- break;
case 'n':
nprocs = strtoul(EARGF(usage()), nil, 10);
break;
@@ -982,25 +910,43 @@ threadmain(int argc, char *argv[])
green = rgb(DGreen);
blue = rgb(DBlue);
- if(mdlpath != nil && (model = objparse(mdlpath)) == nil)
+ if(mdlpath == nil)
+ mdlpath = "mdl/def.obj";
+ if((model = objparse(mdlpath)) == nil)
sysfatal("objparse: %r");
if(texpath != nil && (modeltex = readtga(texpath)) == nil)
sysfatal("readtga: %r");
+ {
+ int i, nv[OBJNVERT], nf;
+ OBJObject *o;
+ OBJElem *e;
+
+ nf = 0;
+ memset(nv, 0, sizeof nv);
+ for(i = 0; i < OBJNVERT; i++) nv[i] += model->vertdata[i].nvert;
+ for(i = 0; i < OBJHTSIZE; i++) if((o = model->objtab[i]) != nil)
+ for(e = o->child; e != nil; e = e->next) if(e->type == OBJEFace) nf++;
+ fprint(2, "v %d vn %d vt %d f %d\n", nv[OBJVGeometric], nv[OBJVNormal], nv[OBJVTexture], nf);
+ }
+
drawc = chancreate(sizeof(void*), 1);
display->locking = 1;
unlockdisplay(display);
- proj[3][2] = -1.0/camera.z;
Matrix3 yrot = {
cos(θ), 0, -sin(θ), 0,
0, 1, 0, 0,
sin(θ), 0, cos(θ), 0,
0, 0, 0, 1,
};
- identity3(rota);
+ viewport(fb->r);
+ projection(-1.0/vec3len(subpt3(camera, center)));
+ lookat(camera, center, up);
mulm3(rota, yrot);
+ mulm3(proj, rota);
mulm3(view, proj);
+
rendering = 1;
proccreate(renderer, nil, mainstacksize);
threadcreate(scrsync, nil, mainstacksize);
diff --git a/mdl/def.obj b/mdl/def.obj
new file mode 100644
index 0000000..48cc560
--- /dev/null
+++ b/mdl/def.obj
@@ -0,0 +1,6 @@
+v -100 -100 0
+v 100 -100 0
+v -100 100 0
+v 100 100 0
+f 1 2 3
+f 4 3 2