aboutsummaryrefslogtreecommitdiff
path: root/src/model.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/model.zig')
-rw-r--r--src/model.zig90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/model.zig b/src/model.zig
new file mode 100644
index 0000000..274176d
--- /dev/null
+++ b/src/model.zig
@@ -0,0 +1,90 @@
+// 3D model
+// Copyright (C) 2002 David Rosen
+// Copyright (C) 2023 Nguyễn Gia Phong
+//
+// This file is part of Black Shades.
+//
+// Black Shades is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Black Shades is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Black Shades. If not, see <https://www.gnu.org/licenses/>.
+
+const XYZ = geom.XYZ;
+const degToRad = std.math.degreesToRadians;
+const floatMax = std.math.floatMax;
+const geom = @import("geom.zig");
+const rotate2d = geom.rotate2d;
+const segCrossSphere = geom.segCrossSphere;
+const segCrossTrigon = geom.segCrossTrigon;
+const sqr = geom.sqr;
+const std = @import("std");
+
+const max_trigons = 400;
+
+const Trigon = extern struct {
+ vertices: [3]u32,
+ r: f32,
+ g: f32,
+ b: f32,
+};
+
+pub const Model = extern struct {
+ vertices: [max_trigons * 3]XYZ,
+ vertices_len: u32,
+ normals: [max_trigons]XYZ,
+ trigons: [max_trigons]Trigon,
+ trigons_len: u32,
+ center: XYZ,
+ radius: f32,
+ vert_array: [max_trigons * 27]f32,
+};
+
+pub export fn segCrossModel(start: XYZ, end: XYZ, m: *const Model,
+ intersection: *XYZ) c_int {
+ if (!segCrossSphere(start, end, m.center, m.radius))
+ return -1;
+ const p: @Vector(3, f32) = @bitCast(start);
+ var result: c_int = -1;
+ var shortest = floatMax(f32);
+ for (0..m.trigons_len) |j| {
+ var v: @Vector(3, f32) = undefined;
+ if (!segCrossTrigon(start, end,
+ &m.vertices[m.trigons[j].vertices[0]],
+ &m.vertices[m.trigons[j].vertices[1]],
+ &m.vertices[m.trigons[j].vertices[2]],
+ &m.normals[j], @ptrCast(&v)))
+ continue;
+ const distance = @reduce(.Add, sqr(v - p));
+ if (distance < shortest or result == -1) {
+ shortest = distance;
+ result = @intCast(j);
+ intersection.* = @bitCast(v);
+ }
+ }
+ return result;
+}
+
+pub export fn segCrossModelTrans(start: XYZ, end: XYZ, m: *const Model,
+ move: XYZ, rot: f32,
+ intersection: *XYZ) c_int {
+ const t: @Vector(3, f32) = @bitCast(move);
+ var p = @as(@Vector(3, f32), @bitCast(start)) - t;
+ rotate2d(&p[2], &p[0], degToRad(f32, -rot));
+ var q = @as(@Vector(3, f32), @bitCast(end)) - t;
+ rotate2d(&q[2], &q[0], degToRad(f32, -rot));
+
+ defer {
+ rotate2d(&intersection.z, &intersection.x, degToRad(f32, rot));
+ intersection.* = @bitCast(@as(@Vector(3, f32),
+ @bitCast(intersection.*)) + t);
+ }
+ return segCrossModel(@bitCast(p), @bitCast(q), m, intersection);
+}