ref: 263444216730830b712a4f8f3a087513c5ac93e9
parent: a435467f81a1d9d429109f3a34988c642bed6035
author: rodri <rgl@antares-labs.eu>
date: Fri Mar 6 16:05:07 EST 2020
redesign of the camera abstraction. general unused/useless data cleaning.
--- a/dat.h
+++ b/dat.h
@@ -26,16 +26,3 @@
Scambx, Scamby, Scambz,
Se
};
-
-typedef struct Mesh Mesh;
-typedef struct TTriangle3 TTriangle3;
-
-struct Mesh {
- Triangle3 *tris;
- int ntri;
-};
-
-struct TTriangle3 {
- Triangle3;
- Image *tx;
-};
--- a/graphics.h
+++ b/graphics.h
@@ -10,23 +10,28 @@
struct Vertex {
Point3 p; /* position */
Point3 n; /* surface normal */
- //Image tx; /* (?) */
};
+struct Viewport
+{
+ RFrame;
+ Memimage *fb;
+};
+
struct Camera {
RFrame3; /* VCS */
- Image *viewport;
+ Viewport viewport;
double fov; /* vertical FOV */
- struct {
- double n, f; /* near and far clipping planes */
- } clip;
+ double clipn;
+ double clipf;
Matrix3 proj; /* VCS to NDC xform */
Projection ptype;
+
+ void (*updatefb)(Camera*, Rectangle, ulong);
};
/* Camera */
-void perspective(Matrix3, double, double, double, double);
-void orthographic(Matrix3, double, double, double, double, double, double);
+Camera *alloccamera(Rectangle, ulong);
void configcamera(Camera*, Image*, double, double, double, Projection);
void placecamera(Camera*, Point3, Point3, Point3);
void aimcamera(Camera*, Point3);
@@ -33,12 +38,14 @@
void reloadcamera(Camera*);
/* rendering */
-#define FPS2MS(n) (1000/(n))
+#define FPS2MS(n) (1000/(n))
#define WORLD2VCS(cp, p) (rframexform3((p), *(cp)))
-#define VCS2NDC(cp, p) (xform3((p), (cp)->proj))
+#define VCS2NDC(cp, p) (xform3((p), (cp)->proj))
#define WORLD2NDC(cp, p) (VCS2NDC((cp), WORLD2VCS((cp), (p))))
int isclipping(Point3);
Point toviewport(Camera*, Point3);
Point2 fromviewport(Camera*, Point);
-void line3(Camera *c, Point3 p0, Point3 p1, int end0, int end1, Image *src);
-Point string3(Camera *c, Point3 p, Image *src, Font *f, char *s);
+void perspective(Matrix3, double, double, double, double);
+void orthographic(Matrix3, double, double, double, double, double, double);
+void line3(Camera*, Point3, Point3, int, int, Image*);
+Point string3(Camera*, Point3, Image*, Font*, char*);
--- a/libgraphics/camera.c
+++ b/libgraphics/camera.c
@@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
+#include <memdraw.h>
#include "../geometry.h"
#include "../graphics.h"
@@ -13,45 +14,45 @@
static void
verifycfg(Camera *c)
{
- assert(c->viewport != nil);
+ assert(c->viewport.fb != nil);
if(c->ptype == Ppersp)
- assert(c->fov >= 1 && c->fov < 360);
- assert(c->clip.n > 0 && c->clip.n < c->clip.f);
+ assert(c->fov > 0 && c->fov < 360);
+ assert(c->clipn > 0 && c->clipn < c->clipf);
}
-void
-perspective(Matrix3 m, double fov, double a, double n, double f)
+static void
+updatefb(Camera *c, Rectangle r, ulong chan)
{
- double cotan;
+ Memimage *fb;
- cotan = 1/tan(fov/2*DEG);
- identity3(m);
- m[0][0] = cotan/a;
- m[1][1] = cotan;
- m[2][2] = -(f+n)/(f-n);
- m[2][3] = -2*f*n/(f-n);
- m[3][2] = -1;
+ fb = allocmemimage(r, chan);
+ if(fb == nil)
+ sysfatal("allocmemimage: %r");
+ c->viewport.fb = fb;
+ c->viewport.p = Pt2(r.min.x,r.max.y,1);
}
-void
-orthographic(Matrix3 m, double l, double r, double b, double t, double n, double f)
+Camera*
+alloccamera(Rectangle r, ulong chan)
{
- identity3(m);
- m[0][0] = 2/(r - l);
- m[1][1] = 2/(t - b);
- m[2][2] = -2/(f - n);
- m[0][3] = -(r + l)/(r - l);
- m[1][3] = -(t + b)/(t - b);
- m[2][3] = -(f + n)/(f - n);
+ Camera *c;
+
+ c = malloc(sizeof(Camera));
+ if(c == nil)
+ sysfatal("malloc: %r");
+ memset(c, 0, sizeof *c);
+ c->viewport.bx = Vec2(1,0);
+ c->viewport.by = Vec2(0,-1);
+ updatefb(c, r, chan);
+ c->updatefb = updatefb;
}
void
-configcamera(Camera *c, Image *v, double fov, double n, double f, Projection p)
+configcamera(Camera *c, double fov, double n, double f, Projection p)
{
- c->viewport = v;
c->fov = fov;
- c->clip.n = n;
- c->clip.f = f;
+ c->clipn = n;
+ c->clipf = f;
c->ptype = p;
reloadcamera(c);
}
@@ -84,19 +85,19 @@
switch(c->ptype){
case Portho:
/*
- r = Dx(c->viewport->r)/2;
- t = Dy(c->viewport->r)/2;
+ r = Dx(c->viewport.fb->r)/2;
+ t = Dy(c->viewport.fb->r)/2;
l = -r;
b = -t;
*/
l = t = 0;
- r = Dx(c->viewport->r);
- b = Dy(c->viewport->r);
- orthographic(c->proj, l, r, b, t, c->clip.n, c->clip.f);
+ r = Dx(c->viewport.fb->r);
+ b = Dy(c->viewport.fb->r);
+ orthographic(c->proj, l, r, b, t, c->clipn, c->clipf);
break;
case Ppersp:
- a = (double)Dx(c->viewport->r)/Dy(c->viewport->r);
- perspective(c->proj, c->fov, a, c->clip.n, c->clip.f);
+ a = (double)Dx(c->viewport.fb->r)/Dy(c->viewport.fb->r);
+ perspective(c->proj, c->fov, a, c->clipn, c->clipf);
break;
default: sysfatal("unknown projection type");
}
--- a/libgraphics/render.c
+++ b/libgraphics/render.c
@@ -41,13 +41,8 @@
toviewport(Camera *c, Point3 p)
{
Point2 p2;
- RFrame rf = {
- c->viewport->r.min.x, c->viewport->r.max.y, 1,
- 1, 0, 0,
- 0, -1, 0
- };
- p2 = invrframexform(flatten(c, p), rf);
+ p2 = invrframexform(flatten(c, p), c->viewport);
return (Point){p2.x, p2.y};
}
@@ -54,13 +49,33 @@
Point2
fromviewport(Camera *c, Point p)
{
- RFrame rf = {
- c->viewport->r.min.x, c->viewport->r.max.y, 1,
- 1, 0, 0,
- 0, -1, 0
- };
+ return rframexform(Pt2(p.x,p.y,1), c->viewport);
+}
- return rframexform(Pt2(p.x, p.y, 1), rf);
+void
+perspective(Matrix3 m, double fov, double a, double n, double f)
+{
+ double cotan;
+
+ cotan = 1/tan(fov/2*DEG);
+ identity3(m);
+ m[0][0] = cotan/a;
+ m[1][1] = cotan;
+ m[2][2] = -(f+n)/(f-n);
+ m[2][3] = -2*f*n/(f-n);
+ m[3][2] = -1;
+}
+
+void
+orthographic(Matrix3 m, double l, double r, double b, double t, double n, double f)
+{
+ identity3(m);
+ m[0][0] = 2/(r - l);
+ m[1][1] = 2/(t - b);
+ m[2][2] = -2/(f - n);
+ m[0][3] = -(r + l)/(r - l);
+ m[1][3] = -(t + b)/(t - b);
+ m[2][3] = -(f + n)/(f - n);
}
void
--- a/main.c
+++ b/main.c
@@ -10,6 +10,15 @@
#include "dat.h"
#include "fns.h"
+typedef struct Camcfg Camcfg;
+
+struct Camcfg
+{
+ Point3 p, lookat, up;
+ double fov, clipn, clipf;
+ int ptype;
+};
+
Rune keys[Ke] = {
[K↑] = Kup,
[K↓] = Kdown,
@@ -37,11 +46,24 @@
int kdown;
vlong t0, t;
double Δt;
-Mesh model;
+//Mesh model;
char *mdlpath = "../threedee/mdl/rocket.obj";
-Camera cams[4], *maincam;
+Camera *cams[4], *maincam;
+Camcfg camcfgs[4] = {
+ Pt3(2,0,-4,1), Pt3(0,0,0,1), Vec3(0,1,0),
+ 90, 0.1, 100, Ppersp,
+ Pt3(-2,0,-4,1), Pt3(0,0,0,1), Vec3(0,1,0),
+ 120, 0.1, 100, Ppersp,
+
+ Pt3(-2,0,4,1), Pt3(0,0,0,1), Vec3(0,1,0),
+ 90, 0.1, 100, Ppersp,
+
+ Pt3(2,0,4,1), Pt3(0,0,0,1), Vec3(0,1,0),
+ 120, 0.1, 100, Ppersp
+};
+
#pragma varargck type "v" Point2
int
vfmt(Fmt *f)
@@ -120,7 +142,7 @@
{
int i;
- snprint(stats[Scamno], sizeof(stats[Scamno]), "CAM %lld", maincam-cams+1);
+ snprint(stats[Scamno], sizeof(stats[Scamno]), "CAM %lld", maincam-cams[0]+1);
snprint(stats[Sfov], sizeof(stats[Sfov]), "FOV %g°", maincam->fov);
snprint(stats[Scampos], sizeof(stats[Scampos]), "%V", maincam->p);
snprint(stats[Scambx], sizeof(stats[Scambx]), "bx %V", maincam->bx);
@@ -127,67 +149,67 @@
snprint(stats[Scamby], sizeof(stats[Scamby]), "by %V", maincam->by);
snprint(stats[Scambz], sizeof(stats[Scambz]), "bz %V", maincam->bz);
for(i = 0; i < Se; i++)
- stringn(maincam->viewport, addpt(screen->r.min, Pt(10, 10 + i*font->height)), display->black, ZP, font, stats[i], sizeof(stats[i]));
+ stringn(maincam->viewport, addpt(screen->r.min, Pt(10,10 + i*font->height)), display->black, ZP, font, stats[i], sizeof(stats[i]));
}
void
redraw(void)
{
- Triangle3 tmp;
- static TTriangle3 *vistris;
- static int nallocvistri;
- Triangle trit;
- Point3 n;
- u8int c;
- int i, nvistri;
-
- nvistri = 0;
- if(nallocvistri == 0 && vistris == nil){
- nallocvistri = model.ntri/2;
- vistris = emalloc(nallocvistri*sizeof(TTriangle3));
- }
- for(i = 0; i < model.ntri; i++){
- /* world to camera */
- tmp.p0 = WORLD2VCS(maincam, model.tris[i].p0);
- tmp.p1 = WORLD2VCS(maincam, model.tris[i].p1);
- tmp.p2 = WORLD2VCS(maincam, model.tris[i].p2);
- /* back-face culling */
- n = normvec3(crossvec3(subpt3(tmp.p1, tmp.p0), subpt3(tmp.p2, tmp.p0)));
- if(dotvec3(n, mulpt3(tmp.p0, -1)) <= 0)
- continue;
- /* camera to projected ndc */
- tmp.p0 = VCS2NDC(maincam, tmp.p0);
- tmp.p1 = VCS2NDC(maincam, tmp.p1);
- tmp.p2 = VCS2NDC(maincam, tmp.p2);
- /* clipping */
- /*
- * no clipping for now, the whole triangle is ignored
- * if any of its vertices gets outside the fustrum.
- */
- if(isclipping(tmp.p0) || isclipping(tmp.p1) || isclipping(tmp.p2))
- continue;
- if(nvistri >= nallocvistri){
- nallocvistri += model.ntri/3;
- vistris = erealloc(vistris, nallocvistri*sizeof(TTriangle3));
- }
- vistris[nvistri] = (TTriangle3)tmp;
- c = 0xff*fabs(dotvec3(n, Vec3(0, 0, 1)));
- vistris[nvistri].tx = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c<<24|c<<16|c<<8|0xff);
- nvistri++;
- }
- qsort(vistris, nvistri, sizeof(TTriangle3), depthcmp);
+// Triangle3 tmp;
+// static TTriangle3 *vistris;
+// static int nallocvistri;
+// Triangle trit;
+// Point3 n;
+// u8int c;
+// int i, nvistri;
+//
+// nvistri = 0;
+// if(nallocvistri == 0 && vistris == nil){
+// nallocvistri = model.ntri/2;
+// vistris = emalloc(nallocvistri*sizeof(TTriangle3));
+// }
+// for(i = 0; i < model.ntri; i++){
+// /* world to camera */
+// tmp.p0 = WORLD2VCS(maincam, model.tris[i].p0);
+// tmp.p1 = WORLD2VCS(maincam, model.tris[i].p1);
+// tmp.p2 = WORLD2VCS(maincam, model.tris[i].p2);
+// /* back-face culling */
+// n = normvec3(crossvec3(subpt3(tmp.p1, tmp.p0), subpt3(tmp.p2, tmp.p0)));
+// if(dotvec3(n, mulpt3(tmp.p0, -1)) <= 0)
+// continue;
+// /* camera to projected ndc */
+// tmp.p0 = VCS2NDC(maincam, tmp.p0);
+// tmp.p1 = VCS2NDC(maincam, tmp.p1);
+// tmp.p2 = VCS2NDC(maincam, tmp.p2);
+// /* clipping */
+// /*
+// * no clipping for now, the whole triangle is ignored
+// * if any of its vertices gets outside the fustrum.
+// */
+// if(isclipping(tmp.p0) || isclipping(tmp.p1) || isclipping(tmp.p2))
+// continue;
+// if(nvistri >= nallocvistri){
+// nallocvistri += model.ntri/3;
+// vistris = erealloc(vistris, nallocvistri*sizeof(TTriangle3));
+// }
+// vistris[nvistri] = (TTriangle3)tmp;
+// c = 0xff*fabs(dotvec3(n, Vec3(0,0,1)));
+// vistris[nvistri].tx = allocimage(display, Rect(0,0,1,1), screen->chan, 1, c<<24|c<<16|c<<8|0xff);
+// nvistri++;
+// }
+// qsort(vistris, nvistri, sizeof(TTriangle3), depthcmp);
lockdisplay(display);
draw(maincam->viewport, maincam->viewport->r, display->white, nil, ZP);
drawaxis();
- for(i = 0; i < nvistri; i++){
- /* ndc to screen */
- trit.p0 = toviewport(maincam, vistris[i].p0);
- trit.p1 = toviewport(maincam, vistris[i].p1);
- trit.p2 = toviewport(maincam, vistris[i].p2);
- filltriangle(maincam->viewport, trit, vistris[i].tx, ZP);
- triangle(maincam->viewport, trit, 0, display->black, ZP);
- freeimage(vistris[i].tx);
- }
+// for(i = 0; i < nvistri; i++){
+// /* ndc to screen */
+// trit.p0 = toviewport(maincam, vistris[i].p0);
+// trit.p1 = toviewport(maincam, vistris[i].p1);
+// trit.p2 = toviewport(maincam, vistris[i].p2);
+// filltriangle(maincam->viewport, trit, vistris[i].tx, ZP);
+// triangle(maincam->viewport, trit, 0, display->black, ZP);
+// freeimage(vistris[i].tx);
+// }
drawstats();
flushimage(display, 1);
unlockdisplay(display);
@@ -310,13 +332,13 @@
if(kdown & 1<<KR↻)
placecamera(maincam, maincam->p, maincam->bz, qrotate(maincam->by, maincam->bz, -5*DEG));
if(kdown & 1<<Kcam0)
- maincam = &cams[0];
+ maincam = cams[0];
if(kdown & 1<<Kcam1)
- maincam = &cams[1];
+ maincam = cams[1];
if(kdown & 1<<Kcam2)
- maincam = &cams[2];
+ maincam = cams[2];
if(kdown & 1<<Kcam3)
- maincam = &cams[3];
+ maincam = cams[3];
if(kdown & 1<<Kscrshot)
screenshot();
}
@@ -328,8 +350,7 @@
if(getwindow(display, Refnone) < 0)
fprint(2, "can't reattach to window\n");
unlockdisplay(display);
- maincam->viewport = screen;
- reloadcamera(maincam);
+ maincam->updatefb(maincam, screen->r, screen->chan);
}
void
@@ -343,6 +364,7 @@
threadmain(int argc, char *argv[])
{
OBJ *objmesh;
+ int i;
fmtinstall('V', Vfmt);
fmtinstall('v', vfmt);
@@ -358,15 +380,12 @@
sysfatal("initdraw: %r");
if((mctl = initmouse(nil, screen)) == nil)
sysfatal("initmouse: %r");
- placecamera(&cams[0], Pt3(2, 0, -4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0));
- configcamera(&cams[0], screen, 90, 0.1, 100, Ppersp);
- placecamera(&cams[1], Pt3(-2, 0, -4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0));
- configcamera(&cams[1], screen, 120, 0.1, 100, Ppersp);
- placecamera(&cams[2], Pt3(-2, 0, 4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0));
- configcamera(&cams[2], screen, 90, 0.1, 100, Ppersp);
- placecamera(&cams[3], Pt3(2, 0, 4, 1), Pt3(0, 0, 0, 1), Vec3(0, 1, 0));
- configcamera(&cams[3], screen, 120, 0.1, 100, Ppersp);
- maincam = &cams[0];
+ for(i = 0; i < nelem(cams); i++){
+ cams[i] = alloccamera(screen->r, screen->chan);
+ placecamera(cams[i], camcfgs[i].p, camcfgs[i].lookat, camcfgs[i].up);
+ configcamera(cams[i], camcfgs[i].fov, camcfgs[i].clipn, camcfgs[i].clipf, camcfgs[i].ptype);
+ }
+ maincam = cams[0];
if((objmesh = objparse(mdlpath)) == nil)
sysfatal("objparse: %r");
drawc = chancreate(1, 0);