summaryrefslogtreecommitdiff
path: root/map.c
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-04-28 07:50:31 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-04-28 09:23:47 +0200
commit63eb46698b1e19d3f36944992b948c54a7a3740b (patch)
tree1aa8b686039e2f9291d680c21a47427de5daa12b /map.c
parent0ed91795a2db720e688fd2daefd22f7e9c754c2f (diff)
downloadstalag-63eb46698b1e19d3f36944992b948c54a7a3740b.tar.gz
Compiler settings and macOS port
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 @@
1#include "all.h"
2#include <ctype.h>
3#include <stdlib.h>
4#include <stdio.h>
5
6char map_peek(MapParser *p) {
7 if (p->pos >= p->length) return 0;
8 return p->data[p->pos];
9}
10
11char map_get(MapParser *p) {
12 if (p->pos >= p->length) return 0;
13 return p->data[p->pos++];
14}
15
16void map_skip_whitespace(MapParser *p) {
17 while (true) {
18 char c = map_peek(p);
19 if (isspace(c)) {
20 map_get(p);
21 } else if (c == '/' && p->data[p->pos + 1] == '/') {
22 while (map_peek(p) != '\n' && map_peek(p) != 0) map_get(p);
23 } else {
24 break;
25 }
26 }
27}
28
29bool map_expect(MapParser *p, char expected) {
30 map_skip_whitespace(p);
31 if (map_get(p) == expected) return true;
32 return false;
33}
34
35void map_parse_token(MapParser *p, char *buffer, int size) {
36 map_skip_whitespace(p);
37 int i = 0;
38 bool quoted = false;
39 if (map_peek(p) == '"') {
40 quoted = true;
41 map_get(p);
42 }
43
44 while (true) {
45 char c = map_peek(p);
46 if (c == 0) break;
47 if (quoted) {
48 if (c == '"') {
49 map_get(p);
50 break;
51 }
52 } else {
53 if (isspace(c) || c == '(' || c == ')' || c == '{' || c == '}') break;
54 }
55 if (i < size - 1) buffer[i++] = map_get(p);
56 else map_get(p);
57 }
58 buffer[i] = 0;
59}
60
61Vector3 map_parse_vector(MapParser *p) {
62 map_expect(p, '(');
63 char buf[64];
64 map_parse_token(p, buf, sizeof(buf));
65 float x = (float)atof(buf);
66 map_parse_token(p, buf, sizeof(buf));
67 float y = (float)atof(buf);
68 map_parse_token(p, buf, sizeof(buf));
69 float z = (float)atof(buf);
70 map_expect(p, ')');
71 return (Vector3){ x, z, -y };
72}
73
74Map ParseMap(const char *filename) {
75 size_t size;
76 char *data = read_entire_file(filename, &size);
77 Map map = { 0 };
78 if (!data) return map;
79
80 MapParser p = { data, size, 0 };
81 array(MapEntity) entities;
82 array_init(entities);
83
84 while (true) {
85 map_skip_whitespace(&p);
86 if (map_peek(&p) == 0) break;
87
88 if (map_expect(&p, '{')) {
89 MapEntity entity = { 0 };
90 array(MapProperty) props;
91 array(MapBrush) brushes;
92 array_init(props);
93 array_init(brushes);
94
95 while (true) {
96 map_skip_whitespace(&p);
97 char c = map_peek(&p);
98 if (c == '}') {
99 map_get(&p);
100 break;
101 } else if (c == '"') {
102 MapProperty prop;
103 map_parse_token(&p, prop.key, sizeof(prop.key));
104 map_parse_token(&p, prop.value, sizeof(prop.value));
105 array_push(props, prop);
106 } else if (c == '{') {
107 map_get(&p);
108 MapBrush brush = { 0 };
109 array(MapPlane) planes;
110 array_init(planes);
111 while (true) {
112 map_skip_whitespace(&p);
113 if (map_peek(&p) == '}') {
114 map_get(&p);
115 break;
116 }
117 MapPlane plane;
118 plane.p[0] = map_parse_vector(&p);
119 plane.p[1] = map_parse_vector(&p);
120 plane.p[2] = map_parse_vector(&p);
121 map_parse_token(&p, plane.texture, sizeof(plane.texture));
122
123 char buf[64];
124 map_parse_token(&p, buf, sizeof(buf)); plane.shift[0] = (float)atof(buf);
125 map_parse_token(&p, buf, sizeof(buf)); plane.shift[1] = (float)atof(buf);
126 map_parse_token(&p, buf, sizeof(buf)); plane.rotate = (float)atof(buf);
127 map_parse_token(&p, buf, sizeof(buf)); plane.scale[0] = (float)atof(buf);
128 map_parse_token(&p, buf, sizeof(buf)); plane.scale[1] = (float)atof(buf);
129
130 array_push(planes, plane);
131 }
132 brush.planes = planes.data;
133 brush.plane_count = (int)planes.length;
134 array_push(brushes, brush);
135 } else {
136 map_get(&p);
137 }
138 }
139 entity.properties = props.data;
140 entity.property_count = (int)props.length;
141 entity.brushes = brushes.data;
142 entity.brush_count = (int)brushes.length;
143 array_push(entities, entity);
144 }
145 }
146
147 map.entities = entities.data;
148 map.entity_count = (int)entities.length;
149 free(data);
150 return map;
151}
152
153void FreeMap(Map map) {
154 for (int i = 0; i < map.entity_count; i++) {
155 MapEntity *e = &map.entities[i];
156 if (e->properties) free(e->properties);
157 for (int j = 0; j < e->brush_count; j++) {
158 if (e->brushes[j].planes) free(e->brushes[j].planes);
159 }
160 if (e->brushes) free(e->brushes);
161 }
162 if (map.entities) free(map.entities);
163}
164
165Plane PlaneFromPoints(Vector3 p1, Vector3 p2, Vector3 p3) {
166 Vector3 v1 = Vector3Subtract(p2, p1);
167 Vector3 v2 = Vector3Subtract(p3, p1);
168 Vector3 normal = Vector3Normalize(Vector3CrossProduct(v1, v2));
169 return (Plane){ normal, Vector3DotProduct(normal, p1) };
170}
171
172void PolyFree(Polygon p) {
173 if (p.verts) free(p.verts);
174}
175
176Polygon PolyClip(Polygon poly, Plane plane) {
177 if (poly.count == 0) return poly;
178
179 array(Vector3) out_verts;
180 array_init(out_verts);
181
182 for (int i = 0; i < poly.count; i++) {
183 Vector3 p1 = poly.verts[i];
184 Vector3 p2 = poly.verts[(i + 1) % poly.count];
185
186 float d1 = Vector3DotProduct(plane.normal, p1) - plane.dist;
187 float d2 = Vector3DotProduct(plane.normal, p2) - plane.dist;
188
189 // Using a smaller epsilon and more robust logic
190 const float eps = 0.001f;
191
192 if (d1 >= -eps) {
193 if (d2 >= -eps) {
194 array_push(out_verts, p2);
195 } else {
196 float t = d1 / (d1 - d2);
197 Vector3 intersect = Vector3Add(p1, Vector3Scale(Vector3Subtract(p2, p1), t));
198 array_push(out_verts, intersect);
199 }
200 } else {
201 if (d2 >= -eps) {
202 float t = d1 / (d1 - d2);
203 Vector3 intersect = Vector3Add(p1, Vector3Scale(Vector3Subtract(p2, p1), t));
204 array_push(out_verts, intersect);
205 array_push(out_verts, p2);
206 }
207 }
208 }
209
210 Polygon res;
211 res.verts = out_verts.data;
212 res.count = (int)out_verts.length;
213 return res;
214}
215
216Polygon CreateLargeQuad(Plane plane) {
217 Vector3 n = plane.normal;
218 Vector3 up = (fabsf(n.y) < 0.999f) ? (Vector3){ 0, 1, 0 } : (Vector3){ 1, 0, 0 };
219 Vector3 right = Vector3Normalize(Vector3CrossProduct(up, n));
220 up = Vector3CrossProduct(n, right);
221
222 Vector3 center = Vector3Scale(n, plane.dist);
223 float size = 10000.0f;
224
225 Polygon poly;
226 poly.verts = ALLOC(Vector3, 4);
227 poly.count = 4;
228 poly.verts[0] = Vector3Add(center, Vector3Add(Vector3Scale(right, size), Vector3Scale(up, size)));
229 poly.verts[1] = Vector3Add(center, Vector3Add(Vector3Scale(right, -size), Vector3Scale(up, size)));
230 poly.verts[2] = Vector3Add(center, Vector3Add(Vector3Scale(right, -size), Vector3Scale(up, -size)));
231 poly.verts[3] = Vector3Add(center, Vector3Add(Vector3Scale(right, size), Vector3Scale(up, -size)));
232
233 return poly;
234}
235
236Vector2 GetUV(Vector3 p, MapPlane *mp, Plane plane) {
237 Vector3 n = plane.normal;
238 Vector3 up = (fabsf(n.y) < 0.999f) ? (Vector3){ 0, 1, 0 } : (Vector3){ 1, 0, 0 };
239 Vector3 right = Vector3Normalize(Vector3CrossProduct(up, n));
240 up = Vector3CrossProduct(n, right);
241
242 float u = Vector3DotProduct(p, right) * (1.0f / (mp->scale[0] ? mp->scale[0] : 1.0f)) + mp->shift[0];
243 float v = Vector3DotProduct(p, up) * (1.0f / (mp->scale[1] ? mp->scale[1] : 1.0f)) + mp->shift[1];
244
245 return (Vector2){ u / 64.0f, v / 64.0f };
246}