summaryrefslogtreecommitdiff
path: root/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'map.c')
-rw-r--r--map.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/map.c b/map.c
new file mode 100644
index 0000000..f28476f
--- /dev/null
+++ b/map.c
@@ -0,0 +1,246 @@
+#include "all.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+char map_peek(MapParser *p) {
+ if (p->pos >= p->length) return 0;
+ return p->data[p->pos];
+}
+
+char map_get(MapParser *p) {
+ if (p->pos >= p->length) return 0;
+ return p->data[p->pos++];
+}
+
+void map_skip_whitespace(MapParser *p) {
+ while (true) {
+ char c = map_peek(p);
+ if (isspace(c)) {
+ map_get(p);
+ } else if (c == '/' && p->data[p->pos + 1] == '/') {
+ while (map_peek(p) != '\n' && map_peek(p) != 0) map_get(p);
+ } else {
+ break;
+ }
+ }
+}
+
+bool map_expect(MapParser *p, char expected) {
+ map_skip_whitespace(p);
+ if (map_get(p) == expected) return true;
+ return false;
+}
+
+void map_parse_token(MapParser *p, char *buffer, int size) {
+ map_skip_whitespace(p);
+ int i = 0;
+ bool quoted = false;
+ if (map_peek(p) == '"') {
+ quoted = true;
+ map_get(p);
+ }
+
+ while (true) {
+ char c = map_peek(p);
+ if (c == 0) break;
+ if (quoted) {
+ if (c == '"') {
+ map_get(p);
+ break;
+ }
+ } else {
+ if (isspace(c) || c == '(' || c == ')' || c == '{' || c == '}') break;
+ }
+ if (i < size - 1) buffer[i++] = map_get(p);
+ else map_get(p);
+ }
+ buffer[i] = 0;
+}
+
+Vector3 map_parse_vector(MapParser *p) {
+ map_expect(p, '(');
+ char buf[64];
+ map_parse_token(p, buf, sizeof(buf));
+ float x = (float)atof(buf);
+ map_parse_token(p, buf, sizeof(buf));
+ float y = (float)atof(buf);
+ map_parse_token(p, buf, sizeof(buf));
+ float z = (float)atof(buf);
+ map_expect(p, ')');
+ return (Vector3){ x, z, -y };
+}
+
+Map ParseMap(const char *filename) {
+ size_t size;
+ char *data = read_entire_file(filename, &size);
+ Map map = { 0 };
+ if (!data) return map;
+
+ MapParser p = { data, size, 0 };
+ array(MapEntity) entities;
+ array_init(entities);
+
+ while (true) {
+ map_skip_whitespace(&p);
+ if (map_peek(&p) == 0) break;
+
+ if (map_expect(&p, '{')) {
+ MapEntity entity = { 0 };
+ array(MapProperty) props;
+ array(MapBrush) brushes;
+ array_init(props);
+ array_init(brushes);
+
+ while (true) {
+ map_skip_whitespace(&p);
+ char c = map_peek(&p);
+ if (c == '}') {
+ map_get(&p);
+ break;
+ } else if (c == '"') {
+ MapProperty prop;
+ map_parse_token(&p, prop.key, sizeof(prop.key));
+ map_parse_token(&p, prop.value, sizeof(prop.value));
+ array_push(props, prop);
+ } else if (c == '{') {
+ map_get(&p);
+ MapBrush brush = { 0 };
+ array(MapPlane) planes;
+ array_init(planes);
+ while (true) {
+ map_skip_whitespace(&p);
+ if (map_peek(&p) == '}') {
+ map_get(&p);
+ break;
+ }
+ MapPlane plane;
+ plane.p[0] = map_parse_vector(&p);
+ plane.p[1] = map_parse_vector(&p);
+ plane.p[2] = map_parse_vector(&p);
+ map_parse_token(&p, plane.texture, sizeof(plane.texture));
+
+ char buf[64];
+ map_parse_token(&p, buf, sizeof(buf)); plane.shift[0] = (float)atof(buf);
+ map_parse_token(&p, buf, sizeof(buf)); plane.shift[1] = (float)atof(buf);
+ map_parse_token(&p, buf, sizeof(buf)); plane.rotate = (float)atof(buf);
+ map_parse_token(&p, buf, sizeof(buf)); plane.scale[0] = (float)atof(buf);
+ map_parse_token(&p, buf, sizeof(buf)); plane.scale[1] = (float)atof(buf);
+
+ array_push(planes, plane);
+ }
+ brush.planes = planes.data;
+ brush.plane_count = (int)planes.length;
+ array_push(brushes, brush);
+ } else {
+ map_get(&p);
+ }
+ }
+ entity.properties = props.data;
+ entity.property_count = (int)props.length;
+ entity.brushes = brushes.data;
+ entity.brush_count = (int)brushes.length;
+ array_push(entities, entity);
+ }
+ }
+
+ map.entities = entities.data;
+ map.entity_count = (int)entities.length;
+ free(data);
+ return map;
+}
+
+void FreeMap(Map map) {
+ for (int i = 0; i < map.entity_count; i++) {
+ MapEntity *e = &map.entities[i];
+ if (e->properties) free(e->properties);
+ for (int j = 0; j < e->brush_count; j++) {
+ if (e->brushes[j].planes) free(e->brushes[j].planes);
+ }
+ if (e->brushes) free(e->brushes);
+ }
+ if (map.entities) free(map.entities);
+}
+
+Plane PlaneFromPoints(Vector3 p1, Vector3 p2, Vector3 p3) {
+ Vector3 v1 = Vector3Subtract(p2, p1);
+ Vector3 v2 = Vector3Subtract(p3, p1);
+ Vector3 normal = Vector3Normalize(Vector3CrossProduct(v1, v2));
+ return (Plane){ normal, Vector3DotProduct(normal, p1) };
+}
+
+void PolyFree(Polygon p) {
+ if (p.verts) free(p.verts);
+}
+
+Polygon PolyClip(Polygon poly, Plane plane) {
+ if (poly.count == 0) return poly;
+
+ array(Vector3) out_verts;
+ array_init(out_verts);
+
+ for (int i = 0; i < poly.count; i++) {
+ Vector3 p1 = poly.verts[i];
+ Vector3 p2 = poly.verts[(i + 1) % poly.count];
+
+ float d1 = Vector3DotProduct(plane.normal, p1) - plane.dist;
+ float d2 = Vector3DotProduct(plane.normal, p2) - plane.dist;
+
+ // Using a smaller epsilon and more robust logic
+ const float eps = 0.001f;
+
+ if (d1 >= -eps) {
+ if (d2 >= -eps) {
+ array_push(out_verts, p2);
+ } else {
+ float t = d1 / (d1 - d2);
+ Vector3 intersect = Vector3Add(p1, Vector3Scale(Vector3Subtract(p2, p1), t));
+ array_push(out_verts, intersect);
+ }
+ } else {
+ if (d2 >= -eps) {
+ float t = d1 / (d1 - d2);
+ Vector3 intersect = Vector3Add(p1, Vector3Scale(Vector3Subtract(p2, p1), t));
+ array_push(out_verts, intersect);
+ array_push(out_verts, p2);
+ }
+ }
+ }
+
+ Polygon res;
+ res.verts = out_verts.data;
+ res.count = (int)out_verts.length;
+ return res;
+}
+
+Polygon CreateLargeQuad(Plane plane) {
+ Vector3 n = plane.normal;
+ Vector3 up = (fabsf(n.y) < 0.999f) ? (Vector3){ 0, 1, 0 } : (Vector3){ 1, 0, 0 };
+ Vector3 right = Vector3Normalize(Vector3CrossProduct(up, n));
+ up = Vector3CrossProduct(n, right);
+
+ Vector3 center = Vector3Scale(n, plane.dist);
+ float size = 10000.0f;
+
+ Polygon poly;
+ poly.verts = ALLOC(Vector3, 4);
+ poly.count = 4;
+ poly.verts[0] = Vector3Add(center, Vector3Add(Vector3Scale(right, size), Vector3Scale(up, size)));
+ poly.verts[1] = Vector3Add(center, Vector3Add(Vector3Scale(right, -size), Vector3Scale(up, size)));
+ poly.verts[2] = Vector3Add(center, Vector3Add(Vector3Scale(right, -size), Vector3Scale(up, -size)));
+ poly.verts[3] = Vector3Add(center, Vector3Add(Vector3Scale(right, size), Vector3Scale(up, -size)));
+
+ return poly;
+}
+
+Vector2 GetUV(Vector3 p, MapPlane *mp, Plane plane) {
+ Vector3 n = plane.normal;
+ Vector3 up = (fabsf(n.y) < 0.999f) ? (Vector3){ 0, 1, 0 } : (Vector3){ 1, 0, 0 };
+ Vector3 right = Vector3Normalize(Vector3CrossProduct(up, n));
+ up = Vector3CrossProduct(n, right);
+
+ float u = Vector3DotProduct(p, right) * (1.0f / (mp->scale[0] ? mp->scale[0] : 1.0f)) + mp->shift[0];
+ float v = Vector3DotProduct(p, up) * (1.0f / (mp->scale[1] ? mp->scale[1] : 1.0f)) + mp->shift[1];
+
+ return (Vector2){ u / 64.0f, v / 64.0f };
+}