ref: d5147306c711858fe4c0380949c36f8358af7f3e
parent: 2a1566a9ccda2ec5a256b16306c04cf8b43c14b5
author: rodri <rgl@antares-labs.eu>
date: Sat May 24 20:19:49 EDT 2025
add writestl(2)
--- a/stl.2.man
+++ b/stl.2.man
@@ -1,6 +1,7 @@
.TH STL 2
.SH NAME
readstl,
+writestl,
freestl
\- STL parser
.SH SYNOPSIS
@@ -10,6 +11,11 @@
#include <libc.h>
#include <stl.h>
+enum {
+ STLTEXT,
+ STLBINARY,
+};
+
typedef struct Stltri Stltri;
typedef struct Stl Stl;
@@ -29,6 +35,7 @@
};
Stl *readstl(int fd);
+usize writestl(int fd, Stl *stl, int fmt);
void freestl(Stl *stl);
.EE
.SH DESCRIPTION
@@ -40,9 +47,11 @@
or solid.
.PP
.B Readstl
-takes an fd open for reading, and returns an allocated Stl structure
-filled with the model it contains. If the file couldn't be parsed, it
-will write the reason to the errstr and return nil.
+takes an
+.I fd
+open for reading, and returns an allocated Stl structure filled with
+the model it contains. If the file couldn't be parsed, it will write
+the reason to the errstr and return nil.
.PP
.B Freestl
frees an Stl structure created by
@@ -58,6 +67,16 @@
.B Stltri
respectively are not interpreted in any way, and are provided as
blobs; it's up to the user to give them some meaning.
+.PP
+.B Writestl
+takes an
+.I fd
+open for writing and dumps the
+.I stl
+structure with the given
+.I fmt
+(STLTEXT or STLBINARY). If an error
+occurs, it will write the reason to the errstr and return zero.
.SH SOURCE
.B /sys/src/libstl
.SH SEE ALSO
--- a/stl.c
+++ b/stl.c
@@ -71,6 +71,20 @@
}
static int
+Bputs(Biobuf *b, u16int s)
+{
+ uchar buf[2];
+
+ buf[0] = s;
+ buf[1] = s >> 8;
+ if(Bwrite(b, buf, 2) != 2){
+ werrstr("could not put 2 bytes");
+ return -1;
+ }
+ return 0;
+}
+
+static int
Bgetl(Biobuf *b, u32int *l)
{
uchar buf[4];
@@ -84,6 +98,22 @@
}
static int
+Bputl(Biobuf *b, u32int l)
+{
+ uchar buf[4];
+
+ buf[0] = l;
+ buf[1] = l >> 8;
+ buf[2] = l >> 16;
+ buf[3] = l >> 24;
+ if(Bwrite(b, buf, 4) != 4){
+ werrstr("could not put 4 bytes");
+ return -1;
+ }
+ return 0;
+}
+
+static int
Bgetf(Biobuf *b, float *f)
{
u32int l;
@@ -96,7 +126,21 @@
return 0;
}
+static int
+Bputf(Biobuf *b, float f)
+{
+ u32int l;
+
+ l = *(u32int*)&f;
+ if(Bputl(b, l) < 0){
+ werrstr("Bputl: %r");
+ return -1;
+ }
+ return 0;
+}
+
static int bunpack(Biobuf*, char*, ...);
+static int bpack(Biobuf*, char*, ...);
static int
vbunpack(Biobuf *b, char *fmt, va_list a)
@@ -145,6 +189,52 @@
}
static int
+vbpack(Biobuf *b, char *fmt, va_list a)
+{
+ u16int s;
+ u32int l;
+ float f, *v;
+ void *p;
+
+ for(;;){
+ switch(*fmt++){
+ case '\0':
+ return 0;
+ case 's':
+ s = va_arg(a, ushort);
+ if(Bputs(b, s) < 0)
+ goto error;
+ break;
+ case 'l':
+ l = va_arg(a, ulong);
+ if(Bputl(b, l) < 0)
+ goto error;
+ break;
+ case 'f':
+ f = va_arg(a, double);
+ if(Bputf(b, f) < 0)
+ goto error;
+ break;
+ case 'v':
+ v = va_arg(a, float*);
+ if(bpack(b, "fff", v[0], v[1], v[2]) < 0)
+ goto error;
+ break;
+ case '[':
+ p = va_arg(a, void*);
+ s = va_arg(a, ushort);
+ if(Bwrite(b, p, s) != s){
+ werrstr("Bwrite: could not write %ud bytes", s);
+ goto error;
+ }
+ break;
+ }
+ }
+error:
+ return -1;
+}
+
+static int
bunpack(Biobuf *b, char *fmt, ...)
{
va_list a;
@@ -157,6 +247,19 @@
return n;
}
+static int
+bpack(Biobuf *b, char *fmt, ...)
+{
+ va_list a;
+ int n;
+
+ va_start(a, fmt);
+ n = vbpack(b, fmt, a);
+ va_end(a);
+
+ return n;
+}
+
static char *
getline(Biobuf *b)
{
@@ -434,6 +537,84 @@
out:
Bterm(bin);
return stl;
+}
+
+static usize
+writetxt(Biobuf *b, Stl *stl)
+{
+ usize n;
+ int i, j;
+
+ n = Bprint(b, "solid");
+ if(strlen((char*)stl->hdr) > 0)
+ n += Bprint(b, " %s", (char*)stl->hdr);
+ n += Bprint(b, "\n");
+
+ for(i = 0; i < stl->ntris; i++){
+ n += Bprint(b, "facet normal %g %g %g\n",
+ stl->tris[i]->n[0], stl->tris[i]->n[1], stl->tris[i]->n[2]);
+ n += Bprint(b, "\touter loop\n");
+ for(j = 0; j < 3; j++)
+ n += Bprint(b, "\t\tvertex %g %g %g\n",
+ stl->tris[i]->v[j][0], stl->tris[i]->v[j][1], stl->tris[i]->v[j][2]);
+ n += Bprint(b, "\tendloop\n");
+ n += Bprint(b, "endfacet\n");
+ }
+
+ n += Bprint(b, "endsolid\n");
+ return n;
+}
+
+static usize
+writebin(Biobuf *b, Stl *stl)
+{
+ Stltri **tri;
+ usize n;
+
+ if(bpack(b, "[l", stl->hdr, sizeof(stl->hdr), stl->ntris) < 0){
+ werrstr("hdr pack: %r");
+ return 0;
+ }
+ n = sizeof(stl->hdr) + 4;
+
+ for(tri = stl->tris; tri < stl->tris+stl->ntris; tri++){
+ if(bpack(b, "vvvvs", (*tri)->n, (*tri)->v+0, (*tri)->v+1, (*tri)->v+2, (*tri)->attrlen) < 0){
+ werrstr("tri pack0: %r");
+ return 0;
+ }
+ n += 4*3*4+2;
+ if(bpack(b, "[", (*tri)->attrs, (*tri)->attrlen) < 0){
+ werrstr("tri pack1: %r");
+ return 0;
+ }
+ n += (*tri)->attrlen;
+ }
+ return n;
+}
+
+usize
+writestl(int fd, Stl *stl, int fmt)
+{
+ Biobuf *b;
+ usize n;
+
+ b = Bfdopen(fd, OWRITE);
+ if(b == nil)
+ sysfatal("Bfdopen: %r");
+
+ n = 0;
+ switch(fmt){
+ case STLTEXT:
+ n = writetxt(b, stl);
+ break;
+ case STLBINARY:
+ n = writebin(b, stl);
+ break;
+ default:
+ werrstr("unknown format '%d'", fmt);
+ }
+ Bterm(b);
+ return n;
}
void
--- a/stl.h
+++ b/stl.h
@@ -10,6 +10,11 @@
* end
*/
+enum {
+ STLTEXT,
+ STLBINARY,
+};
+
typedef struct Stltri Stltri;
typedef struct Stl Stl;
@@ -29,4 +34,5 @@
};
Stl *readstl(int);
+usize writestl(int, Stl*, int);
void freestl(Stl*);
--- a/test/main.c
+++ b/test/main.c
@@ -7,7 +7,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [file]\n", argv0);
+ fprint(2, "usage: %s [-o [tb]] [file]\n", argv0);
exits("usage");
}
@@ -14,7 +14,7 @@
static void
printfv(float *f)
{
- print("%f\t%f\t%f", f[0], f[1], f[2]);
+ fprint(2, "%f\t%f\t%f", f[0], f[1], f[2]);
}
static void
@@ -22,20 +22,20 @@
{
int i;
- print("header: %.*s\n", sizeof(stl->hdr), (char*)stl->hdr);
- print("ntris: %ud\n", stl->ntris);
- print("tris:\n");
+ fprint(2, "header: %.*s\n", sizeof(stl->hdr), (char*)stl->hdr);
+ fprint(2, "ntris: %ud\n", stl->ntris);
+ fprint(2, "tris:\n");
for(i = 0; i < stl->ntris; i++){
- print("\t%08d\n\t\tn\t", i);
+ fprint(2, "\t%08d\n\t\tn\t", i);
printfv(stl->tris[i]->n);
- print("\n\t\tp0\t");
+ fprint(2, "\n\t\tp0\t");
printfv(stl->tris[i]->v[0]);
- print("\n\t\tp1\t");
+ fprint(2, "\n\t\tp1\t");
printfv(stl->tris[i]->v[1]);
- print("\n\t\tp2\t");
+ fprint(2, "\n\t\tp2\t");
printfv(stl->tris[i]->v[2]);
- print("\n\t\tattrlen\t%d", stl->tris[i]->attrlen);
- print("\n\t\tattrs: %.*s\n", stl->tris[i]->attrlen, (char*)stl->tris[i]->attrs);
+ fprint(2, "\n\t\tattrlen\t%d", stl->tris[i]->attrlen);
+ fprint(2, "\n\t\tattrs: %.*s\n", stl->tris[i]->attrlen, (char*)stl->tris[i]->attrs);
}
}
@@ -43,11 +43,20 @@
main(int argc, char *argv[])
{
Stl *stl;
- char *f;
- int fd;
+ char *f, *fmt;
+ int fd, ofmt;
f = fd0;
+ ofmt = -1;
ARGBEGIN{
+ case 'o':
+ fmt = EARGF(usage());
+ switch(*fmt){
+ case 't': ofmt = STLTEXT; break;
+ case 'b': ofmt = STLBINARY; break;
+ default: sysfatal("unknown format '%d'", *fmt);
+ }
+ break;
default: usage();
}ARGEND;
if(argc > 1)
@@ -64,6 +73,8 @@
close(fd);
printstl(stl);
+ if(ofmt >= 0)
+ writestl(1, stl, ofmt);
freestl(stl);
exits(nil);
}
binary files /dev/null b/test/teapot.stl differ
--
⑨