From 63eb46698b1e19d3f36944992b948c54a7a3740b Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Tue, 28 Apr 2026 07:50:31 +0200 Subject: Compiler settings and macOS port --- map.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 map.c (limited to 'map.c') 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 +#include +#include + +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 }; +} -- cgit v1.2.3