diff options
author | rodri <rgl@antares-labs.eu> | 2024-05-14 16:40:49 +0000 |
---|---|---|
committer | rodri <rgl@antares-labs.eu> | 2024-05-14 16:40:49 +0000 |
commit | 702e1d92ff4e270f5be88d1b5b190c4de758a101 (patch) | |
tree | d57423ddc3a63495e374af5b243b649dd2ef57e4 | |
parent | 53c0208f4caf8701189484e6125821f69e249f94 (diff) | |
download | 3dee-702e1d92ff4e270f5be88d1b5b190c4de758a101.tar.gz 3dee-702e1d92ff4e270f5be88d1b5b190c4de758a101.tar.bz2 3dee-702e1d92ff4e270f5be88d1b5b190c4de758a101.zip |
use real lengths in solar. bring a qball for vis.
-rw-r--r-- | fns.h | 1 | ||||
-rw-r--r-- | mdl/planet.mtl | 1 | ||||
-rw-r--r-- | mdl/sol_diffuse.jpg | bin | 822427 -> 0 bytes | |||
-rw-r--r-- | mkfile | 1 | ||||
-rw-r--r-- | qb.c | 86 | ||||
-rw-r--r-- | solar.c | 93 | ||||
-rw-r--r-- | vis.c | 58 |
7 files changed, 183 insertions, 57 deletions
@@ -2,3 +2,4 @@ void *emalloc(ulong); void *erealloc(void*, ulong); Image *eallocimage(Display*, Rectangle, ulong, int, ulong); Memimage *eallocmemimage(Rectangle, ulong); +void qb(Rectangle, Point, Point, Quaternion*, Quaternion*); diff --git a/mdl/planet.mtl b/mdl/planet.mtl index 343d38e..43bf96e 100644 --- a/mdl/planet.mtl +++ b/mdl/planet.mtl @@ -1,6 +1,5 @@ newmtl Sol Kd 1.0 1.0 1.0 -map_Kd sol_diffuse.jpg newmtl Mercury Kd 1.0 1.0 1.0 diff --git a/mdl/sol_diffuse.jpg b/mdl/sol_diffuse.jpg Binary files differdeleted file mode 100644 index 9d787d8..0000000 --- a/mdl/sol_diffuse.jpg +++ /dev/null @@ -7,6 +7,7 @@ TARG=\ OFILES=\ alloc.$O\ + qb.$O\ HFILES=dat.h fns.h @@ -0,0 +1,86 @@ +/* + * Ken Shoemake's Quaternion rotation controller + * “Arcball Rotation Control”, Graphics Gems IV § III.1, pp. 175-192, August 1994. + */ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <thread.h> +#include <draw.h> +#include <memdraw.h> +#include <mouse.h> +#include <keyboard.h> +#include <geometry.h> +#include "libobj/obj.h" +#include "libgraphics/graphics.h" +#include "fns.h" + +static int +min(int a, int b) +{ + return a < b? a: b; +} + +/* + * Convert a mouse point into a unit quaternion, flattening if + * constrained to a particular plane. + */ +static Quaternion +mouseq(Point2 p, Quaternion *axis) +{ + double l; + Quaternion q; + double rsq = p.x*p.x + p.y*p.y; /* quadrance */ + + if(rsq > 1){ /* outside the sphere */ + rsq = sqrt(rsq); + q.r = 0; + q.i = p.x/rsq; + q.j = p.y/rsq; + q.k = 0; + }else{ /* within the sphere */ + q.r = 0; + q.i = p.x; + q.j = p.y; + q.k = sqrt(1 - rsq); + } + + if(axis != nil){ + l = dotq(q, *axis); + q.i -= l*axis->i; + q.j -= l*axis->j; + q.k -= l*axis->k; + l = qlen(q); + if(l != 0){ + q.i /= l; + q.j /= l; + q.k /= l; + } + } + + return q; +} + +void +qb(Rectangle r, Point p0, Point p1, Quaternion *orient, Quaternion *axis) +{ + Quaternion q, down; + Point2 rmin, rmax; + Point2 s0, s1; /* screen coords */ + Point2 v0, v1; /* unit sphere coords */ + Point2 ctlcen; /* controller center */ + double ctlrad; /* controller radius */ + + rmin = Vec2(r.min.x, r.min.y); + rmax = Vec2(r.max.x, r.max.y); + s0 = Vec2(p0.x, p0.y); + s1 = Vec2(p1.x, p1.y); + ctlcen = divpt2(addpt2(rmin, rmax), 2); + ctlrad = min(Dx(r), Dy(r)); + v0 = divpt2(subpt2(s0, ctlcen), ctlrad); + down = invq(mouseq(v0, axis)); + + q = *orient; + v1 = divpt2(subpt2(s1, ctlcen), ctlrad); + *orient = mulq(q, mulq(down, mouseq(v1, axis))); +} @@ -109,17 +109,17 @@ Rune keys[Ke] = { [Khud] = 'h', }; Planet planets[] = { - { .id = 10, .name = "Sol", .scale = 100 }, - { .id = 1, .name = "Mercury", .scale = 0.333333 }, - { .id = 2, .name = "Venus", .scale = 0.8 }, - { .id = 399, .name = "Earth", .scale = 1 }, - { .id = 301, .name = "Luna", .scale = 0.25 }, - { .id = 4, .name = "Mars", .scale = 0.5 }, - { .id = 5, .name = "Jupiter", .scale = 11 }, - { .id = 6, .name = "Saturn", .scale = 9 }, - { .id = 7, .name = "Uranus", .scale = 4 }, - { .id = 8, .name = "Neptune", .scale = 3.666666 }, - { .id = 9, .name = "Pluto", .scale = 0.166666 }, + { .id = 10, .name = "Sol", .scale = 695700 }, + { .id = 1, .name = "Mercury", .scale = 2439.4 }, + { .id = 2, .name = "Venus", .scale = 6051.8 }, + { .id = 399, .name = "Earth", .scale = 6371.0084 }, + { .id = 301, .name = "Luna", .scale = 1737.4 }, + { .id = 4, .name = "Mars", .scale = 3389.50 }, + { .id = 5, .name = "Jupiter", .scale = 69911 }, + { .id = 6, .name = "Saturn", .scale = 58232 }, + { .id = 7, .name = "Uranus", .scale = 25362 }, + { .id = 8, .name = "Neptune", .scale = 24622 }, + { .id = 9, .name = "Pluto", .scale = 1188.3 }, }; char stats[Se][256]; char datefmt[] = "YYYY-MM-DD"; @@ -129,12 +129,12 @@ Image *screenb; Mousectl *mctl; Keyboardctl *kctl; Channel *drawc; +Mouse om; int kdown; Tm date; char datestr[16]; Model *model; Scene *scene; -double θ, ω = 0; Camera camera; Camcfg cameracfg = { @@ -144,7 +144,9 @@ Camcfg cameracfg = { 80*DEG, 0.01, 1e12, PERSPECTIVE }; Point3 center = {0,0,0,1}; +double speed = 10; +static int museummode; static int doprof; static int showhud; @@ -242,7 +244,6 @@ updateplanets(void) p = strchr(p, '='); planets[i].body->p.z = strtod(++p, nil); planets[i].body->p.w = 1; - planets[i].body->p = divpt3(planets[i].body->p, 1e5); free(s); fprint(2, "%s ready\n", planets[i].name); } @@ -288,15 +289,13 @@ identshader(FSparams *sp) if(sp->v.mtl != nil && sp->v.mtl->diffusemap != nil && sp->v.uv.w != 0) tc = texture(sp->v.mtl->diffusemap, sp->v.uv, neartexsampler); - else if(sp->su->entity->mdl->tex != nil && sp->v.uv.w != 0) - tc = texture(sp->su->entity->mdl->tex, sp->v.uv, neartexsampler); else tc = Pt3(1,1,1,1); c.a = 1; - c.b = fclamp(sp->v.c.b*tc.b, 0, 1); - c.g = fclamp(sp->v.c.g*tc.g, 0, 1); - c.r = fclamp(sp->v.c.r*tc.r, 0, 1); + c.b = fclamp(tc.b, 0, 1); + c.g = fclamp(tc.g, 0, 1); + c.r = fclamp(tc.r, 0, 1); return c; } @@ -411,7 +410,7 @@ goto_cmd(Cmdbut *) if(idx < 0) return; p = &planets[idx]; - placecamera(&camera, addpt3(p->body->p, Vec3(0,0,10)), p->body->p, cameracfg.up); + placecamera(&camera, addpt3(p->body->p, Vec3(0,0,1.5*p->scale)), p->body->p, cameracfg.up); nbsend(drawc, nil); } @@ -421,6 +420,9 @@ date_cmd(Cmdbut *) Tm t; char buf[16]; + if(museummode) + return; + memmove(buf, datestr, sizeof buf); if(enter("new date", buf, sizeof buf, mctl, kctl, nil) <= 0) return; @@ -443,6 +445,13 @@ lmb(void) Cmdbut *cmd; int i; + if(ptinrect(subpt(mctl->xy, screen->r.min), viewr) && (om.buttons^mctl->buttons) == 0){ + return; + } + + if((om.buttons ^ mctl->buttons) == 0) + return; + cmd = nil; for(i = 0; i < cmdbox.ncmds; i++) if(ptinrect(subpt(mctl->xy, screen->r.min), cmdbox.cmds[i].r)) @@ -457,15 +466,27 @@ void mmb(void) { enum { + CHGSPEED, QUIT, }; static char *items[] = { + [CHGSPEED] "change speed", [QUIT] "quit", nil, }; static Menu menu = { .item = items }; + char buf[128]; + + if((om.buttons ^ mctl->buttons) == 0) + return; switch(menuhit(2, mctl, &menu, _screen)){ + case CHGSPEED: + snprint(buf, sizeof buf, "%g", speed); + if(enter("speed (km)", buf, sizeof buf, mctl, kctl, nil) <= 0) + return; + speed = fabs(strtod(buf, nil)); + break; case QUIT: threadexitsall(nil); } @@ -475,10 +496,6 @@ mmb(void) void mouse(void) { - static Mouse om; - - if((om.buttons ^ mctl->buttons) == 0) - return; if((mctl->buttons & 1) != 0) lmb(); if((mctl->buttons & 2) != 0) @@ -555,17 +572,17 @@ handlekeys(void) static int okdown; if(kdown & 1<<K↑) - placecamera(&camera, subpt3(camera.p, mulpt3(camera.bz, 0.1)), camera.bz, camera.by); + placecamera(&camera, subpt3(camera.p, mulpt3(camera.bz, speed)), camera.bz, camera.by); if(kdown & 1<<K↓) - placecamera(&camera, addpt3(camera.p, mulpt3(camera.bz, 0.1)), camera.bz, camera.by); + placecamera(&camera, addpt3(camera.p, mulpt3(camera.bz, speed)), camera.bz, camera.by); if(kdown & 1<<K←) - placecamera(&camera, subpt3(camera.p, mulpt3(camera.bx, 0.1)), camera.bz, camera.by); + placecamera(&camera, subpt3(camera.p, mulpt3(camera.bx, speed)), camera.bz, camera.by); if(kdown & 1<<K→) - placecamera(&camera, addpt3(camera.p, mulpt3(camera.bx, 0.1)), camera.bz, camera.by); + placecamera(&camera, addpt3(camera.p, mulpt3(camera.bx, speed)), camera.bz, camera.by); if(kdown & 1<<Krise) - placecamera(&camera, addpt3(camera.p, mulpt3(camera.by, 0.1)), camera.bz, camera.by); + placecamera(&camera, addpt3(camera.p, mulpt3(camera.by, speed)), camera.bz, camera.by); if(kdown & 1<<Kfall) - placecamera(&camera, subpt3(camera.p, mulpt3(camera.by, 0.1)), camera.bz, camera.by); + placecamera(&camera, subpt3(camera.p, mulpt3(camera.by, speed)), camera.bz, camera.by); if(kdown & 1<<KR↑) aimcamera(&camera, qrotate(camera.bz, camera.bx, 1*DEG)); if(kdown & 1<<KR↓) @@ -618,7 +635,7 @@ confproc(void) void usage(void) { - fprint(2, "usage: %s\n", argv0); + fprint(2, "usage: %s [-m]\n", argv0); exits("usage"); } @@ -636,6 +653,7 @@ threadmain(int argc, char *argv[]) tmfmtinstall(); GEOMfmtinstall(); ARGBEGIN{ + case 'm': museummode++; break; case 'p': doprof++; break; default: usage(); }ARGEND; @@ -649,6 +667,15 @@ threadmain(int argc, char *argv[]) model = newmodel(); loadobjmodel(model, obj); objfree(obj); + /* + * normalize the vertices so that we can scale + * each planet based on its radius + */ + for(i = 0; i < model->nprims; i++) + for(j = 0; j < model->prims[i].type+1; j++){ + model->prims[i].v[j].p = normvec3(model->prims[i].v[j].p); + model->prims[i].v[j].p.w = 1; + } scene = newscene(nil); for(i = 0; i < nelem(planets); i++){ subject = newentity(model); @@ -660,11 +687,13 @@ threadmain(int argc, char *argv[]) if(i == 0){ subject->p = Pt3(0,0,0,1); continue; - } + }else if(museummode) + subject->p.x = planets[i-1].body->p.x + 1.5*planets[i-1].scale + planets[i].scale; } tmnow(&date, nil); snprint(datestr, sizeof datestr, "%τ", tmfmt(&date, datefmt)); - updateplanets(); + if(!museummode) + updateplanets(); if(memimageinit() != 0) sysfatal("memimageinit: %r"); @@ -50,7 +50,7 @@ Shadertab *shader; Model *model; Entity *subject; Scene *scene; -double θ, ω = 0; +Quaternion orient = {1,0,0,0}; Camera cams[4], *maincam; Camcfg camcfgs[4] = { @@ -94,21 +94,17 @@ max(int a, int b) return a > b? a: b; } -//void -//drawaxis(void) -//{ -// Point3 op = Pt3(0,0,0,1), -// px = Pt3(1,0,0,1), -// py = Pt3(0,1,0,1), -// pz = Pt3(0,0,1,1); -// -// line3(maincam, op, px, 0, Endarrow, display->black); -// string3(maincam, px, display->black, font, "x"); -// line3(maincam, op, py, 0, Endarrow, display->black); -// string3(maincam, py, display->black, font, "y"); -// line3(maincam, op, pz, 0, Endarrow, display->black); -// string3(maincam, pz, display->black, font, "z"); -//} +static Point3 +Vecquat(Quaternion q) +{ + return Vec3(q.i, q.j, q.k); +} + +static Point3 +Ptquat(Quaternion q, double w) +{ + return Pt3(q.i, q.j, q.k, w); +} Point3 gouraudvshader(VSparams *sp) @@ -121,8 +117,8 @@ gouraudvshader(VSparams *sp) Material m; Color ambient, diffuse, specular; - sp->v->n = qrotate(sp->v->n, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI)); - sp->v->p = qrotate(sp->v->p, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI)); + sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient))); + sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w); pos = model2world(sp->su->entity, sp->v->p); if(sp->v->mtl != nil){ m = *sp->v->mtl; @@ -182,8 +178,8 @@ phongvshader(VSparams *sp) Color a, d, s; double ss; - sp->v->n = qrotate(sp->v->n, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI)); - sp->v->p = qrotate(sp->v->p, Vec3(0,1,0), θ+fmod(ω*sp->su->uni_time/1e9, 2*PI)); + sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient))); + sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w); pos = model2world(sp->su->entity, sp->v->p); addvattr(sp->v, "pos", VAPoint, &pos); if(sp->v->mtl != nil){ @@ -268,6 +264,8 @@ identvshader(VSparams *sp) Point3 pos, lightdir; double intens; + sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient))); + sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w); pos = model2world(sp->su->entity, sp->v->p); lightdir = normvec3(subpt3(light.p, pos)); intens = fmax(0, dotvec3(sp->v->n, lightdir)); @@ -313,6 +311,8 @@ identshader(FSparams *sp) Point3 ivshader(VSparams *sp) { + sp->v->n = Vecquat(mulq(mulq(orient, Quatvec(0, sp->v->n)), invq(orient))); + sp->v->p = Ptquat(mulq(mulq(orient, Quatvec(0, sp->v->p)), invq(orient)), sp->v->p.w); return world2clip(maincam, model2world(sp->su->entity, sp->v->p)); } @@ -468,7 +468,6 @@ redraw(void) maincam->vp->draw(maincam->vp, screenb); draw(screen, screen->r, bg, nil, ZP); draw(screen, screen->r, screenb, nil, ZP); -// drawaxis(); if(showhud) drawstats(); flushimage(display, 1); @@ -512,12 +511,22 @@ drawproc(void *) if((model->tex = readmemimage(fd)) == nil) sysfatal("readmemimage: %r"); } - light.p = qrotate(light.p, Vec3(0,1,0), θ+fmod(ω*Δt/1e9, 2*PI)); } } } void +lmb(void) +{ + static Mouse om; + + if((om.buttons^mctl->buttons) == 0) + qb(screen->r, om.xy, mctl->xy, &orient, nil); + + om = mctl->Mouse; +} + +void mmb(void) { enum { @@ -583,6 +592,8 @@ rmb(void) void mouse(void) { + if((mctl->buttons & 1) != 0) + lmb(); if((mctl->buttons & 2) != 0) mmb(); if((mctl->buttons & 4) != 0) @@ -732,7 +743,7 @@ confproc(void) void usage(void) { - fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] [-ω yrot] model...\n", argv0); + fprint(2, "usage: %s [-t texture] [-n normals] [-s shader] model...\n", argv0); exits("usage"); } @@ -754,7 +765,6 @@ threadmain(int argc, char *argv[]) case 't': texpath = EARGF(usage()); break; case 'n': norpath = EARGF(usage()); break; case 's': sname = EARGF(usage()); break; - case L'ω': ω = strtod(EARGF(usage()), nil)*DEG; break; case L'ι': inception++; break; case 'p': doprof++; break; default: usage(); |