shithub: 3dee

Download patch

ref: 727cb178cfbc31d46098bcbb46ebf2452527025a
parent: 95edbe92a75b47a7a36e4c41bb450a718feabd60
author: rodri <rgl@antares-labs.eu>
date: Fri Oct 4 11:41:43 EDT 2024

med: switch opmodes with the mouse. add a user logging system.

--- a/med.c
+++ b/med.c
@@ -9,9 +9,9 @@
 #include "libgraphics/graphics.h"
 #include "fns.h"
 
+#define SEC	(1000000000ULL)
+
 enum {
-	Kmodeorb,
-	Kmodesel,
 	Kzoomin,
 	Kzoomout,
 	Khud,
@@ -33,6 +33,30 @@
 	OMSelect,
 };
 
+typedef struct Usermsg Usermsg;
+typedef struct Userlog Userlog;
+
+struct Usermsg
+{
+	char *s;
+	Image *i;
+	uvlong eol;
+	Usermsg *prev, *next;
+};
+
+struct Userlog
+{
+	QLock;
+	Usermsg msgs;
+	ulong nmsgs;
+	ulong cap;
+
+	void (*send)(Userlog*, char*, ...);
+	void (*update)(Userlog*);
+	void (*draw)(Userlog*);
+	void (*delmsg)(Userlog*, Usermsg*);
+};
+
 typedef struct Camcfg Camcfg;
 struct Camcfg
 {
@@ -47,11 +71,8 @@
 	Camera	*cam;
 	Scene	*scn;
 };
-Compass compass;	/* 3d compass */
 
 Rune keys[Ke] = {
- [Kmodeorb]	= 'r',
- [Kmodesel]	= 's',
  [Kzoomin]	= 'z',
  [Kzoomout]	= 'x',
  [Khud]		= 'h',
@@ -79,6 +100,8 @@
 };
 Point3 center = {0,0,0,1};
 LightSource light;	/* global point light */
+Compass compass;	/* 3d compass */
+Userlog *usrlog;
 
 static int doprof;
 static int showhud;
@@ -147,7 +170,120 @@
 	return vec3len(crossvec3(p0p, p01))/h <= r;
 }
 
+static Point
+randptfromrect(Rectangle *r)
+{
+	if(badrect(*r))
+		return r->min;
+	return addpt(r->min, Pt(ntruerand(Dx(*r)), ntruerand(Dy(*r))));
+}
+
+static void
+userlog_send(Userlog *l, char *msg, ...)
+{
+	Usermsg *m;
+	Rectangle ar;	/* available spawn area */
+	Point dim, off;
+	va_list va;
+	char buf[ERRMAX];
+
+	m = emalloc(sizeof *m);
+	memset(m, 0, sizeof *m);
+
+	va_start(va, msg);
+	vsnprint(buf, sizeof buf, msg, va);
+	va_end(va);
+
+	m->s = strdup(buf);
+	if(m->s == nil){
+		free(m);
+		return;		/* lost message */
+	}
+
+	dim = stringsize(font, m->s);
+	ar = screen->r;
+	ar.max = subpt(ar.max, dim);
+	off = randptfromrect(&ar);
+
+	m->i = eallocimage(display, Rpt(off, addpt(off, dim)), XRGB32, 0, DNofill);
+	stringbg(m->i, m->i->r.min, display->white, ZP, font, m->s, display->black, ZP);
+	m->eol = nsec() + 5*SEC;
+
+	qlock(l);
+	m->prev = l->msgs.prev;
+	m->next = l->msgs.prev->next;
+	l->msgs.prev->next = m;
+	l->msgs.prev = m;
+	l->nmsgs++;
+	qunlock(l);
+}
+
+static void
+userlog_delmsg(Userlog *l, Usermsg *m)
+{
+	m->prev->next = m->next;
+	m->next->prev = m->prev;
+	m->prev = m->next = nil;
+
+	freeimage(m->i);
+	free(m->s);
+	free(m);
+
+	l->nmsgs--;
+}
+
+static void
+userlog_update(Userlog *l)
+{
+	Usermsg *m, *nm;
+
+	qlock(l);
+	for(m = l->msgs.next; m != &l->msgs; m = nm){
+		nm = m->next;
+		if(nsec() >= m->eol)
+			l->delmsg(l, m);
+	}
+	qunlock(l);
+}
+
+static void
+userlog_draw(Userlog *l)
+{
+	Usermsg *m;
+
+	qlock(l);
+	for(m = l->msgs.next; m != &l->msgs; m = m->next)
+		draw(screen, m->i->r, m->i, nil, m->i->r.min);
+	qunlock(l);
+}
+
+Userlog *
+mkuserlog(void)
+{
+	Userlog *l;
+
+	l = emalloc(sizeof *l);
+	memset(l, 0, sizeof *l);
+	l->msgs.prev = l->msgs.next = &l->msgs;
+	l->send = userlog_send;
+	l->update = userlog_update;
+	l->draw = userlog_draw;
+	l->delmsg = userlog_delmsg;
+	return l;
+}
+
 void
