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}