@@ -25,6 +25,11 @@ pub const ErrorInfo = struct {
25
25
line_number : usize ,
26
26
};
27
27
28
+ pub const QuakeMapHit = struct {
29
+ loc : Vec3 ,
30
+ plane : Plane ,
31
+ };
32
+
28
33
pub const Property = struct {
29
34
key : []const u8 ,
30
35
value : []const u8 ,
@@ -97,6 +102,7 @@ pub const Entity = struct {
97
102
98
103
pub const Solid = struct {
99
104
faces : std .ArrayList (Face ),
105
+ bounds : BoundingBox = undefined ,
100
106
101
107
fn init (allocator : Allocator ) Solid {
102
108
return .{ .faces = std .ArrayList (Face ).init (allocator ) };
@@ -110,6 +116,9 @@ pub const Solid = struct {
110
116
defer vertices .deinit (allocator );
111
117
defer clipped .deinit (allocator );
112
118
119
+ // build a bounding box along the way too
120
+ var solid_bounds : BoundingBox = undefined ;
121
+
113
122
for (self .faces .items , 0.. ) | * face , i | {
114
123
const quad = makeQuadWithRadius (face .plane , 1000000.0 );
115
124
vertices .clearRetainingCapacity ();
@@ -125,7 +134,20 @@ pub const Solid = struct {
125
134
}
126
135
127
136
face .vertices = try allocator .dupe (Vec3 , vertices .items );
137
+
138
+ // create a bounding box out of these vertices
139
+ const face_bounds : BoundingBox = BoundingBox .initFromPositions (face .vertices );
140
+ if (i == 0 ) {
141
+ solid_bounds = face_bounds ;
142
+ continue ;
143
+ }
144
+
145
+ // expand our solid's bounding box by the new face bounds
146
+ solid_bounds .min = Vec3 .min (solid_bounds .min , face_bounds .min );
147
+ solid_bounds .max = Vec3 .max (solid_bounds .max , face_bounds .max );
128
148
}
149
+
150
+ self .bounds = solid_bounds ;
129
151
}
130
152
131
153
fn clip (allocator : Allocator , vertices : std .ArrayListUnmanaged (Vec3 ), clip_plane : Plane , clipped : * std .ArrayListUnmanaged (Vec3 )) ! void {
@@ -193,44 +215,128 @@ pub const Solid = struct {
193
215
return true ;
194
216
}
195
217
196
- pub fn checkBoundingBoxCollision (self : * const Solid , bounds : BoundingBox ) bool {
197
- const x_size = (bounds .max .x - bounds .min .x ) * 0.5 ;
198
- const y_size = (bounds .max .y - bounds .min .y ) * 0.5 ;
199
- const z_size = (bounds .max .z - bounds .min .z ) * 0.5 ;
218
+ // Get our planes expanded by the Minkowski sum of the bounding box
219
+ pub fn getExpandedPlanes (self : * const Solid , size : math.Vec3 ) [24 ]? Plane {
220
+ var expanded_planes = [_ ]? Plane {null } ** 24 ;
221
+ var plane_count : usize = 0 ;
222
+
223
+ if (self .faces .items .len == 0 )
224
+ return expanded_planes ;
200
225
201
- const point = bounds .center ;
202
226
for (self .faces .items ) | * face | {
203
227
var expand_dist : f32 = 0 ;
204
228
205
229
// x_axis
206
- const x_d = face .plane .normal .dot (Vec3 .x_axis );
207
- if (x_d > 0 ) expand_dist += - x_d * x_size ;
230
+ const x_d = face .plane .normal .dot (math . Vec3 .x_axis );
231
+ if (x_d > 0 ) expand_dist += - x_d * size . x ;
208
232
209
- const x_d_n = face .plane .normal .dot (Vec3 .x_axis .scale (-1 ));
210
- if (x_d_n > 0 ) expand_dist += - x_d_n * x_size ;
233
+ const x_d_n = face .plane .normal .dot (math . Vec3 .x_axis .scale (-1 ));
234
+ if (x_d_n > 0 ) expand_dist += - x_d_n * size . x ;
211
235
212
236
// y_axis
213
- const y_d = face .plane .normal .dot (Vec3 .y_axis );
214
- if (y_d > 0 ) expand_dist += - y_d * y_size ;
237
+ const y_d = face .plane .normal .dot (math . Vec3 .y_axis );
238
+ if (y_d > 0 ) expand_dist += - y_d * size . y ;
215
239
216
- const y_d_n = face .plane .normal .dot (Vec3 .y_axis .scale (-1 ));
217
- if (y_d_n > 0 ) expand_dist += - y_d_n * y_size ;
240
+ const y_d_n = face .plane .normal .dot (math . Vec3 .y_axis .scale (-1 ));
241
+ if (y_d_n > 0 ) expand_dist += - y_d_n * size . y ;
218
242
219
243
// z_axis
220
- const z_d = face .plane .normal .dot (Vec3 .z_axis );
221
- if (z_d > 0 ) expand_dist += - z_d * z_size ;
244
+ const z_d = face .plane .normal .dot (math . Vec3 .z_axis );
245
+ if (z_d > 0 ) expand_dist += - z_d * size . z ;
222
246
223
- const z_d_n = face .plane .normal .dot (Vec3 .z_axis .scale (-1 ));
224
- if (z_d_n > 0 ) expand_dist += - z_d_n * z_size ;
247
+ const z_d_n = face .plane .normal .dot (math . Vec3 .z_axis .scale (-1 ));
248
+ if (z_d_n > 0 ) expand_dist += - z_d_n * size . z ;
225
249
226
250
var expandedface = face .plane ;
227
251
expandedface .d += expand_dist ;
228
252
229
- if ( expandedface . testPoint ( point ) == .FRONT )
230
- return false ;
253
+ expanded_planes [ plane_count ] = expandedface ;
254
+ plane_count += 1 ;
231
255
}
256
+
257
+ // Make the Minkowski sum of both bounding boxes
258
+ var solid_bounds = self .bounds ;
259
+ solid_bounds .min .x -= size .x ;
260
+ solid_bounds .min .y -= size .y ;
261
+ solid_bounds .min .z -= size .z ;
262
+
263
+ solid_bounds .max .x += size .x ;
264
+ solid_bounds .max .y += size .y ;
265
+ solid_bounds .max .z += size .z ;
266
+
267
+ // Can use the sum as our bevel planes
268
+ const bevel_planes = solid_bounds .getPlanes ();
269
+ for (bevel_planes ) | p | {
270
+ expanded_planes [plane_count ] = p ;
271
+ plane_count += 1 ;
272
+ }
273
+
274
+ return expanded_planes ;
275
+ }
276
+
277
+ pub fn checkBoundingBoxCollision (self : * const Solid , bounds : BoundingBox ) bool {
278
+ const x_size = (bounds .max .x - bounds .min .x ) * 0.5 ;
279
+ const y_size = (bounds .max .y - bounds .min .y ) * 0.5 ;
280
+ const z_size = (bounds .max .z - bounds .min .z ) * 0.5 ;
281
+ const point = bounds .center ;
282
+
283
+ const expanded_planes = self .getExpandedPlanes (Vec3 .new (x_size , y_size , z_size ));
284
+ for (expanded_planes ) | ep | {
285
+ if (ep ) | p | {
286
+ if (p .testPoint (point ) == .FRONT )
287
+ return false ;
288
+ }
289
+ }
290
+
232
291
return true ;
233
292
}
293
+
294
+ pub fn checkBoundingBoxCollisionWithVelocity (self : * const Solid , bounds : BoundingBox , velocity : Vec3 ) ? QuakeMapHit {
295
+ var worldhit : ? QuakeMapHit = null ;
296
+
297
+ const size = bounds .max .sub (bounds .min ).scale (0.5 );
298
+ const planes = getExpandedPlanes (self , size );
299
+
300
+ const point = bounds .center ;
301
+ const next = point .add (velocity );
302
+
303
+ if (planes .len == 0 )
304
+ return null ;
305
+
306
+ for (0.. planes .len ) | idx | {
307
+ const ep = planes [idx ];
308
+ if (ep ) | p | {
309
+ if (p .testPoint (next ) == .FRONT )
310
+ return null ;
311
+
312
+ const hit = p .intersectLine (point , next );
313
+ if (hit ) | h | {
314
+ var didhit = true ;
315
+ for (0.. planes .len ) | h_idx | {
316
+ if (idx == h_idx )
317
+ continue ;
318
+
319
+ // check that this hit point is behind the other clip planes
320
+ if (planes [h_idx ]) | pp | {
321
+ if (pp .testPoint (h ) == .FRONT ) {
322
+ didhit = false ;
323
+ break ;
324
+ }
325
+ }
326
+ }
327
+
328
+ if (didhit ) {
329
+ worldhit = .{
330
+ .loc = h ,
331
+ .plane = p ,
332
+ };
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ return worldhit ;
339
+ }
234
340
};
235
341
236
342
pub const QuakeMaterial = struct {
0 commit comments