+rmuserlog(Userlog *l)
+{
+	if(l->msgs.next != &l->msgs){
+		l->delmsg(l, l->msgs.next);
+		rmuserlog(l);
+		return;
+	}
+	free(l);
+}
+
+void
 materializefrustum(void)
 {
 	Primitive l;
@@ -334,6 +470,7 @@
 {
 	lockdisplay(display);
 	draw(screen, screen->r, screenb, nil, ZP);
+	usrlog->draw(usrlog);
 	drawopmode();
 	if(showhud)
 		drawstats();
@@ -388,6 +525,8 @@
 	for(;;){
 		recv(drawc, nil);
 		redraw();
+
+		usrlog->update(usrlog);
 	}
 }
 
@@ -446,28 +585,45 @@
 mmb(void)
 {
 	enum {
-		TSNEAR,
-		TSBILI,
-		SP,
+		ORBIT,
+		SELECT,
+		SP0,
+		SAVE,
+		SP1,
 		QUIT,
 	};
 	static char *items[] = {
-	 [TSNEAR]	"use nearest sampler",
-	 [TSBILI]	"use bilinear sampler",
-	 [SP]	"",
-	 [QUIT]	"quit",
+	 [ORBIT]	"orbit",
+	 [SELECT]	"select",
+			"",
+	 [SAVE]		"save",
+			"",
+	 [QUIT]		"quit",
 		nil,
 	};
 	static Menu menu = { .item = items };
+	static char buf[256];
+	int fd;
 
 	lockdisplay(display);
 	switch(menuhit(2, mctl, &menu, _screen)){
-	case TSNEAR:
-		tsampler = neartexsampler;
+	case ORBIT:
+		opmode = OMOrbit;
 		break;
-	case TSBILI:
-		tsampler = bilitexsampler;
+	case SELECT:
+		opmode = OMSelect;
 		break;
+	case SAVE:
+		if(enter("path", buf, sizeof buf, mctl, kctl, nil) <= 0)
+			break;
+		fd = create(buf, OWRITE, 0644);
+		if(fd < 0){
+			usrlog->send(usrlog, "create: %r");
+			break;
+		}
+		writemodel(fd, model);
+		close(fd);
+		break;
 	case QUIT:
 		threadexitsall(nil);
 	}
@@ -597,11 +753,6 @@
 {
 	static int okdown;
 
-	if((okdown & 1<<Kmodeorb) == 0 && (kdown & 1<<Kmodeorb) != 0)
-		opmode = OMOrbit;
-	else if((okdown & 1<<Kmodesel) == 0 && (kdown & 1<<Kmodesel) != 0)
-		opmode = OMSelect;
-
 	if(kdown & 1<<Kzoomin)
 		zoomin();
 	if(kdown & 1<<Kzoomout)
@@ -694,6 +845,7 @@
 	tsampler = neartexsampler;
 
 	setupcompass(&compass, rectaddpt(Rect(0,0,100,100), subpt(screenb->r.max, Pt(100,100))), rctl);
+	usrlog = mkuserlog();
 
 	kctl = emalloc(sizeof *kctl);
 	kctl->c = chancreate(sizeof(Rune), 16);