ref: cdb4aca6643ebde7cfb7af332cb323ba2afacf15
parent: ec90599ffe6fedf2019fb2d0972497b5f9aa7229
author: rodri <rgl@antares-labs.eu>
date: Sat Sep 21 07:44:08 EDT 2024
put all the shaders in a single file.
--- a/med.c
+++ b/med.c
@@ -106,6 +106,8 @@
static int showhud;
Color (*tsampler)(Texture*,Point2);
+#include "shaders.inc"
+
static Point3
Vecquat(Quaternion q)
{
@@ -248,205 +250,6 @@
c->scn = newscene(nil);
addbasis(c->scn);
placecamera(c->cam, c->scn, camcfg.p, center, Vec3(0,1,0));
-}
-
-Point3
-gouraudvshader(Shaderparams *sp)
-{
- static double Ka = 0.1; /* ambient factor */
- static double Ks = 0.5; /* specular factor */
- double Kd; /* diffuse factor */
- double spec;
- Point3 pos, lightdir, lookdir;
- Material m;
- Color ambient, diffuse, specular, lightc;
-
- sp->v->n = model2world(sp->su->entity, sp->v->n);
- sp->v->p = model2world(sp->su->entity, sp->v->p);
- pos = sp->v->p;
-
- if(sp->v->mtl != nil)
- m = *sp->v->mtl;
- else{
- memset(&m, 0, sizeof m);
- m.diffuse = sp->v->c;
- m.specular = Pt3(1,1,1,1);
- m.shininess = 1;
- }
-
- lightdir = normvec3(subpt3(light.p, pos));
- lightc = getlightcolor(&light, lightdir);
-
- ambient = mulpt3(lightc, Ka);
- ambient = modulapt3(ambient, m.diffuse);
-
- Kd = max(0, dotvec3(sp->v->n, lightdir));
- diffuse = mulpt3(lightc, Kd);
- diffuse = modulapt3(diffuse, m.diffuse);
-
- lookdir = normvec3(subpt3(sp->su->camera->p, pos));
- lightdir = qrotate(lightdir, sp->v->n, PI);
- spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess);
- specular = mulpt3(lightc, spec*Ks);
- specular = modulapt3(specular, m.specular);
-
- sp->v->c = addpt3(ambient, addpt3(diffuse, specular));
- sp->v->c.a = m.diffuse.a;
- return world2clip(sp->su->camera, pos);
-}
-
-Color
-gouraudshader(Shaderparams *sp)
-{
- Color tc;
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
- else
- tc = Pt3(1,1,1,1);
-
- return modulapt3(sp->v->c, tc);
-}
-
-Point3
-phongvshader(Shaderparams *sp)
-{
- Point3 pos;
- Color a, d, s;
- double ss;
-
- sp->v->n = model2world(sp->su->entity, sp->v->n);
- sp->v->p = model2world(sp->su->entity, sp->v->p);
- pos = sp->v->p;
- sp->setattr(sp, "pos", VAPoint, &pos);
- if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){
- sp->v->tangent = model2world(sp->su->entity, sp->v->tangent);
- sp->setattr(sp, "tangent", VAPoint, &sp->v->tangent);
- }
- if(sp->v->mtl != nil){
- a = sp->v->mtl->ambient;
- d = sp->v->mtl->diffuse;
- s = sp->v->mtl->specular;
- ss = sp->v->mtl->shininess;
- sp->setattr(sp, "ambient", VAPoint, &a);
- sp->setattr(sp, "diffuse", VAPoint, &d);
- sp->setattr(sp, "specular", VAPoint, &s);
- sp->setattr(sp, "shininess", VANumber, &ss);
- }
- return world2clip(sp->su->camera, pos);
-}
-
-Color
-phongshader(Shaderparams *sp)
-{
- static double Ka = 0.1; /* ambient factor */
- static double Ks = 0.5; /* specular factor */
- double Kd; /* diffuse factor */
- double spec;
- Color ambient, diffuse, specular, lightc, c;
- Point3 pos, n, lightdir, lookdir;
- Material m;
- RFrame3 TBN;
- Vertexattr *va;
-
- va = sp->getattr(sp, "pos");
- pos = va->p;
-
- va = sp->getattr(sp, "ambient");
- m.ambient = va != nil? va->p: Pt3(1,1,1,1);
- va = sp->getattr(sp, "diffuse");
- m.diffuse = va != nil? va->p: sp->v->c;
- va = sp->getattr(sp, "specular");
- m.specular = va != nil? va->p: Pt3(1,1,1,1);
- va = sp->getattr(sp, "shininess");
- m.shininess = va != nil? va->n: 1;
-
- lightdir = normvec3(subpt3(light.p, pos));
- lightc = getlightcolor(&light, lightdir);
-
- /* normal mapping */
- va = sp->getattr(sp, "tangent");
- if(va == nil)
- n = sp->v->n;
- else{
- /* TODO implement this on the VS instead and apply Gram-Schmidt here */
- n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler);
- n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1)));
-
- TBN.p = Pt3(0,0,0,1);
- TBN.bx = va->p; /* T */
- TBN.bz = sp->v->n; /* N */
- TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */
-
- n = normvec3(invrframexform3(n, TBN));
- sp->v->n = n;
- }
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
-
- ambient = mulpt3(lightc, Ka);
- ambient = modulapt3(ambient, m.diffuse);
-
- Kd = max(0, dotvec3(n, lightdir));
- diffuse = mulpt3(lightc, Kd);
- diffuse = modulapt3(diffuse, m.diffuse);
-
- if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0)
- m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler);
-
- lookdir = normvec3(subpt3(sp->su->camera->p, pos));
- lightdir = qrotate(lightdir, n, PI);
- spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess);
- specular = mulpt3(lightc, spec*Ks);
- specular = modulapt3(specular, m.specular);
-
- c = addpt3(ambient, addpt3(diffuse, specular));
- c.a = m.diffuse.a;
- return c;
-}
-
-Point3
-identvshader(Shaderparams *sp)
-{
- if(sp->v->mtl != nil)
- sp->v->c = sp->v->mtl->diffuse;
- return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p));
-}
-
-Color
-identshader(Shaderparams *sp)
-{
- Color tc;
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
- else
- tc = Pt3(1,1,1,1);
-
- return modulapt3(sp->v->c, tc);
-}
-
-Shadertab shadertab[] = {
- { "ident", identvshader, identshader },
- { "gouraud", gouraudvshader, gouraudshader },
- { "phong", phongvshader, phongshader },
-};
-Shadertab *
-getshader(char *name)
-{
- int i;
-
- for(i = 0; i < nelem(shadertab); i++)
- if(strcmp(shadertab[i].name, name) == 0)
- return &shadertab[i];
- return nil;
}
void
--- /dev/null
+++ b/shaders.inc
@@ -1,0 +1,421 @@
+
+Point3
+gouraudvshader(Shaderparams *sp)
+{
+ static double Ka = 0.1; /* ambient factor */
+ static double Ks = 0.5; /* specular factor */
+ double Kd; /* diffuse factor */
+ double spec;
+ Point3 pos, lightdir, lookdir;
+ Material m;
+ Color ambient, diffuse, specular, lightc;
+
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ pos = sp->v->p;
+
+ if(sp->v->mtl != nil)
+ m = *sp->v->mtl;
+ else{
+ memset(&m, 0, sizeof m);
+ m.diffuse = sp->v->c;
+ m.specular = Pt3(1,1,1,1);
+ m.shininess = 1;
+ }
+
+ lightdir = normvec3(subpt3(light.p, pos));
+ lightc = getlightcolor(&light, lightdir);
+
+ ambient = mulpt3(lightc, Ka);
+ ambient = modulapt3(ambient, m.diffuse);
+
+ Kd = max(0, dotvec3(sp->v->n, lightdir));
+ diffuse = mulpt3(lightc, Kd);
+ diffuse = modulapt3(diffuse, m.diffuse);
+
+ lookdir = normvec3(subpt3(sp->su->camera->p, pos));
+ lightdir = qrotate(lightdir, sp->v->n, PI);
+ spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess);
+ specular = mulpt3(lightc, spec*Ks);
+ specular = modulapt3(specular, m.specular);
+
+ sp->v->c = addpt3(ambient, addpt3(diffuse, specular));
+ sp->v->c.a = m.diffuse.a;
+ return world2clip(sp->su->camera, pos);
+}
+
+Color
+gouraudshader(Shaderparams *sp)
+{
+ Color tc;
+
+ if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
+ tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
+ else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
+ tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
+ else
+ tc = Pt3(1,1,1,1);
+
+ sp->v->n.w = 1;
+ sp->toraster(sp, "normals", &sp->v->n);
+
+ return modulapt3(sp->v->c, tc);
+}
+
+Point3
+phongvshader(Shaderparams *sp)
+{
+ Point3 pos;
+ Color a, d, s;
+ double ss;
+
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ pos = sp->v->p;
+ sp->setattr(sp, "pos", VAPoint, &pos);
+ if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){
+ sp->v->tangent = model2world(sp->su->entity, sp->v->tangent);
+ sp->setattr(sp, "tangent", VAPoint, &sp->v->tangent);
+ }
+ if(sp->v->mtl != nil){
+ a = sp->v->mtl->ambient;
+ d = sp->v->mtl->diffuse;
+ s = sp->v->mtl->specular;
+ ss = sp->v->mtl->shininess;
+ sp->setattr(sp, "ambient", VAPoint, &a);
+ sp->setattr(sp, "diffuse", VAPoint, &d);
+ sp->setattr(sp, "specular", VAPoint, &s);
+ sp->setattr(sp, "shininess", VANumber, &ss);
+ }
+ return world2clip(sp->su->camera, pos);
+}
+
+Color
+phongshader(Shaderparams *sp)
+{
+ static double Ka = 0.1; /* ambient factor */
+ static double Ks = 0.5; /* specular factor */
+ double Kd; /* diffuse factor */
+ double spec;
+ Color ambient, diffuse, specular, lightc, c;
+ Point3 pos, n, lightdir, lookdir;
+ Material m;
+ RFrame3 TBN;
+ Vertexattr *va;
+
+ va = sp->getattr(sp, "pos");
+ pos = va->p;
+
+ va = sp->getattr(sp, "ambient");
+ m.ambient = va != nil? va->p: Pt3(1,1,1,1);
+ va = sp->getattr(sp, "diffuse");
+ m.diffuse = va != nil? va->p: sp->v->c;
+ va = sp->getattr(sp, "specular");
+ m.specular = va != nil? va->p: Pt3(1,1,1,1);
+ va = sp->getattr(sp, "shininess");
+ m.shininess = va != nil? va->n: 1;
+
+ lightdir = normvec3(subpt3(light.p, pos));
+ lightc = getlightcolor(&light, lightdir);
+
+ /* normal mapping */
+ va = sp->getattr(sp, "tangent");
+ if(va == nil)
+ n = sp->v->n;
+ else{
+ /* TODO implement this on the VS instead and apply Gram-Schmidt here */
+ n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler);
+ n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1)));
+
+ TBN.p = Pt3(0,0,0,1);
+ TBN.bx = va->p; /* T */
+ TBN.bz = sp->v->n; /* N */
+ TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */
+
+ n = normvec3(invrframexform3(n, TBN));
+ sp->v->n = n;
+ }
+
+ if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
+ m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
+ else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
+ m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
+
+ ambient = mulpt3(lightc, Ka);
+ ambient = modulapt3(ambient, m.diffuse);
+
+ Kd = max(0, dotvec3(n, lightdir));
+ diffuse = mulpt3(lightc, Kd);
+ diffuse = modulapt3(diffuse, m.diffuse);
+
+ if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0)
+ m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler);
+
+ lookdir = normvec3(subpt3(sp->su->camera->p, pos));
+ lightdir = qrotate(lightdir, n, PI);
+ spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess);
+ specular = mulpt3(lightc, spec*Ks);
+ specular = modulapt3(specular, m.specular);
+
+ sp->v->n.w = 1;
+ sp->toraster(sp, "normals", &sp->v->n);
+
+ c = addpt3(ambient, addpt3(diffuse, specular));
+ c.a = m.diffuse.a;
+ return c;
+}
+
+Color
+blinnshader(Shaderparams *sp)
+{
+ static double Ka = 0.1; /* ambient factor */
+ static double Ks = 0.5; /* specular factor */
+ double Kd; /* diffuse factor */
+ double spec;
+ Color ambient, diffuse, specular, lightc, c;
+ Point3 pos, n, lightdir, lookdir;
+ Material m;
+ RFrame3 TBN;
+ Vertexattr *va;
+
+ va = sp->getattr(sp, "pos");
+ pos = va->p;
+
+ va = sp->getattr(sp, "ambient");
+ m.ambient = va != nil? va->p: Pt3(1,1,1,1);
+ va = sp->getattr(sp, "diffuse");
+ m.diffuse = va != nil? va->p: sp->v->c;
+ va = sp->getattr(sp, "specular");
+ m.specular = va != nil? va->p: Pt3(1,1,1,1);
+ va = sp->getattr(sp, "shininess");
+ m.shininess = va != nil? va->n: 1;
+
+ lightdir = normvec3(subpt3(light.p, pos));
+ lightc = getlightcolor(&light, lightdir);
+
+ /* normal mapping */
+ va = sp->getattr(sp, "tangent");
+ if(va == nil)
+ n = sp->v->n;
+ else{
+ /* TODO implement this on the VS instead and apply Gram-Schmidt here */
+ n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler);
+ n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1)));
+
+ TBN.p = Pt3(0,0,0,1);
+ TBN.bx = va->p; /* T */
+ TBN.bz = sp->v->n; /* N */
+ TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */
+
+ n = normvec3(invrframexform3(n, TBN));
+ sp->v->n = n;
+ }
+
+ if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
+ m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
+ else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
+ m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
+
+ ambient = mulpt3(lightc, Ka);
+ ambient = modulapt3(ambient, m.diffuse);
+
+ Kd = max(0, dotvec3(n, lightdir));
+ diffuse = mulpt3(lightc, Kd);
+ diffuse = modulapt3(diffuse, m.diffuse);
+
+ if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0)
+ m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler);
+
+ lookdir = normvec3(subpt3(sp->su->camera->p, pos));
+ lightdir = normvec3(addpt3(lookdir, lightdir)); /* half vector */
+ spec = pow(max(0, dotvec3(n, lightdir)), m.shininess);
+ specular = mulpt3(lightc, spec*Ks);
+ specular = modulapt3(specular, m.specular);
+
+ sp->v->n.w = 1;
+ sp->toraster(sp, "normals", &sp->v->n);
+
+ c = addpt3(ambient, addpt3(diffuse, specular));
+ c.a = m.diffuse.a;
+ return c;
+}
+
+Point3
+toonvshader(Shaderparams *sp)
+{
+ Point3 pos, lightdir;
+ double intens;
+
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ pos = model2world(sp->su->entity, sp->v->p);
+ lightdir = normvec3(subpt3(light.p, pos));
+ intens = max(0, dotvec3(sp->v->n, lightdir));
+ sp->setattr(sp, "intensity", VANumber, &intens);
+ if(sp->v->mtl != nil)
+ sp->v->c = sp->v->mtl->diffuse;
+ return world2clip(sp->su->camera, pos);
+}
+
+Color
+toonshader(Shaderparams *sp)
+{
+ Vertexattr *va;
+ double intens;
+
+ va = sp->getattr(sp, "intensity");
+ intens = va->n;
+ intens = intens > 0.85? 1:
+ intens > 0.60? 0.80:
+ intens > 0.45? 0.60:
+ intens > 0.30? 0.45:
+ intens > 0.15? 0.30: 0.15;
+
+ sp->v->n.w = 1;
+ sp->toraster(sp, "normals", &sp->v->n);
+
+ return Pt3(intens, 0.6*intens, 0, 1);
+}
+
+Point3
+identvshader(Shaderparams *sp)
+{
+ if(sp->v->mtl != nil)
+ sp->v->c = sp->v->mtl->diffuse;
+ return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p));
+}
+
+Color
+identshader(Shaderparams *sp)
+{
+ Color tc;
+
+ if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
+ tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
+ else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
+ tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
+ else
+ tc = Pt3(1,1,1,1);
+
+ sp->v->n.w = 1;
+ sp->toraster(sp, "normals", &sp->v->n);
+
+ return modulapt3(sp->v->c, tc);
+}
+
+Point3
+ivshader(Shaderparams *sp)
+{
+ sp->v->n = model2world(sp->su->entity, sp->v->n);
+ sp->v->p = model2world(sp->su->entity, sp->v->p);
+ return world2clip(sp->su->camera, sp->v->p);
+}
+
+Color
+triangleshader(Shaderparams *sp)
+{
+ Triangle2 t;
+ Rectangle bbox;
+ Point3 bc;
+
+ t.p0 = Pt2(240,200,1);
+ t.p1 = Pt2(400,40,1);
+ t.p2 = Pt2(240,40,1);
+
+ bbox = Rect(
+ min(min(t.p0.x, t.p1.x), t.p2.x), min(min(t.p0.y, t.p1.y), t.p2.y),
+ max(max(t.p0.x, t.p1.x), t.p2.x), max(max(t.p0.y, t.p1.y), t.p2.y)
+ );
+ if(!ptinrect(sp->p, bbox))
+ return Vec3(0,0,0);
+
+ bc = barycoords(t, Pt2(sp->p.x,sp->p.y,1));
+ if(bc.x < 0 || bc.y < 0 || bc.z < 0)
+ return Vec3(0,0,0);
+
+ return Pt3(bc.x, bc.y, bc.z, 1);
+}
+
+Color
+circleshader(Shaderparams *sp)
+{
+ Point2 uv;
+ double r, d;
+
+ uv = Pt2(sp->p.x,sp->p.y,1);
+ uv.x /= Dx(sp->su->fb->r);
+ uv.y /= Dy(sp->su->fb->r);
+// r = 0.3;
+ r = 0.3*fabs(sin(sp->su->uni_time/1e9));
+ d = vec2len(subpt2(uv, Vec2(0.5,0.5)));
+
+ if(d > r + r*0.05 || d < r - r*0.05)
+ return Vec3(0,0,0);
+
+ return Pt3(uv.x, uv.y, 0, 1);
+}
+
+/* some shaping functions from The Book of Shaders, Chapter 5 */
+Color
+sfshader(Shaderparams *sp)
+{
+ Point2 uv;
+ double y, pct;
+
+ uv = Pt2(sp->p.x,sp->p.y,1);
+ uv.x /= Dx(sp->su->fb->r);
+ uv.y /= Dy(sp->su->fb->r);
+ uv.y = 1 - uv.y; /* make [0 0] the bottom-left corner */
+
+// y = step(0.5, uv.x);
+// y = pow(uv.x, 5);
+// y = sin(uv.x);
+ y = sin(uv.x*sp->su->uni_time/1e8)/2.0 + 0.5;
+// y = smoothstep(0.1, 0.9, uv.x);
+ pct = smoothstep(y-0.02, y, uv.y) - smoothstep(y, y+0.02, uv.y);
+
+ return Pt3(flerp(y, 0, pct), flerp(y, 1, pct), flerp(y, 0, pct), 1);
+}
+
+Color
+boxshader(Shaderparams *sp)
+{
+ Point2 uv, p;
+ Point2 r;
+
+ uv = Pt2(sp->p.x,sp->p.y,1);
+ uv.x /= Dx(sp->su->fb->r);
+ uv.y /= Dy(sp->su->fb->r);
+ r = Vec2(0.2,0.4);
+
+ p = Pt2(fabs(uv.x - 0.5), fabs(uv.y - 0.5), 1);
+ p = subpt2(p, r);
+ p.x = max(p.x, 0);
+ p.y = max(p.y, 0);
+
+ if(vec2len(p) > 0)
+ return Vec3(0,0,0);
+
+ return Pt3(uv.x, uv.y, smoothstep(0,1,uv.x+uv.y), 1);
+}
+
+Shadertab shadertab[] = {
+ { "triangle", ivshader, triangleshader },
+ { "circle", ivshader, circleshader },
+ { "box", ivshader, boxshader },
+ { "sf", ivshader, sfshader },
+ { "toon", toonvshader, toonshader },
+ { "ident", identvshader, identshader },
+ { "gouraud", gouraudvshader, gouraudshader },
+ { "phong", phongvshader, phongshader },
+ { "blinn", phongvshader, blinnshader },
+};
+Shadertab *
+getshader(char *name)
+{
+ int i;
+
+ for(i = 0; i < nelem(shadertab); i++)
+ if(strcmp(shadertab[i].name, name) == 0)
+ return &shadertab[i];
+ return nil;
+}
--- a/vis.c
+++ b/vis.c
@@ -98,6 +98,8 @@
static int abuffon;
Color (*tsampler)(Texture*,Point2);
+#include "shaders.inc"
+
static Point3
Vecquat(Quaternion q)
{
@@ -108,427 +110,6 @@
Ptquat(Quaternion q, double w)
{
return Pt3(q.i, q.j, q.k, w);
-}
-
-Point3
-gouraudvshader(Shaderparams *sp)
-{
- static double Ka = 0.1; /* ambient factor */
- static double Ks = 0.5; /* specular factor */
- double Kd; /* diffuse factor */
- double spec;
- Point3 pos, lightdir, lookdir;
- Material m;
- Color ambient, diffuse, specular, lightc;
-
- sp->v->n = model2world(sp->su->entity, sp->v->n);
- sp->v->p = model2world(sp->su->entity, sp->v->p);
- pos = sp->v->p;
-
- if(sp->v->mtl != nil)
- m = *sp->v->mtl;
- else{
- memset(&m, 0, sizeof m);
- m.diffuse = sp->v->c;
- m.specular = Pt3(1,1,1,1);
- m.shininess = 1;
- }
-
- lightdir = normvec3(subpt3(light.p, pos));
- lightc = getlightcolor(&light, lightdir);
-
- ambient = mulpt3(lightc, Ka);
- ambient = modulapt3(ambient, m.diffuse);
-
- Kd = max(0, dotvec3(sp->v->n, lightdir));
- diffuse = mulpt3(lightc, Kd);
- diffuse = modulapt3(diffuse, m.diffuse);
-
- lookdir = normvec3(subpt3(sp->su->camera->p, pos));
- lightdir = qrotate(lightdir, sp->v->n, PI);
- spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess);
- specular = mulpt3(lightc, spec*Ks);
- specular = modulapt3(specular, m.specular);
-
- sp->v->c = addpt3(ambient, addpt3(diffuse, specular));
- sp->v->c.a = m.diffuse.a;
- return world2clip(sp->su->camera, pos);
-}
-
-Color
-gouraudshader(Shaderparams *sp)
-{
- Color tc;
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
- else
- tc = Pt3(1,1,1,1);
-
- sp->v->n.w = 1;
- sp->toraster(sp, "normals", &sp->v->n);
-
- return modulapt3(sp->v->c, tc);
-}
-
-Point3
-phongvshader(Shaderparams *sp)
-{
- Point3 pos;
- Color a, d, s;
- double ss;
-
- sp->v->n = model2world(sp->su->entity, sp->v->n);
- sp->v->p = model2world(sp->su->entity, sp->v->p);
- pos = sp->v->p;
- sp->setattr(sp, "pos", VAPoint, &pos);
- if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){
- sp->v->tangent = model2world(sp->su->entity, sp->v->tangent);
- sp->setattr(sp, "tangent", VAPoint, &sp->v->tangent);
- }
- if(sp->v->mtl != nil){
- a = sp->v->mtl->ambient;
- d = sp->v->mtl->diffuse;
- s = sp->v->mtl->specular;
- ss = sp->v->mtl->shininess;
- sp->setattr(sp, "ambient", VAPoint, &a);
- sp->setattr(sp, "diffuse", VAPoint, &d);
- sp->setattr(sp, "specular", VAPoint, &s);
- sp->setattr(sp, "shininess", VANumber, &ss);
- }
- return world2clip(sp->su->camera, pos);
-}
-
-Color
-phongshader(Shaderparams *sp)
-{
- static double Ka = 0.1; /* ambient factor */
- static double Ks = 0.5; /* specular factor */
- double Kd; /* diffuse factor */
- double spec;
- Color ambient, diffuse, specular, lightc, c;
- Point3 pos, n, lightdir, lookdir;
- Material m;
- RFrame3 TBN;
- Vertexattr *va;
-
- va = sp->getattr(sp, "pos");
- pos = va->p;
-
- va = sp->getattr(sp, "ambient");
- m.ambient = va != nil? va->p: Pt3(1,1,1,1);
- va = sp->getattr(sp, "diffuse");
- m.diffuse = va != nil? va->p: sp->v->c;
- va = sp->getattr(sp, "specular");
- m.specular = va != nil? va->p: Pt3(1,1,1,1);
- va = sp->getattr(sp, "shininess");
- m.shininess = va != nil? va->n: 1;
-
- lightdir = normvec3(subpt3(light.p, pos));
- lightc = getlightcolor(&light, lightdir);
-
- /* normal mapping */
- va = sp->getattr(sp, "tangent");
- if(va == nil)
- n = sp->v->n;
- else{
- /* TODO implement this on the VS instead and apply Gram-Schmidt here */
- n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler);
- n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1)));
-
- TBN.p = Pt3(0,0,0,1);
- TBN.bx = va->p; /* T */
- TBN.bz = sp->v->n; /* N */
- TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */
-
- n = normvec3(invrframexform3(n, TBN));
- sp->v->n = n;
- }
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
-
- ambient = mulpt3(lightc, Ka);
- ambient = modulapt3(ambient, m.diffuse);
-
- Kd = max(0, dotvec3(n, lightdir));
- diffuse = mulpt3(lightc, Kd);
- diffuse = modulapt3(diffuse, m.diffuse);
-
- if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0)
- m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler);
-
- lookdir = normvec3(subpt3(sp->su->camera->p, pos));
- lightdir = qrotate(lightdir, n, PI);
- spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess);
- specular = mulpt3(lightc, spec*Ks);
- specular = modulapt3(specular, m.specular);
-
- sp->v->n.w = 1;
- sp->toraster(sp, "normals", &sp->v->n);
-
- c = addpt3(ambient, addpt3(diffuse, specular));
- c.a = m.diffuse.a;
- return c;
-}
-
-Color
-blinnshader(Shaderparams *sp)
-{
- static double Ka = 0.1; /* ambient factor */
- static double Ks = 0.5; /* specular factor */
- double Kd; /* diffuse factor */
- double spec;
- Color ambient, diffuse, specular, lightc, c;
- Point3 pos, n, lightdir, lookdir;
- Material m;
- RFrame3 TBN;
- Vertexattr *va;
-
- va = sp->getattr(sp, "pos");
- pos = va->p;
-
- va = sp->getattr(sp, "ambient");
- m.ambient = va != nil? va->p: Pt3(1,1,1,1);
- va = sp->getattr(sp, "diffuse");
- m.diffuse = va != nil? va->p: sp->v->c;
- va = sp->getattr(sp, "specular");
- m.specular = va != nil? va->p: Pt3(1,1,1,1);
- va = sp->getattr(sp, "shininess");
- m.shininess = va != nil? va->n: 1;
-
- lightdir = normvec3(subpt3(light.p, pos));
- lightc = getlightcolor(&light, lightdir);
-
- /* normal mapping */
- va = sp->getattr(sp, "tangent");
- if(va == nil)
- n = sp->v->n;
- else{
- /* TODO implement this on the VS instead and apply Gram-Schmidt here */
- n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler);
- n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1)));
-
- TBN.p = Pt3(0,0,0,1);
- TBN.bx = va->p; /* T */
- TBN.bz = sp->v->n; /* N */
- TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */
-
- n = normvec3(invrframexform3(n, TBN));
- sp->v->n = n;
- }
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
-
- ambient = mulpt3(lightc, Ka);
- ambient = modulapt3(ambient, m.diffuse);
-
- Kd = max(0, dotvec3(n, lightdir));
- diffuse = mulpt3(lightc, Kd);
- diffuse = modulapt3(diffuse, m.diffuse);
-
- if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0)
- m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler);
-
- lookdir = normvec3(subpt3(sp->su->camera->p, pos));
- lightdir = normvec3(addpt3(lookdir, lightdir)); /* half vector */
- spec = pow(max(0, dotvec3(n, lightdir)), m.shininess);
- specular = mulpt3(lightc, spec*Ks);
- specular = modulapt3(specular, m.specular);
-
- sp->v->n.w = 1;
- sp->toraster(sp, "normals", &sp->v->n);
-
- c = addpt3(ambient, addpt3(diffuse, specular));
- c.a = m.diffuse.a;
- return c;
-}
-
-Point3
-toonvshader(Shaderparams *sp)
-{
- Point3 pos, lightdir;
- double intens;
-
- sp->v->n = model2world(sp->su->entity, sp->v->n);
- pos = model2world(sp->su->entity, sp->v->p);
- lightdir = normvec3(subpt3(light.p, pos));
- intens = max(0, dotvec3(sp->v->n, lightdir));
- sp->setattr(sp, "intensity", VANumber, &intens);
- if(sp->v->mtl != nil)
- sp->v->c = sp->v->mtl->diffuse;
- return world2clip(sp->su->camera, pos);
-}
-
-Color
-toonshader(Shaderparams *sp)
-{
- Vertexattr *va;
- double intens;
-
- va = sp->getattr(sp, "intensity");
- intens = va->n;
- intens = intens > 0.85? 1:
- intens > 0.60? 0.80:
- intens > 0.45? 0.60:
- intens > 0.30? 0.45:
- intens > 0.15? 0.30: 0.15;
-
- sp->v->n.w = 1;
- sp->toraster(sp, "normals", &sp->v->n);
-
- return Pt3(intens, 0.6*intens, 0, 1);
-}
-
-Point3
-identvshader(Shaderparams *sp)
-{
- if(sp->v->mtl != nil)
- sp->v->c = sp->v->mtl->diffuse;
- return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p));
-}
-
-Color
-identshader(Shaderparams *sp)
-{
- Color tc;
-
- if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler);
- else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0)
- tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler);
- else
- tc = Pt3(1,1,1,1);
-
- sp->v->n.w = 1;
- sp->toraster(sp, "normals", &sp->v->n);
-
- return modulapt3(sp->v->c, tc);
-}
-
-Point3
-ivshader(Shaderparams *sp)
-{
- sp->v->n = model2world(sp->su->entity, sp->v->n);
- sp->v->p = model2world(sp->su->entity, sp->v->p);
- return world2clip(sp->su->camera, sp->v->p);
-}
-
-Color
-triangleshader(Shaderparams *sp)
-{
- Triangle2 t;
- Rectangle bbox;
- Point3 bc;
-
- t.p0 = Pt2(240,200,1);
- t.p1 = Pt2(400,40,1);
- t.p2 = Pt2(240,40,1);
-
- bbox = Rect(
- min(min(t.p0.x, t.p1.x), t.p2.x), min(min(t.p0.y, t.p1.y), t.p2.y),
- max(max(t.p0.x, t.p1.x), t.p2.x), max(max(t.p0.y, t.p1.y), t.p2.y)
- );
- if(!ptinrect(sp->p, bbox))
- return Vec3(0,0,0);
-
- bc = barycoords(t, Pt2(sp->p.x,sp->p.y,1));
- if(bc.x < 0 || bc.y < 0 || bc.z < 0)
- return Vec3(0,0,0);
-
- return Pt3(bc.x, bc.y, bc.z, 1);
-}
-
-Color
-circleshader(Shaderparams *sp)
-{
- Point2 uv;
- double r, d;
-
- uv = Pt2(sp->p.x,sp->p.y,1);
- uv.x /= Dx(sp->su->fb->r);
- uv.y /= Dy(sp->su->fb->r);
-// r = 0.3;
- r = 0.3*fabs(sin(sp->su->uni_time/1e9));
- d = vec2len(subpt2(uv, Vec2(0.5,0.5)));
-
- if(d > r + r*0.05 || d < r - r*0.05)
- return Vec3(0,0,0);
-
- return Pt3(uv.x, uv.y, 0, 1);
-}
-
-/* some shaping functions from The Book of Shaders, Chapter 5 */
-Color
-sfshader(Shaderparams *sp)
-{
- Point2 uv;
- double y, pct;
-
- uv = Pt2(sp->p.x,sp->p.y,1);
- uv.x /= Dx(sp->su->fb->r);
- uv.y /= Dy(sp->su->fb->r);
- uv.y = 1 - uv.y; /* make [0 0] the bottom-left corner */
-
-// y = step(0.5, uv.x);
-// y = pow(uv.x, 5);
-// y = sin(uv.x);
- y = sin(uv.x*sp->su->uni_time/1e8)/2.0 + 0.5;
-// y = smoothstep(0.1, 0.9, uv.x);
- pct = smoothstep(y-0.02, y, uv.y) - smoothstep(y, y+0.02, uv.y);
-
- return Pt3(flerp(y, 0, pct), flerp(y, 1, pct), flerp(y, 0, pct), 1);
-}
-
-Color
-boxshader(Shaderparams *sp)
-{
- Point2 uv, p;
- Point2 r;
-
- uv = Pt2(sp->p.x,sp->p.y,1);
- uv.x /= Dx(sp->su->fb->r);
- uv.y /= Dy(sp->su->fb->r);
- r = Vec2(0.2,0.4);
-
- p = Pt2(fabs(uv.x - 0.5), fabs(uv.y - 0.5), 1);
- p = subpt2(p, r);
- p.x = max(p.x, 0);
- p.y = max(p.y, 0);
-
- if(vec2len(p) > 0)
- return Vec3(0,0,0);
-
- return Pt3(uv.x, uv.y, smoothstep(0,1,uv.x+uv.y), 1);
-}
-
-Shadertab shadertab[] = {
- { "triangle", ivshader, triangleshader },
- { "circle", ivshader, circleshader },
- { "box", ivshader, boxshader },
- { "sf", ivshader, sfshader },
- { "toon", toonvshader, toonshader },
- { "ident", identvshader, identshader },
- { "gouraud", gouraudvshader, gouraudshader },
- { "phong", phongvshader, phongshader },
- { "blinn", phongvshader, blinnshader },
-};
-Shadertab *
-getshader(char *name)
-{
- int i;
-
- for(i = 0; i < nelem(shadertab); i++)
- if(strcmp(shadertab[i].name, name) == 0)
- return &shadertab[i];
- return nil;
}
void