#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 }; }