shithub: libstl

Download patch

ref: a86cea4bc4207f2193a2ba5e35730f1a087f5c06
author: rodri <rgl@antares-labs.eu>
date: Fri Mar 14 19:02:23 EDT 2025

initial implementation.

--- /dev/null
+++ b/mkfile
@@ -1,0 +1,9 @@
+</$objtype/mkfile
+
+LIB=libstl.a$O
+OFILES=\
+	stl.$O\
+
+HFILES=stl.h
+
+</sys/src/cmd/mklib
--- /dev/null
+++ b/readme.md
@@ -1,0 +1,3 @@
+# libstl
+
+Libstl provides a parser for the STL (binary) file format.
--- /dev/null
+++ b/stl.c
@@ -1,0 +1,158 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "stl.h"
+
+static int
+Bgets(Biobuf *b, u16int *s)
+{
+	uchar buf[2];
+
+	if(Bread(b, buf, 2) != 2){
+		werrstr("could not get 2 bytes");
+		return -1;
+	}
+	*s = buf[0] | buf[1] << 8;
+	return 0;
+}
+
+static int
+Bgetl(Biobuf *b, u32int *l)
+{
+	uchar buf[4];
+
+	if(Bread(b, buf, 4) != 4){
+		werrstr("could not get 4 bytes");
+		return -1;
+	}
+	*l = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+	return 0;
+}
+
+static int
+Bgetf(Biobuf *b, float *f)
+{
+	u32int l;
+
+	if(Bgetl(b, &l) < 0){
+		werrstr("Bgetl: %r");
+		return -1;
+	}
+	*f = *(float*)&l;
+	return 0;
+}
+
+static int
+Bgetfv(Biobuf *b, float *f)
+{
+	int i;
+
+	for(i = 0; i < 3; i++)
+		if(Bgetf(b, &f[i]) < 0){
+			werrstr("Bgetf: %r");
+			return -1;
+		}
+	return 0;
+}
+
+Stl *
+readstl(int fd)
+{
+	Biobuf *bin;
+	Stltri *tri;
+	Stl *stl;
+	u32int i, ntris;
+
+	bin = Bfdopen(fd, OREAD);
+	if(bin == nil){
+		werrstr("Bfdopen: %r");
+		return nil;
+	}
+
+	stl = mallocz(sizeof(Stl), 1);
+	if(stl == nil){
+		werrstr("mallocz: %r");
+		goto error;
+	}
+	if(Bread(bin, stl->hdr, sizeof(stl->hdr)) != sizeof(stl->hdr)){
+		werrstr("Bread: %r");
+		goto error;
+	}
+	if(Bgetl(bin, &ntris) < 0){
+		werrstr("Bgetl: %r");
+		goto error;
+	}
+
+	for(i = 0; i < ntris; i++){
+		tri = mallocz(sizeof(Stltri), 1);
+		if(tri == nil){
+			free(tri);
+			werrstr("mallocz: %r");
+			goto error;
+		}
+		if(Bgetfv(bin, tri->n) < 0){
+			free(tri);
+			werrstr("Bgetfv: %r");
+			goto error;
+		}
+		if(Bgetfv(bin, tri->p0) < 0){
+			free(tri);
+			werrstr("Bgetfv: %r");
+			goto error;
+		}
+		if(Bgetfv(bin, tri->p1) < 0){
+			free(tri);
+			werrstr("Bgetfv: %r");
+			goto error;
+		}
+		if(Bgetfv(bin, tri->p2) < 0){
+			free(tri);
+			werrstr("Bgetfv: %r");
+			goto error;
+		}
+
+		if(Bgets(bin, &tri->attrlen) < 0){
+			free(tri);
+			werrstr("Bgets: %r");
+			goto error;
+		}
+		tri = realloc(tri, sizeof(Stltri) + tri->attrlen);
+		if(tri == nil){
+			werrstr("realloc: %r");
+			goto error;
+		}
+		if(Bread(bin, tri->attrs, tri->attrlen) != tri->attrlen){
+			free(tri);
+			werrstr("Bread: %r");
+			goto error;
+		}
+
+		stl->tris = realloc(stl->tris, (stl->ntris+1)*sizeof(*stl->tris));
+		if(stl->tris == nil){
+			werrstr("realloc: %r");
+			goto error;
+		}
+		stl->tris[stl->ntris++] = tri;
+	}
+
+	Bterm(bin);
+	return stl;
+error:
+	Bterm(bin);
+	freestl(stl);
+	return nil;
+}
+
+void
+freestl(Stl *stl)
+{
+	int i;
+
+	if(stl == nil)
+		return;
+
+	for(i = 0; i < stl->ntris; i++)
+		free(stl->tris[i]);
+	free(stl->tris);
+	free(stl);
+}
--- /dev/null
+++ b/stl.h
@@ -1,0 +1,34 @@
+/*
+ * 	UINT8[80]    – Header                 - 80 bytes
+ * 	UINT32       – Number of triangles    - 04 bytes
+ * 	foreach triangle                      - 50 bytes
+ * 	    REAL32[3] – Normal vector         - 12 bytes
+ * 	    REAL32[3] – Vertex 1              - 12 bytes
+ * 	    REAL32[3] – Vertex 2              - 12 bytes
+ * 	    REAL32[3] – Vertex 3              - 12 bytes
+ * 	    UINT16    – Attribute byte count  - 02 bytes
+ * 	end
+*/
+
+typedef struct Stltri Stltri;
+typedef struct Stl Stl;
+
+struct Stltri
+{
+	float	n[3];
+	float	p0[3];
+	float	p1[3];
+	float	p2[3];
+	u16int	attrlen;
+	u8int	attrs[];
+};
+
+struct Stl
+{
+	u8int	hdr[80];
+	u32int	ntris;
+	Stltri	**tris;
+};
+
+Stl *readstl(int);
+void freestl(Stl*);
--- /dev/null
+++ b/test/main.c
@@ -1,0 +1,69 @@
+#include <u.h>
+#include <libc.h>
+#include "../stl.h"
+
+static char fd0[] = "/fd/0";
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [file]\n", argv0);
+	exits("usage");
+}
+
+static void
+printfv(float *f)
+{
+	print("%f\t%f\t%f", f[0], f[1], f[2]);
+}
+
+static void
+printstl(Stl *stl)
+{
+	int i;
+
+	print("header: %.*s\n", sizeof(stl->hdr), (char*)stl->hdr);
+	print("ntris: %ud\n", stl->ntris);
+	print("tris:\n");
+	for(i = 0; i < stl->ntris; i++){
+		print("\t%08d\n\t\tn\t", i);
+		printfv(stl->tris[i]->n);
+		print("\n\t\tp0\t");
+		printfv(stl->tris[i]->p0);
+		print("\n\t\tp1\t");
+		printfv(stl->tris[i]->p1);
+		print("\n\t\tp2\t");
+		printfv(stl->tris[i]->p2);
+		print("\n\t\tattrlen\t%d\n", stl->tris[i]->attrlen);
+		print("\n\t\tattrs: %.*s\n", stl->tris[i]->attrlen, (char*)stl->tris[i]->attrs);
+	}
+}
+
+void
+main(int argc, char *argv[])
+{
+	Stl *stl;
+	char *f;
+	int fd;
+
+	f = fd0;
+	ARGBEGIN{
+	default: usage();
+	}ARGEND;
+	if(argc > 1)
+		usage();
+	if(argc == 1)
+		f = argv[0];
+
+	fd = open(f, OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	stl = readstl(fd);
+	if(stl == nil)
+		sysfatal("readstl: %r");
+	close(fd);
+
+	printstl(stl);
+	freestl(stl);
+	exits(nil);
+}
--- /dev/null
+++ b/test/mkfile
@@ -1,0 +1,21 @@
+</$objtype/mkfile
+
+BIN=$home/$objtype/bin
+TARG=stltest
+OFILES=\
+	main.$O\
+
+HFILES=../stl.h
+
+LIB=\
+	../libstl.a$O\
+
+</sys/src/cmd/mkone
+
+../libstl.a$O:
+	cd ..
+	mk install
+
+clean nuke:V:
+	rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output $TARG
+	@{cd ..; mk $target}