From 263444216730830b712a4f8f3a087513c5ac93e9 Mon Sep 17 00:00:00 2001 From: rodri Date: Fri, 6 Mar 2020 21:05:07 +0000 Subject: redesign of the camera abstraction. general unused/useless data cleaning. --- dat.h | 13 ----- graphics.h | 29 ++++++---- libgraphics/camera.c | 67 ++++++++++----------- libgraphics/render.c | 39 +++++++++---- main.c | 161 ++++++++++++++++++++++++++++----------------------- 5 files changed, 169 insertions(+), 140 deletions(-) diff --git a/dat.h b/dat.h index f2d7588..1f6ae7e 100644 --- a/dat.h +++ b/dat.h @@ -26,16 +26,3 @@ enum { Scambx, Scamby, Scambz, Se }; - -typedef struct Mesh Mesh; -typedef struct TTriangle3 TTriangle3; - -struct Mesh { - Triangle3 *tris; - int ntri; -}; - -struct TTriangle3 { - Triangle3; - Image *tx; -}; diff --git a/graphics.h b/graphics.h index 57aa56e..51c0a93 100644 --- a/graphics.h +++ b/graphics.h @@ -10,35 +10,42 @@ typedef struct Camera Camera; 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); 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*); diff --git a/libgraphics/camera.c b/libgraphics/camera.c index c850477..bb55490 100644 --- a/libgraphics/camera.c +++ b/libgraphics/camera.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "../geometry.h" #include "../graphics.h" @@ -13,45 +14,45 @@ max(int a, int b) 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 @@ reloadcamera(Camera *c) 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"); } diff --git a/libgraphics/render.c b/libgraphics/render.c index ddc0663..a1819ec 100644 --- a/libgraphics/render.c +++ b/libgraphics/render.c @@ -41,26 +41,41 @@ Point 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}; } 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); +} + +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; +} - return rframexform(Pt2(p.x, p.y, 1), rf); +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 diff --git a/main.c b/main.c index 1a23c7c..703fbac 100644 --- 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,10 +46,23 @@ Channel *drawc; 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 @@ -120,74 +142,74 @@ drawstats(void) { 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); 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 @@ handlekeys(void) if(kdown & 1<p, maincam->bz, qrotate(maincam->by, maincam->bz, -5*DEG)); if(kdown & 1<viewport = screen; - reloadcamera(maincam); + maincam->updatefb(maincam, screen->r, screen->chan); } void @@ -343,6 +364,7 @@ void threadmain(int argc, char *argv[]) { OBJ *objmesh; + int i; fmtinstall('V', Vfmt); fmtinstall('v', vfmt); @@ -358,15 +380,12 @@ threadmain(int argc, char *argv[]) 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); -- cgit v1.2.3