shithub: libobj

Download patch

ref: 0f0a9514ccabd558e9b6610e7c6150a69e6f9bcd
parent: b4f6e218fccb523c9449a94b30cd6b2fa876a361
author: rodri <[email protected]>
date: Mon Oct 7 14:32:50 EDT 2024

leave a single, general error reporting fn. add specular map support.

improvements to path handling.

--- a/obj.c
+++ b/obj.c
@@ -13,38 +13,22 @@
 struct Line
 {
 	char *file;
-	ulong lineno;
+	ulong line;
 };
 
-static Line curline;
-static Line curmtline;
-
 static void
-error(char *fmt, ...)
+error(Line *l, char *fmt, ...)
 {
 	va_list va;
 	char buf[ERRMAX], *bp;
 
 	va_start(va, fmt);
-	bp = seprint(buf, buf + sizeof buf, "%s:%lud ", curline.file, curline.lineno);
+	bp = seprint(buf, buf + sizeof buf, "%s:%lud ", l->file, l->line);
 	vseprint(bp, buf + sizeof buf, fmt, va);
 	va_end(va);
 	werrstr("%s", buf);
 }
 
-static void
-mterror(char *fmt, ...)
-{
-	va_list va;
-	char buf[ERRMAX], *bp;
-
-	va_start(va, fmt);
-	bp = seprint(buf, buf + sizeof buf, "%s:%lud ", curmtline.file, curmtline.lineno);
-	vseprint(bp, buf + sizeof buf, fmt, va);
-	va_end(va);
-	werrstr("%s", buf);
-}
-
 static void *
 emalloc(ulong n)
 {
@@ -321,6 +305,7 @@
 freemt(OBJMaterial *m)
 {
 	freememimage(m->norm);
+	freememimage(m->map_Ks);
 	freememimage(m->map_Kd);
 	free(m->name);
 	free(m);
@@ -374,28 +359,35 @@
 OBJMaterlist *
 objmtlparse(char *file)
 {
+	Line curline;
 	OBJMaterlist *ml;
 	OBJMaterial *m;
 	Biobuf *bin;
-	char *line, *f[10], *p, buf[128];
+	char *line, *f[10], *p, wdir[128], buf[128];
 	int nf;
 
-	if((p = strrchr(curline.file, '/')) != nil)
-		snprint(buf, sizeof buf, "%.*s/%s", (int)(p-curline.file), curline.file, file);
-	else
-		snprint(buf, sizeof buf, "%s", file);
-
-	bin = Bopen(buf, OREAD);
-	if(bin == nil)
+	bin = Bopen(file, OREAD);
+	if(bin == nil){
+		werrstr("Bopen: %r");
 		return nil;
+	}
 
+	if((p = strrchr(file, '/')) != nil){
+		*p++ = 0;
+		snprint(wdir, sizeof wdir, "%s", file);
+		file = p;
+	}else{
+		wdir[0] = '.';
+		wdir[1] = 0;
+	}
+
 	ml = allocmtl(file);
 	m = nil;
-	curmtline.file = file;
-	curmtline.lineno = 0;
+	curline.file = file;
+	curline.line = 0;
 
 	while((line = Brdline(bin, '\n')) != nil){
-		curmtline.lineno++;
+		curline.line++;
 		line[Blinelen(bin)-1] = 0;
 
 		nf = tokenize(line, f, nelem(f));
@@ -404,7 +396,7 @@
 
 		if(strcmp(f[0], "newmtl") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			m = allocmt(f[1]);
@@ -411,11 +403,11 @@
 			addmtl(ml, m);
 		}else if(strcmp(f[0], "Ka") == 0){
 			if(nf != 2 && nf != 4){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			if(nf == 2)
@@ -428,11 +420,11 @@
 			m->Ka.a = 1;
 		}else if(strcmp(f[0], "Kd") == 0){
 			if(nf != 2 && nf != 4){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			if(nf == 2)
@@ -445,11 +437,11 @@
 			m->Kd.a = 1;
 		}else if(strcmp(f[0], "Ks") == 0){
 			if(nf != 2 && nf != 4){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			if(nf == 2)
@@ -462,11 +454,11 @@
 			m->Ks.a = 1;
 		}else if(strcmp(f[0], "Ke") == 0){
 			if(nf != 2 && nf != 4){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			if(nf == 2)
@@ -479,75 +471,83 @@
 			m->Ke.a = 1;
 		}else if(strcmp(f[0], "Ns") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			m->Ns = strtod(f[1], nil);
 		}else if(strcmp(f[0], "Ni") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			m->Ni = strtod(f[1], nil);
 		}else if(strcmp(f[0], "d") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			m->d = strtod(f[1], nil);
 		}else if(strcmp(f[0], "map_Kd") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
-			if(p != nil)
-				snprint(buf, sizeof buf, "%.*s/%s", (int)(p-curline.file), curline.file, f[1]);
-			else
-				snprint(buf, sizeof buf, "%s", f[1]);
+			snprint(buf, sizeof buf, "%s/%s", wdir, f[1]);
 			if((m->map_Kd = readimagefile(buf)) == nil){
-				mterror("readimagefile: %r");
+				error(&curline, "readimagefile: %r");
 				goto error;
 			}
+		}else if(strcmp(f[0], "map_Ks") == 0){
+			if(nf != 2){
+				error(&curline, "syntax error");
+				goto error;
+			}
+			if(m == nil){
+				error(&curline, "no material found");
+				goto error;
+			}
+			snprint(buf, sizeof buf, "%s/%s", wdir, f[1]);
+			if((m->map_Ks = readimagefile(buf)) == nil){
+				error(&curline, "readimagefile: %r");
+				goto error;
+			}
 		}else if(strcmp(f[0], "norm") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
-			if(p != nil)
-				snprint(buf, sizeof buf, "%.*s/%s", (int)(p-curline.file), curline.file, f[1]);
-			else
-				snprint(buf, sizeof buf, "%s", f[1]);
+			snprint(buf, sizeof buf, "%s/%s", wdir, f[1]);
 			if((m->norm = readimagefile(buf)) == nil){
-				mterror("readimagefile: %r");
+				error(&curline, "readimagefile: %r");
 				goto error;
 			}
 		}else if(strcmp(f[0], "illum") == 0){
 			if(nf != 2){
-				mterror("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			if(m == nil){
-				mterror("no material found");
+				error(&curline, "no material found");
 				goto error;
 			}
 			m->illum = strtol(f[1], nil, 10);
@@ -582,6 +582,7 @@
 objparse(char *file)
 {
 	Biobuf *bin;
+	Line curline;
 	OBJ *obj;
 	OBJObject *o;
 	OBJMaterial *m;
@@ -588,7 +589,7 @@
 	OBJElem *e;
 	OBJVertex v;
 	double *d;
-	char c, buf[256], *p;
+	char c, wdir[128], buf[256], *p;
 	int vtype, idxtab, idx, sign;
 
 	m = nil;
@@ -596,8 +597,16 @@
 	bin = Bopen(file, OREAD);
 	if(bin == nil)
 		sysfatal("Bopen: %r");
+	if((p = strrchr(file, '/')) != nil){
+		*p++ = 0;
+		snprint(wdir, sizeof wdir, "%s", file);
+		file = p;
+	}else{
+		wdir[0] = '.';
+		wdir[1] = 0;
+	}
 	curline.file = file;
-	curline.lineno = 1;
+	curline.line = 1;
 	obj = emalloc(sizeof(OBJ));
 	while((c = Bgetc(bin)) != Beof){
 		switch(c){
@@ -611,7 +620,7 @@
 			case 'n': vtype = OBJVNormal; break;
 			default:
 				if(!isspace(c)){
-					error("wrong vertex type");
+					error(&curline, "wrong vertex type");
 					goto error;
 				}
 			}
@@ -624,7 +633,7 @@
 					continue;
 				}
 				if(c != '-' && !isdigit(c)){
-					error("unexpected character '%c'", c);
+					error(&curline, "unexpected character '%c'", c);
 					goto error;
 				}
 				Bungetc(bin);
@@ -633,7 +642,7 @@
 			switch(vtype){
 			case OBJVGeometric:
 				if(d-(double*)&v < 3){
-					error("not enough coordinates");
+					error(&curline, "not enough coordinates");
 					goto error;
 				}
 				if(d-(double*)&v < 4)
@@ -641,7 +650,7 @@
 				break;
 			case OBJVTexture:
 				if(d-(double*)&v < 1){
-					error("not enough coordinates");
+					error(&curline, "not enough coordinates");
 					goto error;
 				}
 				while(d-(double*)&v < 3)
@@ -649,7 +658,7 @@
 				break;
 			case OBJVParametric:
 				if(d-(double*)&v < 2){
-					error("not enough coordinates");
+					error(&curline, "not enough coordinates");
 					goto error;
 				}
 				if(d-(double*)&v < 3)
@@ -657,7 +666,7 @@
 				break;
 			case OBJVNormal:
 				if(d-(double*)&v < 3){
-					error("not enough coordinates");
+					error(&curline, "not enough coordinates");
 					goto error;
 				}
 			}
@@ -667,13 +676,13 @@
 			p = buf;
 			c = Bgetc(bin);
 			if(!isspace(c)){
-				error("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			while(isspace(c))
 				c = Bgetc(bin);
 			if(!isalnum(c)){
-				error("unexpected character '%c'", c);
+				error(&curline, "unexpected character '%c'", c);
 				goto error;
 			}
 			do{
@@ -695,7 +704,7 @@
 		case 'p':
 			c = Bgetc(bin);
 			if(!isspace(c)){
-				error("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			while(c = Bgetc(bin), c != '\n'){
@@ -709,7 +718,7 @@
 					continue;
 				}
 				if(c != '-' && !isdigit(c)){
-					error("unexpected character '%c'", c);
+					error(&curline, "unexpected character '%c'", c);
 					goto error;
 				}
 				if(c == '-'){
@@ -716,7 +725,7 @@
 					sign = 1;
 					c = Bgetc(bin);
 					if(!isdigit(c)){
-						error("unexpected character '%c'", c);
+						error(&curline, "unexpected character '%c'", c);
 						goto error;
 					}
 				}
@@ -726,7 +735,7 @@
 				Bungetc(bin);
 				idx = sign ? obj->vertdata[OBJVGeometric].nvert-idx : idx-1;
 				if(idx+1 > obj->vertdata[OBJVGeometric].nvert){
-					error("not enough vertices");
+					error(&curline, "not enough vertices");
 					goto error;
 				}
 				e = allocelem(OBJEPoint);
@@ -743,7 +752,7 @@
 		case 'l':
 			c = Bgetc(bin);
 			if(!isspace(c)){
-				error("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			while(c = Bgetc(bin), c != '\n'){
@@ -757,7 +766,7 @@
 					continue;
 				}
 				if(c != '-' && !isdigit(c)){
-					error("unexpected character '%c'", c);
+					error(&curline, "unexpected character '%c'", c);
 					goto error;
 				}
 				if(c == '-'){
@@ -764,7 +773,7 @@
 					sign = 1;
 					c = Bgetc(bin);
 					if(!isdigit(c)){
-						error("unexpected character '%c'", c);
+						error(&curline, "unexpected character '%c'", c);
 						goto error;
 					}
 				}
@@ -773,7 +782,7 @@
 				}while(c = Bgetc(bin), isdigit(c));
 				idx = sign ? obj->vertdata[OBJVGeometric].nvert-idx : idx-1;
 				if(idx+1 > obj->vertdata[OBJVGeometric].nvert){
-					error("not enough vertices");
+					error(&curline, "not enough vertices");
 					goto error;
 				}
 				e = allocelem(OBJELine);
@@ -791,7 +800,7 @@
 				}
 				if(c != '-' && !isdigit(c)){
 					freeelem(e);
-					error("unexpected character '%c'", c);
+					error(&curline, "unexpected character '%c'", c);
 					goto error;
 				}
 				if(c == '-'){
@@ -799,7 +808,7 @@
 					c = Bgetc(bin);
 					if(!isdigit(c)){
 						freeelem(e);
-						error("unexpected character '%c'", c);
+						error(&curline, "unexpected character '%c'", c);
 						goto error;
 					}
 				}
@@ -810,7 +819,7 @@
 				idx = sign ? obj->vertdata[OBJVGeometric].nvert-idx : idx-1;
 				if(idx+1 > obj->vertdata[OBJVGeometric].nvert){
 					freeelem(e);
-					error("not enough vertices");
+					error(&curline, "not enough vertices");
 					goto error;
 				}
 				addelemidx(e, OBJVGeometric, idx);
@@ -829,7 +838,7 @@
 			c = Bgetc(bin);
 			if(!isspace(c)){
 				freeelem(e);
-				error("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			while(c = Bgetc(bin), c != '\n'){
@@ -847,7 +856,7 @@
 				if(c == '/'){
 					if(++idxtab >= OBJNVERT){
 						freeelem(e);
-						error("unknown vertex type '%d'", idxtab);
+						error(&curline, "unknown vertex type '%d'", idxtab);
 						goto error;
 					}
 					continue;
@@ -854,7 +863,7 @@
 				}
 				if(c != '-' && !isdigit(c)){
 					freeelem(e);
-					error("unexpected character '%c'", c);
+					error(&curline, "unexpected character '%c'", c);
 					goto error;
 				}
 				if(c == '-'){
@@ -862,7 +871,7 @@
 					c = Bgetc(bin);
 					if(!isdigit(c)){
 						freeelem(e);
-						error("unexpected character '%c'", c);
+						error(&curline, "unexpected character '%c'", c);
 						goto error;
 					}
 				}
@@ -873,7 +882,7 @@
 				idx = sign ? obj->vertdata[idxtab].nvert-idx : idx-1;
 				if(idx+1 > obj->vertdata[idxtab].nvert){
 					freeelem(e);
-					error("not enough vertices");
+					error(&curline, "not enough vertices");
 					goto error;
 				}
 				addelemidx(e, idxtab, idx);
@@ -896,14 +905,14 @@
 			if(strcmp(buf, "mtllib") == 0){
 				while(isspace(c))
 					c = Bgetc(bin);
-				p = buf;
+				p = seprint(buf, buf + sizeof buf, "%s/", wdir);
 				do{
 					*p++ = c;
 				}while(c = Bgetc(bin), (isalnum(c) || c == '.' || c == '_' || c == '-') && p-buf < sizeof(buf)-1);
 				*p = 0;
 				if((obj->materials = objmtlparse(buf)) == nil){
-					error("objmtlparse: %r");
-					fprint(2, "%r");
+					error(&curline, "warning: objmtlparse: %r");
+					fprint(2, "%r\n");
 				}
 			}else if(strcmp(buf, "usemtl") == 0){
 				while(isspace(c))
@@ -914,11 +923,11 @@
 				}while(c = Bgetc(bin), (isalnum(c) || c == '.' || c == '_' || c == '-' || c == '(' || c == ')') && p-buf < sizeof(buf)-1);
 				*p = 0;
 				if(obj->materials != nil && (m = getmtl(obj->materials, buf)) == nil){
-					error("no material '%s' found", buf);
+					error(&curline, "no material '%s' found", buf);
 					goto error;
 				}
 			}else{
-				error("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 			while(c != '\n')
@@ -931,11 +940,11 @@
 		}
 		do{
 			if(c == '\n'){
-				curline.lineno++;
+				curline.line++;
 				break;
 			}
 			if(!isspace(c)){
-				error("syntax error");
+				error(&curline, "syntax error");
 				goto error;
 			}
 		}while((c = Bgetc(bin)) != Beof);
--- a/obj.h
+++ b/obj.h
@@ -72,9 +72,10 @@
 	OBJColor Ke;		/* emissive color */
 	double Ns;		/* specular highlight */
 	double Ni;		/* index of refraction */
-	double d;		/* dissolution factor */
+	double d;		/* dissolution factor (opacity) */
 	int illum;		/* illumination model */
 	Memimage *map_Kd;	/* color texture file */
+	Memimage *map_Ks;	/* specular texture file */
 	Memimage *norm;		/* normal texture file */
 	OBJMaterial *next;
 };