From ea530015e97e5280b61f3a8bc2d2ddee5c0e2dff Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Mon, 6 Feb 2023 11:59:28 -0600
Subject: implement kai_read_triangles

---
 src/geometry/geometry.c      | 104 ++++++++++++++++++++++++++++++++++++++-----
 src/geometry/geometry.h      |   3 ++
 src/geometry/geometry.test.c |  71 +++++++++++++++++++++++++++++
 src/util/util.c              |  20 +++++++++
 src/util/util.h              |   2 +
 5 files changed, 189 insertions(+), 11 deletions(-)

(limited to 'src')

diff --git a/src/geometry/geometry.c b/src/geometry/geometry.c
index ea04fd3..78fbaea 100644
--- a/src/geometry/geometry.c
+++ b/src/geometry/geometry.c
@@ -12,6 +12,14 @@ if (strcmp(src->type, expected) != 0) { \
 	return -1; \
 }
 
+/* helper macro for iterating over tag children of a particular type */
+#define FOR_CHILD_OF_TYPE(parent, child, type) \
+for ( \
+	child = kai_tag_get_first_child_with_type(parent, type); \
+	child != NULL; \
+	child = kai_tag_get_next_sibling_with_type(child, type) \
+)
+
 
 int kai_read_float_array(struct ka_float_array_t *dest, struct kai_tag_t *src)
 {
@@ -219,8 +227,8 @@ int kai_read_vertices(struct ka_vertices_t *dest, struct kai_tag_t *src)
 	/* count input children */
 	int count = 0;
 	struct kai_tag_t *child;
-	for (child = src->children; child != NULL; child = child->next) {
-		if (strcmp(child->type, "input") == 0) { count += 1; }
+	FOR_CHILD_OF_TYPE(src, child, "input") {
+		count += 1;
 	}
 
 	dest->input_count = count;
@@ -231,16 +239,14 @@ int kai_read_vertices(struct ka_vertices_t *dest, struct kai_tag_t *src)
 	}
 
 	int i=0;
-	for (child = src->children; child != NULL; child = child->next) {
-		if (strcmp(child->type, "input") == 0) {
-			int result = kai_read_input_unshared(dest->input + i, child);
-			if (result != 0) {
-				dest->input_count = i;
-				kai_release_vertices(*dest);
-				return -1;
-			}
-			i += 1;
+	FOR_CHILD_OF_TYPE(src, child, "input") {
+		int result = kai_read_input_unshared(dest->input + i, child);
+		if (result != 0) {
+			dest->input_count = i;
+			kai_release_vertices(*dest);
+			return -1;
 		}
+		i += 1;
 	}
 
 	return 0;
@@ -258,3 +264,79 @@ void kai_release_vertices(struct ka_vertices_t v)
 }
 
 
+int kai_read_triangles(struct ka_triangles_t *dest, struct kai_tag_t *src)
+{
+	CHECK_TAG_TYPE("triangles");
+
+	long count = kai_tag_attr_to_long(src, "count", -1);
+	if (count == -1) { return -1; }
+
+	dest->name = kai_tag_attr_to_dup(src, "name");
+	dest->count = count;
+	dest->material = kai_tag_attr_to_dup(src, "material");
+
+	
+	/* zero these out so that any error-related calls to kai_release_triangles
+	 * won't cause an invalid free
+	 */
+	dest->input_count = 0;
+	dest->input = NULL;
+	dest->p_count = 0;
+	dest->p = NULL;
+
+	/* load the child inputs into the structure */
+	int input_count = 0;
+	struct kai_tag_t *child;
+	FOR_CHILD_OF_TYPE(src, child, "input") {
+		input_count += 1;
+	}
+
+	dest->input = kai_alloc(input_count * sizeof(struct ka_input_t), "triangles input array");
+	if (dest->input == NULL) {
+		kai_release_triangles(*dest);
+		return -1;
+	}
+
+	int i=0;
+	FOR_CHILD_OF_TYPE(src, child, "input") {
+		int result = kai_read_input_shared(dest->input + i, child);
+		if (result != 0) {
+			dest->input_count = i;
+			kai_release_triangles(*dest);
+			return -1;
+		}
+		i += 1;
+	}
+	dest->input_count = input_count;
+
+
+	/* load the child p tag */
+	struct kai_tag_t *p = kai_tag_get_first_child_with_type(src, "p");
+	if (p != NULL) {
+		dest->p_count = 3 * dest->count * dest->input_count;
+		dest->p = kai_alloc(dest->p_count * sizeof(unsigned int), "triangles primitive array");
+		if (dest->p == NULL) {
+			dest->p_count = 0;
+			kai_release_triangles(*dest);
+			return -1;
+		}
+		kai_text_to_uints(dest->p, p->content, dest->p_count);
+	}
+
+	return 0;
+}
+
+void kai_release_triangles(struct ka_triangles_t t)
+{
+	free(t.name);
+	free(t.material);
+
+	int i;
+	for (i=0; i<t.input_count; i++) {
+		kai_release_input(t.input[i]);
+	}
+	free(t.input);
+	free(t.p);
+}
+
+
diff --git a/src/geometry/geometry.h b/src/geometry/geometry.h
index a5ebab7..26fc16b 100644
--- a/src/geometry/geometry.h
+++ b/src/geometry/geometry.h
@@ -23,4 +23,7 @@ void kai_release_input(struct ka_input_t i);
 int kai_read_vertices(struct ka_vertices_t *dest, struct kai_tag_t *src);
 void kai_release_vertices(struct ka_vertices_t v);
 
+int kai_read_triangles(struct ka_triangles_t *dest, struct kai_tag_t *src);
+void kai_release_triangles(struct ka_triangles_t t);
+
 #endif
diff --git a/src/geometry/geometry.test.c b/src/geometry/geometry.test.c
index 968060d..d918ffa 100644
--- a/src/geometry/geometry.test.c
+++ b/src/geometry/geometry.test.c
@@ -408,6 +408,77 @@ LILY_TEST("read vertices tag")
 #include LILY_PUSH_TEST()
 
 
+LILY_TEST("fail to read non-triangles tag")
+{
+	struct kai_tag_t *t = kai_parse_string(
+		"<tag />"
+	);
+
+	struct ka_triangles_t triangles;
+	int result = kai_read_triangles(&triangles, t);
+	CHECK_EQ(result, -1, "%d");
+
+	kai_tag_destroy(t);
+}
+#include LILY_PUSH_TEST()
+
+
+LILY_TEST("fail to read triangles tag with no specified count")
+{
+	struct kai_tag_t *t = kai_parse_string(
+		"<triangles />"
+	);
+
+	struct ka_triangles_t triangles;
+	int result = kai_read_triangles(&triangles, t);
+	CHECK_EQ(result, -1, "%d");
+	kai_tag_destroy(t);
+}
+#include LILY_PUSH_TEST()
+
+
+LILY_TEST("read triangles tag")
+{
+	struct kai_tag_t *t = kai_parse_string(
+		"<triangles count=\"2\" material=\"Bricks\">"
+		"	<input semantic=\"VERTEX\" source=\"#verts\" offset=\"0\"/>"
+		"	<input semantic=\"NORMAL\" source=\"#normal\" offset=\"1\"/>"
+		"	<p>"
+		"		0 0 1 3 2 1"
+		"		0 0 2 1 3 2"
+		"	</p>"
+		"</triangles>"
+	);
+
+	struct ka_triangles_t triangles;
+	int result = kai_read_triangles(&triangles, t);
+	kai_tag_destroy(t);
+
+	REQUIRE_EQ(result, 0, "%d");
+	CHECK_EQ(triangles.name, NULL, "%p");
+	CHECK_EQ(triangles.count, 2, "%d");
+	CHECK_EQS(triangles.material, "Bricks");
+	CHECK_EQ(triangles.input_count, 2, "%d");
+	CHECK_EQS(triangles.input[1].semantic, "NORMAL");
+	CHECK_EQ(triangles.p_count, 12, "%d");
+	CHECK_EQ(triangles.p[0], 0, "%d");
+	CHECK_EQ(triangles.p[1], 0, "%d");
+	CHECK_EQ(triangles.p[2], 1, "%d");
+	CHECK_EQ(triangles.p[3], 3, "%d");
+	CHECK_EQ(triangles.p[4], 2, "%d");
+	CHECK_EQ(triangles.p[5], 1, "%d");
+
+	CHECK_EQ(triangles.p[6], 0, "%d");
+	CHECK_EQ(triangles.p[7], 0, "%d");
+	CHECK_EQ(triangles.p[8], 2, "%d");
+	CHECK_EQ(triangles.p[9], 1, "%d");
+	CHECK_EQ(triangles.p[10], 3, "%d");
+	CHECK_EQ(triangles.p[11], 2, "%d");
+
+	kai_release_triangles(triangles);
+}
+#include LILY_PUSH_TEST()
+
 
 
 #define LILY_FILE_END
diff --git a/src/util/util.c b/src/util/util.c
index 4f79870..c113377 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -64,6 +64,26 @@ size_t kai_text_to_longs(long *dest, const char *str, size_t count)
 }
 
 
+size_t kai_text_to_uints(unsigned int *dest, const char *str, size_t count)
+{
+	char *nptr = (char*) str;
+	char *end;
+
+	size_t result = count;
+
+	int i;
+	for (i=0; i<count; i++) {
+		dest[i] = strtol(nptr, &end, 10);
+		if (nptr == end) {
+			result -= 1;
+		}
+		nptr = end;
+	}
+
+	return result;
+}
+
+
 void *kai_alloc(size_t size, const char *purpose)
 {
 	void *buf = malloc(size);
diff --git a/src/util/util.h b/src/util/util.h
index d5fa636..67d3922 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -34,6 +34,8 @@ size_t kai_text_to_reals(ka_real_t *dest, const char *str, size_t count);
 
 size_t kai_text_to_longs(long *dest, const char *str, size_t count);
 
+size_t kai_text_to_uints(unsigned int *dest, const char *str, size_t count);
+
 
 void *kai_alloc(size_t size, const char *purpose);
 
-- 
cgit v1.2.1