Skip to content

Commit a887de1

Browse files
committed
Quake map solids: adding ray and line checks
1 parent c9f4143 commit a887de1

File tree

1 file changed

+99
-2
lines changed

1 file changed

+99
-2
lines changed

src/framework/utils/quakemap.zig

+99-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const debug = @import("../debug.zig");
33
const math = @import("../math.zig");
44
const plane = @import("../spatial/plane.zig");
55
const boundingbox = @import("../spatial/boundingbox.zig");
6+
const rays = @import("../spatial/rays.zig");
67
const mesh = @import("../graphics/mesh.zig");
78
const colors = @import("../colors.zig");
89
const graphics = @import("../platform/graphics.zig");
@@ -17,6 +18,7 @@ const Vec2 = math.Vec2;
1718
const Plane = plane.Plane;
1819
const Mesh = mesh.Mesh;
1920
const BoundingBox = boundingbox.BoundingBox;
21+
const Ray = rays.Ray;
2022

2123
// From https://github.com/fabioarnold/3d-game/blob/master/src/QuakeMap.zig
2224
// This is so cool!
@@ -295,7 +297,7 @@ pub const Solid = struct {
295297
var worldhit: ?QuakeMapHit = null;
296298

297299
const size = bounds.max.sub(bounds.min).scale(0.5);
298-
const planes = getExpandedPlanes(self, size);
300+
const planes = self.getExpandedPlanes(size);
299301

300302
const point = bounds.center;
301303
const next = point.add(velocity);
@@ -306,8 +308,11 @@ pub const Solid = struct {
306308
for (0..planes.len) |idx| {
307309
const ep = planes[idx];
308310
if (ep) |p| {
311+
// must start in front but end in back
312+
if (p.testPoint(point) == .BACK)
313+
continue;
309314
if (p.testPoint(next) == .FRONT)
310-
return null;
315+
continue;
311316

312317
const hit = p.intersectLine(point, next);
313318
if (hit) |h| {
@@ -330,8 +335,100 @@ pub const Solid = struct {
330335
.loc = h,
331336
.plane = p,
332337
};
338+
339+
// convex, so should only have one collision
340+
break;
341+
}
342+
}
343+
}
344+
}
345+
346+
return worldhit;
347+
}
348+
349+
pub fn checkLineCollision(self: *const Solid, start: Vec3, end: Vec3) ?QuakeMapHit {
350+
var worldhit: ?QuakeMapHit = null;
351+
352+
if (self.faces.items.len == 0)
353+
return null;
354+
355+
for (0..self.faces.items.len) |idx| {
356+
const p = self.faces.items[idx].plane;
357+
// must start in front and end in back
358+
if (p.testPoint(start) == .BACK)
359+
continue;
360+
if (p.testPoint(end) == .FRONT)
361+
continue;
362+
363+
const hit = p.intersectLine(start, end);
364+
365+
if (hit) |h| {
366+
var didhit = true;
367+
for (0..self.faces.items.len) |h_idx| {
368+
if (idx == h_idx)
369+
continue;
370+
371+
// check that this hit point is behind the other clip planes
372+
const pp = self.faces.items[h_idx].plane;
373+
if (pp.testPoint(h) == .FRONT) {
374+
didhit = false;
375+
break;
333376
}
334377
}
378+
379+
if (didhit) {
380+
worldhit = .{
381+
.loc = h,
382+
.plane = p,
383+
};
384+
385+
// convex, so should only have one collision
386+
break;
387+
}
388+
}
389+
}
390+
391+
return worldhit;
392+
}
393+
394+
pub fn checkRayCollision(self: *const Solid, ray: Ray) ?QuakeMapHit {
395+
var worldhit: ?QuakeMapHit = null;
396+
397+
if (self.faces.items.len == 0)
398+
return null;
399+
400+
for (0..self.faces.items.len) |idx| {
401+
const p = self.faces.items[idx].plane;
402+
403+
// must start in front!
404+
if (p.testPoint(ray.pos) == .BACK)
405+
continue;
406+
407+
const hit = ray.intersectPlane(p, true);
408+
409+
if (hit) |h| {
410+
var didhit = true;
411+
for (0..self.faces.items.len) |h_idx| {
412+
if (idx == h_idx)
413+
continue;
414+
415+
// check that this hit point is behind the other clip planes
416+
const pp = self.faces.items[h_idx].plane;
417+
if (pp.testPoint(h.hit_pos) == .FRONT) {
418+
didhit = false;
419+
break;
420+
}
421+
}
422+
423+
if (didhit) {
424+
worldhit = .{
425+
.loc = h.hit_pos,
426+
.plane = p,
427+
};
428+
429+
// convex, so should only have one collision
430+
break;
431+
}
335432
}
336433
}
337434

0 commit comments

Comments
 (0)