shithub: 3dee

Download patch

ref: acffbcfc161bddcc8fa454c256ebcfd9160e0b46
parent: bd079fb59cff60792842d2726737002fabcc8951
author: rodri <rgl@antares-labs.eu>
date: Fri Jun 13 20:36:42 EDT 2025

new tool: plot3 (wip)

--- a/mkfile
+++ b/mkfile
@@ -10,6 +10,7 @@
 	obj\
 	stl\
 	tostl\
+	plot3\
 
 OFILES=\
 	alloc.$O\
--- /dev/null
+++ b/plot3.c
@@ -1,0 +1,285 @@
+#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 "libgraphics/graphics.h"
+#include "fns.h"
+
+typedef struct AABB AABB;
+struct AABB
+{
+	Point3 min;
+	Point3 max;
+	/* with its homologous bounding sphere */
+	Point3 c;
+	double r;
+};
+
+typedef struct Plot Plot;
+struct Plot
+{
+	Point3 *pts;
+	ulong npts;
+	AABB bbox;
+	Scene *scn;
+};
+
+Mousectl *mctl;
+Keyboardctl *kctl;
+Channel *drawc;
+Image *screenb;
+Plot theplot;
+Camera *cam;
+
+static Point3
+vs(Shaderparams *sp)
+{
+	return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p));
+}
+
+static Color
+fs(Shaderparams *sp)
+{
+	return sp->v->c;
+}
+
+Shadertab shaders = {
+	.vs = vs,
+	.fs = fs
+};
+
+void
+updatebboxfromtheplot(void)
+{
+	static int inited;
+	Point3 *lastpt;
+
+	lastpt = &theplot.pts[theplot.npts-1];
+
+	if(!inited){
+		theplot.bbox.min = theplot.bbox.max = *lastpt;
+		inited++;
+		return;
+	}
+
+	theplot.bbox.min = minpt3(theplot.bbox.min, *lastpt);
+	theplot.bbox.max = maxpt3(theplot.bbox.max, *lastpt);
+	theplot.bbox.c = divpt3(addpt3(theplot.bbox.max, theplot.bbox.min), 2);
+	theplot.bbox.r = max(vec3len(theplot.bbox.min), vec3len(theplot.bbox.max));
+}
+
+void
+addpttotheplot(Point3 p)
+{
+	if(theplot.npts % 4 == 0)
+		theplot.pts = erealloc(theplot.pts, (theplot.npts + 4)*sizeof(Plot));
+	theplot.pts[theplot.npts++] = p;
+	updatebboxfromtheplot();
+}
+
+void
+readtheplot(int fd)
+{
+	Biobuf *bin;
+	Point3 p;
+	char *line, *f[3];
+	ulong lineno;
+	int nf;
+
+	bin = Bfdopen(fd, OREAD);
+	if(bin == nil)
+		sysfatal("Bfdopen: %r");
+
+	lineno = 0;
+	p.w = 1;
+	while((line = Brdstr(bin, '\n', 1)) != nil){
+		lineno++;
+		nf = tokenize(line, f, nelem(f));
+		if(nf != 3){
+			fprint(2, "not enough fields. ignoring line %uld\n", lineno);
+			free(line);
+			continue;
+		}
+		p.x = strtod(f[0], nil);
+		p.y = strtod(f[1], nil);
+		p.z = strtod(f[2], nil);
+		addpttotheplot(p);
+		free(line);
+	}
+	Bterm(bin);
+}
+
+#define smallestbbox(coord)	(min(theplot.bbox.min.coord, theplot.bbox.max.coord))
+#define biggestbbox(coord)	(max(theplot.bbox.min.coord, theplot.bbox.max.coord))
+void
+frametheplot(void)
+{
+	Model *mdl;
+	Entity *ent;
+	Primitive line;
+
+	mdl = newmodel();
+	ent = newentity("axis scales", mdl);
+	theplot.scn->addent(theplot.scn, ent);
+
+	line.type = PLine;
+	line.v[0].c = line.v[1].c = Pt3(0,0,0,1);
+
+	/* x scale */
+	line.v[0].p = Pt3(smallestbbox(x), smallestbbox(y), biggestbbox(z), 1);
+	line.v[1].p = addpt3(line.v[0].p, Vec3(biggestbbox(x), 0, 0));
+	mdl->addprim(mdl, line);
+
+	/* y scale */
+	line.v[1].p = addpt3(line.v[0].p, Vec3(0, biggestbbox(y), 0));
+	mdl->addprim(mdl, line);
+
+	/* z scale */
+	line.v[1].p = addpt3(line.v[0].p, Vec3(0, 0, smallestbbox(z)));
+	mdl->addprim(mdl, line);
+}
+
+void
+understandtheplot(void)
+{
+	Model *mdl;
+	Entity *ent;
+	Scene *scn;
+	Primitive prim;
+	Point3 *p;
+
+	mdl = newmodel();
+	ent = newentity(nil, mdl);
+	scn = newscene("the plot");
+	scn->addent(scn, ent);
+	theplot.scn = scn;
+
+	memset(&prim, 0, sizeof prim);
+	prim.type = PPoint;
+	prim.v[0].c = Pt3(0,0,0,1);
+
+	for(p = theplot.pts; p < theplot.pts + theplot.npts; p++){
+		prim.v[0].p = *p;
+		mdl->addprim(mdl, prim);
+	}
+	frametheplot();
+}
+
+void
+redraw(void)
+{
+	shootcamera(cam, &shaders);
+	lockdisplay(display);
+	draw(screenb, screenb->r, display->white, nil, ZP);
+	cam->view->draw(cam->view, screenb, nil);
+	draw(screen, screen->r, screenb, nil, ZP);
+	flushimage(display, 1);
+	unlockdisplay(display);
+}
+
+void
+drawproc(void *)
+{
+	threadsetname("drawproc");
+
+	for(;;){
+		recv(drawc, nil);
+		redraw();
+	}
+}
+
+void
+mouse(void)
+{
+}
+
+void
+resize(void)
+{
+	lockdisplay(display);
+	if(getwindow(display, Refnone) < 0)
+		fprint(2, "can't reattach to window\n");
+	unlockdisplay(display);
+	nbsend(drawc, nil);
+}
+
+void
+key(Rune r)
+{
+	switch(r){
+	case Kdel:
+	case 'q':
+		threadexitsall(nil);
+	}
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s\n", argv0);
+	exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	Renderer *rctl;
+	Rune r;
+
+	ARGBEGIN{
+	default: usage();
+	}ARGEND;
+	if(argc != 0)
+		usage();
+
+	readtheplot(0);
+	understandtheplot();
+
+	if(memimageinit() != 0)
+		sysfatal("memimageinit: %r");
+	if((rctl = initgraphics()) == nil)
+		sysfatal("initgraphics: %r");
+	if(initdraw(nil, nil, "solar") < 0)
+		sysfatal("initdraw: %r");
+	if((mctl = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+	if((kctl = initkeyboard(nil)) == nil)
+		sysfatal("initkeyboard: %r");
+
+	screenb = eallocimage(display, rectsubpt(screen->r, screen->r.min), XRGB32, 0, DNofill);
+	cam = Cam(screenb->r, rctl, PERSPECTIVE, 90*DEG, 0.1, 1000);
+	placecamera(cam, theplot.scn, addpt3(theplot.bbox.c, mulpt3(normvec3(Vec3(1,1,1)), 1.5*theplot.bbox.r)), theplot.bbox.c, Vec3(0,1,0));
+
+	display->locking = 1;
+	unlockdisplay(display);
+
+	drawc = chancreate(sizeof(void*), 1);
+	proccreate(drawproc, nil, mainstacksize);
+	nbsend(drawc, nil);
+
+	enum {MOUSE, RESIZE, KEY};
+	Alt a[] = {
+		{mctl->c, &mctl->Mouse, CHANRCV},
+		{mctl->resizec, nil, CHANRCV},
+		{kctl->c, &r, CHANRCV},
+		{nil, nil, CHANEND}
+	};
+	for(;;)
+		switch(alt(a)){
+		case -1: sysfatal("alt interrupted");
+		case MOUSE:
+			mouse();
+			break;
+		case RESIZE:
+			resize();
+			break;
+		case KEY:
+			key(r);
+			break;
+		}
+}
--