Trying to improve collisions and failing
This commit is contained in:
14
src/Game.zig
14
src/Game.zig
@@ -1,6 +1,7 @@
|
||||
const Game = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("const.zig");
|
||||
const glfw = @import("zglfw");
|
||||
const math = @import("math.zig");
|
||||
const shaders = @import("shaders.zig");
|
||||
@@ -23,6 +24,7 @@ const Textures = @import("assets/Textures.zig");
|
||||
const Vector2 = math.Vector2;
|
||||
const Vector2x8 = math.Vector2x8;
|
||||
const Vector3 = math.Vector3;
|
||||
const Vector3Int = math.Vector3Int;
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
engine: *Engine,
|
||||
@@ -591,7 +593,10 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
}
|
||||
}
|
||||
|
||||
const player_position = Vector3.init(0, 0, worldgen.heightF(world_seed, .zero) + 0.5);
|
||||
const player_position_vx = Vector3Int.init(0, 0, worldgen.heightI(world_seed, .zero) + 1);
|
||||
const player_position_sv = player_position_vx
|
||||
.mulScalar(c.sv_per_vx)
|
||||
.add(.init(c.sv_per_vx / 2, c.sv_per_vx / 2, 0));
|
||||
|
||||
var chunk_it = chunks.iterator();
|
||||
while (chunk_it.next()) |entry| {
|
||||
@@ -655,7 +660,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
.chunks = chunks,
|
||||
.skybox = skybox,
|
||||
|
||||
.player = .init(player_position, 0, 0),
|
||||
.player = .init(player_position_sv, 0, 0),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -757,7 +762,10 @@ fn render(self: *Game) !void {
|
||||
@floatFromInt(extent.height),
|
||||
);
|
||||
|
||||
const camera_position = self.player.position.add(.init(0, 0, Player.camera_height));
|
||||
const camera_position = self.player.position_sv
|
||||
.asVector3()
|
||||
.divScalar(c.sv_per_vx)
|
||||
.add(.init(0, 0, Player.camera_height_vx));
|
||||
const camera_rotation = Quaternion.mulQuaternion(
|
||||
.initRotationXY(self.player.yaw_rad),
|
||||
.initRotationYZ(self.player.pitch_rad),
|
||||
|
||||
518
src/Player.zig
518
src/Player.zig
@@ -1,13 +1,17 @@
|
||||
const Player = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("const.zig");
|
||||
const glfw = @import("zglfw");
|
||||
const math = @import("math.zig");
|
||||
|
||||
const Blocks = @import("assets/Blocks.zig");
|
||||
const Chunk = @import("assets/Chunk.zig");
|
||||
const Iterator2 = math.Iterator2;
|
||||
const Vector2 = math.Vector2;
|
||||
const Vector3 = math.Vector3;
|
||||
const Vector2Int = math.Vector2Int;
|
||||
const Vector3Int = math.Vector3Int;
|
||||
|
||||
const AxisState = enum {
|
||||
none,
|
||||
@@ -16,13 +20,29 @@ const AxisState = enum {
|
||||
both_positive,
|
||||
both_negative,
|
||||
|
||||
pub fn getComponent(self: AxisState) f32 {
|
||||
pub fn getComponentFloat(self: AxisState) f32 {
|
||||
return switch (self) {
|
||||
.none => 0,
|
||||
.positive, .both_positive => 1,
|
||||
.negative, .both_negative => -1,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getComponentInt(self: AxisState) i32 {
|
||||
return switch (self) {
|
||||
.none => 0,
|
||||
.positive, .both_positive => 1,
|
||||
.negative, .both_negative => -1,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getComponentIntFrac(self: AxisState) i32 {
|
||||
return switch (self) {
|
||||
.none => 0,
|
||||
.positive, .both_positive => std.math.maxInt(i32),
|
||||
.negative, .both_negative => -std.math.maxInt(i32),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const ButtonState = struct {
|
||||
@@ -80,8 +100,16 @@ const Axis = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getComponent(self: Axis) f32 {
|
||||
return self.state.getComponent();
|
||||
pub fn getComponentFloat(self: Axis) f32 {
|
||||
return self.state.getComponentFloat();
|
||||
}
|
||||
|
||||
pub fn getComponentInt(self: Axis) i32 {
|
||||
return self.state.getComponentInt();
|
||||
}
|
||||
|
||||
pub fn getComponentIntFrac(self: Axis) i32 {
|
||||
return self.state.getComponentIntFrac();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,16 +156,16 @@ const Button = struct {
|
||||
|
||||
const MovementState = union(enum) {
|
||||
ground: struct {
|
||||
horizontal_velocity: Vector2,
|
||||
horizontal_velocity_sv: Vector2Int,
|
||||
},
|
||||
air: struct {
|
||||
horizontal_velocity: Vector2,
|
||||
vertical_velocity: f32,
|
||||
horizontal_velocity_sv: Vector2Int,
|
||||
vertical_velocity_sv: i32,
|
||||
},
|
||||
flight: void,
|
||||
};
|
||||
|
||||
position: Vector3,
|
||||
position_sv: Vector3Int,
|
||||
pitch_rad: f32,
|
||||
yaw_rad: f32,
|
||||
|
||||
@@ -151,31 +179,30 @@ vertical_fov_deg: f32 = 80,
|
||||
|
||||
movement_state: MovementState,
|
||||
|
||||
pub const camera_height = 1.62;
|
||||
pub const camera_height_vx = 1.62;
|
||||
|
||||
pub const horizontal_speed = 11.0;
|
||||
pub const vertical_speed = 7.49;
|
||||
pub const horizontal_speed_sv = c.sv(11.0);
|
||||
pub const vertical_speed_sv = c.sv(7.49);
|
||||
|
||||
pub const min_pitch_rad = -0.5 * std.math.pi;
|
||||
pub const max_pitch_rad = 0.5 * std.math.pi;
|
||||
|
||||
pub const half_width = 0.4;
|
||||
pub const height = 1.8;
|
||||
pub const speed = 5.612;
|
||||
pub const step_up = 0.53125;
|
||||
pub const step_down = 0.53125;
|
||||
pub const jump_velocity = 6.1237245;
|
||||
pub const gravity = 15;
|
||||
pub const vertical_velocity_cap = 30;
|
||||
pub const ground_acceleration = 56.12;
|
||||
pub const air_acceleration = 56.12;
|
||||
pub const air_speed_limit = 0.5612;
|
||||
pub const collision_half_width_sv = c.sv(0.4);
|
||||
pub const collision_height_sv = c.sv(1.8);
|
||||
|
||||
const distance_from_surface = 0.0009765625;
|
||||
pub const speed_sv = c.sv(5.612);
|
||||
pub const step_up_sv = c.sv(0.53125);
|
||||
pub const step_down_sv = c.sv(0.53125);
|
||||
pub const jump_velocity_sv = c.sv(6.1237245);
|
||||
pub const gravity_sv = c.sv(15);
|
||||
pub const vertical_velocity_cap_sv = c.sv(30);
|
||||
pub const ground_acceleration_sv = c.sv(56.12);
|
||||
pub const air_acceleration_sv = c.sv(56.12);
|
||||
pub const air_speed_limit_sv = c.sv(0.5612);
|
||||
|
||||
pub fn init(position: Vector3, pitch_rad: f32, yaw_rad: f32) Player {
|
||||
pub fn init(position_sv: Vector3Int, pitch_rad: f32, yaw_rad: f32) Player {
|
||||
return .{
|
||||
.position = position,
|
||||
.position_sv = position_sv,
|
||||
.pitch_rad = pitch_rad,
|
||||
.yaw_rad = yaw_rad,
|
||||
.movement_state = .flight,
|
||||
@@ -204,17 +231,17 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
|
||||
|
||||
// --- GATHER INPUTS -------------------------------------------------------
|
||||
|
||||
const horizontal_input_vector = blk: {
|
||||
const horizontal_input_vector_frac = blk: {
|
||||
var ret = Vector2
|
||||
.init(self.x_input.getComponent(), self.y_input.getComponent())
|
||||
.init(self.x_input.getComponentFloat(), self.y_input.getComponentFloat())
|
||||
.rotate(self.yaw_rad);
|
||||
const len_squared = ret.lenSquared();
|
||||
if (len_squared > 1) {
|
||||
ret = ret.divScalar(@sqrt(len_squared));
|
||||
}
|
||||
break :blk ret;
|
||||
break :blk ret.asVector2IntFrac();
|
||||
};
|
||||
const vertical_input_vector = self.z_input.getComponent();
|
||||
const vertical_input_vector_frac = self.z_input.getComponentIntFrac();
|
||||
|
||||
// --- STATE TRANSITIONS ---------------------------------------------------
|
||||
|
||||
@@ -223,8 +250,8 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
|
||||
if (self.jump_input.isPressed()) {
|
||||
self.movement_state = .{
|
||||
.air = .{
|
||||
.horizontal_velocity = ground.horizontal_velocity,
|
||||
.vertical_velocity = jump_velocity,
|
||||
.horizontal_velocity_sv = ground.horizontal_velocity_sv,
|
||||
.vertical_velocity_sv = jump_velocity_sv,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -238,73 +265,88 @@ pub fn update(self: *Player, dt: f32, chunks: *const std.AutoHashMapUnmanaged([3
|
||||
.ground => {},
|
||||
.air => {},
|
||||
.flight => {
|
||||
const horizontal_velocity = horizontal_input_vector.mulScalar(horizontal_speed);
|
||||
const vertical_velocity = vertical_input_vector * vertical_speed;
|
||||
const horizontal_velocity_sv = horizontal_input_vector_frac.mulScalarFrac(horizontal_speed_sv);
|
||||
const vertical_velocity_sv = math.mulFrac(vertical_input_vector_frac, vertical_speed_sv);
|
||||
|
||||
var horizontal_displacement = horizontal_velocity.mulScalar(dt);
|
||||
var vertical_displacement = vertical_velocity * dt;
|
||||
var horizontal_displacement_sv = horizontal_velocity_sv.mulScalarFloat(dt);
|
||||
var vertical_displacement_sv = math.mulIntFloat(vertical_velocity_sv, dt);
|
||||
|
||||
if (vertical_displacement > 0.0) {
|
||||
if (sweepCastUp(self.position, vertical_displacement, chunks)) |hit| {
|
||||
vertical_displacement = hit.projected_distance - distance_from_surface;
|
||||
var position_sv = self.position_sv;
|
||||
|
||||
if (vertical_displacement_sv > 0) {
|
||||
if (sweepCastUp(position_sv, vertical_displacement_sv, chunks)) |hit| {
|
||||
vertical_displacement_sv -= hit.projected_distance_sv;
|
||||
}
|
||||
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 2) : (i += 1) {
|
||||
if (sweepCastHorizontal(self.position, horizontal_displacement, chunks)) |hit| {
|
||||
horizontal_displacement = .add(
|
||||
horizontal_displacement,
|
||||
hit.normal
|
||||
.asVector2()
|
||||
.mulScalar(hit.projected_distance + distance_from_surface),
|
||||
if (sweepCastHorizontal(position_sv, horizontal_displacement_sv, chunks)) |hit| {
|
||||
const adjustment = hit.normal_frac
|
||||
.asVector2Int()
|
||||
.mulScalarFrac(hit.projected_distance_sv);
|
||||
std.debug.print("i={} | n={} | d={} | adj={} | disp={}->", .{
|
||||
i,
|
||||
hit.normal_frac.vector,
|
||||
hit.projected_distance_sv,
|
||||
adjustment.vector,
|
||||
horizontal_displacement_sv.vector,
|
||||
});
|
||||
horizontal_displacement_sv = .add(
|
||||
horizontal_displacement_sv,
|
||||
adjustment,
|
||||
);
|
||||
std.debug.print("{}\n", .{horizontal_displacement_sv.vector});
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
position_sv = .add(position_sv, horizontal_displacement_sv.asVector3Int(0));
|
||||
|
||||
if (vertical_displacement < 0.0) {
|
||||
if (sweepCastDown(self.position, -vertical_displacement, chunks)) |hit| {
|
||||
vertical_displacement = -(hit.projected_distance - distance_from_surface);
|
||||
if (vertical_displacement_sv < 0.0) {
|
||||
if (sweepCastDown(position_sv, -vertical_displacement_sv, chunks)) |hit| {
|
||||
vertical_displacement_sv += hit.projected_distance_sv;
|
||||
}
|
||||
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
|
||||
}
|
||||
|
||||
const displacement = horizontal_displacement.asVector3(vertical_displacement);
|
||||
self.position = .add(self.position, displacement);
|
||||
self.position_sv = position_sv;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const SweepHit = struct {
|
||||
normal: Vector3,
|
||||
projected_distance: f32,
|
||||
normal_frac: Vector3Int,
|
||||
projected_distance_sv: i32,
|
||||
};
|
||||
|
||||
fn sweepCastDown(origin: Vector3, distance: f32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
||||
const min_origin = origin.add(.init(-half_width, -half_width, 0.0));
|
||||
const max_origin = origin.add(.init(half_width, half_width, height));
|
||||
fn sweepCastDown(origin_sv: Vector3Int, distance_sv: i32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
||||
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
||||
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
||||
|
||||
const min_x = blockCoord(.border_up, min_origin.getX());
|
||||
const min_y = blockCoord(.border_up, min_origin.getY());
|
||||
const max_x = blockCoord(.border_down, max_origin.getX());
|
||||
const max_y = blockCoord(.border_down, max_origin.getY());
|
||||
const min_x_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getX());
|
||||
const min_y_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getY());
|
||||
const max_x_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getX());
|
||||
const max_y_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getY());
|
||||
|
||||
const start_z = blockCoord(.next_down_with_border, min_origin.getZ());
|
||||
const end_z = blockCoord(.border_down, min_origin.getZ() - distance);
|
||||
const start_z_vx = voxelFromSubvoxel(.next_down, min_origin_sv.getZ());
|
||||
const end_z_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getZ() - distance_sv);
|
||||
|
||||
var z: i32 = start_z;
|
||||
while (z >= end_z) : (z -= 1) {
|
||||
const fz = @as(f32, @floatFromInt(z)) + 1.0;
|
||||
var z_vx: i32 = start_z_vx;
|
||||
while (z_vx >= end_z_vx) : (z_vx -= 1) {
|
||||
const z_sv = (z_vx + 1) * c.sv_per_vx;
|
||||
var it = Iterator2(i32).init(.{
|
||||
.min = .{ min_x, min_y },
|
||||
.max = .{ max_x, max_y },
|
||||
.min = .{ min_x_vx, min_y_vx },
|
||||
.max = .{ max_x_vx, max_y_vx },
|
||||
});
|
||||
while (it.next()) |xy| {
|
||||
const x, const y = xy;
|
||||
if (!isSolid(chunks, x, y, z)) continue;
|
||||
while (it.next()) |xy_vx| {
|
||||
const x_vx, const y_vx = xy_vx;
|
||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
||||
|
||||
return .{
|
||||
.projected_distance = distance - (min_origin.getZ() - fz),
|
||||
.normal = .unit_z,
|
||||
.projected_distance_sv = distance_sv - (min_origin_sv.getZ() - z_sv),
|
||||
.normal_frac = .unit_z_frac,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -312,32 +354,32 @@ fn sweepCastDown(origin: Vector3, distance: f32, chunks: *const std.AutoHashMapU
|
||||
return null;
|
||||
}
|
||||
|
||||
fn sweepCastUp(origin: Vector3, distance: f32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
||||
const min_origin = origin.add(.init(-half_width, -half_width, 0.0));
|
||||
const max_origin = origin.add(.init(half_width, half_width, height));
|
||||
fn sweepCastUp(origin_sv: Vector3Int, distance_sv: i32, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
||||
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
||||
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
||||
|
||||
const min_x = blockCoord(.border_up, min_origin.getX());
|
||||
const min_y = blockCoord(.border_up, min_origin.getY());
|
||||
const max_x = blockCoord(.border_down, max_origin.getX());
|
||||
const max_y = blockCoord(.border_down, max_origin.getY());
|
||||
const min_x_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getX());
|
||||
const min_y_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getY());
|
||||
const max_x_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getX());
|
||||
const max_y_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getY());
|
||||
|
||||
const start_z = blockCoord(.next_up_with_border, max_origin.getZ());
|
||||
const end_z = blockCoord(.border_up, max_origin.getZ() + distance);
|
||||
const start_z_vx = voxelFromSubvoxel(.next_up, max_origin_sv.getZ());
|
||||
const end_z_vx = voxelFromSubvoxel(.border_up, max_origin_sv.getZ() + distance_sv);
|
||||
|
||||
var z: i32 = start_z;
|
||||
while (z <= end_z) : (z += 1) {
|
||||
const fz = @as(f32, @floatFromInt(z));
|
||||
var z_vx: i32 = start_z_vx;
|
||||
while (z_vx <= end_z_vx) : (z_vx += 1) {
|
||||
const z_sv = z_vx * c.sv_per_vx;
|
||||
var it = Iterator2(i32).init(.{
|
||||
.min = .{ min_x, min_y },
|
||||
.max = .{ max_x, max_y },
|
||||
.min = .{ min_x_vx, min_y_vx },
|
||||
.max = .{ max_x_vx, max_y_vx },
|
||||
});
|
||||
while (it.next()) |xy| {
|
||||
const x, const y = xy;
|
||||
if (!isSolid(chunks, x, y, z)) continue;
|
||||
while (it.next()) |xy_vx| {
|
||||
const x_vx, const y_vx = xy_vx;
|
||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
||||
|
||||
return .{
|
||||
.projected_distance = distance - (fz - max_origin.getZ()),
|
||||
.normal = .negate(.unit_z),
|
||||
.projected_distance_sv = distance_sv - (z_sv - max_origin_sv.getZ()),
|
||||
.normal_frac = .unit_nz_frac,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -345,176 +387,178 @@ fn sweepCastUp(origin: Vector3, distance: f32, chunks: *const std.AutoHashMapUnm
|
||||
return null;
|
||||
}
|
||||
|
||||
fn sweepCastHorizontal(origin: Vector3, ray: Vector2, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
||||
const min_origin = origin.add(.init(-half_width, -half_width, 0));
|
||||
const max_origin = origin.add(.init(half_width, half_width, height));
|
||||
fn sweepCastHorizontal(origin_sv: Vector3Int, ray_sv: Vector2Int, chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk)) ?SweepHit {
|
||||
const min_origin_sv = origin_sv.add(.init(-collision_half_width_sv, -collision_half_width_sv, 0));
|
||||
const max_origin_sv = origin_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
|
||||
|
||||
const min_z = blockCoord(.border_up, min_origin.getZ());
|
||||
const max_z = blockCoord(.border_down, max_origin.getZ());
|
||||
const min_z_vx = voxelFromSubvoxel(.border_up, min_origin_sv.getZ());
|
||||
const max_z_vx = voxelFromSubvoxel(.border_down, max_origin_sv.getZ());
|
||||
|
||||
var closest_hit: ?SweepHit = null;
|
||||
var closest_hit_distance = std.math.inf(f32);
|
||||
var hit: ?SweepHit = null;
|
||||
var hit_distance_squared = std.math.inf(f32);
|
||||
|
||||
const dydx = ray.getY() / ray.getX();
|
||||
const dxdy = ray.getX() / ray.getY();
|
||||
const fdydx: f32 = @as(f32, @floatFromInt(ray_sv.getY())) / @as(f32, @floatFromInt(ray_sv.getX()));
|
||||
const fdxdy: f32 = @as(f32, @floatFromInt(ray_sv.getX())) / @as(f32, @floatFromInt(ray_sv.getY()));
|
||||
|
||||
// Positive X
|
||||
if (ray.getX() > 0.0) {
|
||||
const x0 = max_origin.getX();
|
||||
const y0 = min_origin.getY();
|
||||
const y1 = max_origin.getY();
|
||||
if (ray_sv.getX() > 0) {
|
||||
const x0_sv = max_origin_sv.getX();
|
||||
const y0_sv = min_origin_sv.getY();
|
||||
const y1_sv = max_origin_sv.getY();
|
||||
|
||||
const start_x = blockCoord(.next_up_with_border, x0);
|
||||
const end_x = blockCoord(.border_up, x0 + ray.getX());
|
||||
const start_x_vx = voxelFromSubvoxel(.next_up, x0_sv);
|
||||
const end_x_vx = voxelFromSubvoxel(.border_down, x0_sv + ray_sv.getX());
|
||||
|
||||
var x: i32 = start_x;
|
||||
px: while (x <= end_x) : (x += 1) {
|
||||
const fx = @as(f32, @floatFromInt(x));
|
||||
const min_y = blockCoord(.border_up, (fx - x0) * dydx + y0);
|
||||
const max_y = blockCoord(.border_down, (fx - x0) * dydx + y1);
|
||||
var x_vx: i32 = start_x_vx;
|
||||
px: while (x_vx <= end_x_vx) : (x_vx += 1) {
|
||||
const x_sv = x_vx * c.sv_per_vx;
|
||||
const min_y_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
|
||||
const max_y_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
|
||||
var it = Iterator2(i32).init(.{
|
||||
.min = .{ min_y, min_z },
|
||||
.max = .{ max_y, max_z },
|
||||
.min = .{ min_y_vx, min_z_vx },
|
||||
.max = .{ max_y_vx, max_z_vx },
|
||||
});
|
||||
while (it.next()) |yz| {
|
||||
const y, const z = yz;
|
||||
if (!isSolid(chunks, x, y, z)) continue;
|
||||
while (it.next()) |yz_vx| {
|
||||
const y_vx, const z_vx = yz_vx;
|
||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
||||
|
||||
const dx = fx - x0;
|
||||
const dy = dydx * dx;
|
||||
const distance = Vector2.init(dx, dy).len();
|
||||
const dx = x_sv - x0_sv;
|
||||
const fdx: f32 = @floatFromInt(dx);
|
||||
const fdy: f32 = fdx * fdydx;
|
||||
|
||||
if (distance >= closest_hit_distance) {
|
||||
break :px;
|
||||
}
|
||||
|
||||
closest_hit = .{
|
||||
.projected_distance = ray.getX() - dx,
|
||||
.normal = .negate(.unit_x),
|
||||
hit = .{
|
||||
.projected_distance_sv = ray_sv.getX() - dx,
|
||||
.normal_frac = .unit_nx_frac,
|
||||
};
|
||||
closest_hit_distance = distance;
|
||||
hit_distance_squared = fdx * fdx + fdy * fdy;
|
||||
std.debug.print("+X fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, hit_distance_squared });
|
||||
|
||||
break :px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negative X
|
||||
if (ray.getX() < 0.0) {
|
||||
const x0 = min_origin.getX();
|
||||
const y0 = min_origin.getY();
|
||||
const y1 = max_origin.getY();
|
||||
if (ray_sv.getX() < 0) {
|
||||
const x0_sv = min_origin_sv.getX();
|
||||
const y0_sv = min_origin_sv.getY();
|
||||
const y1_sv = max_origin_sv.getY();
|
||||
|
||||
const start_x = blockCoord(.next_down_with_border, x0);
|
||||
const end_x = blockCoord(.border_down, x0 + ray.getX());
|
||||
const start_x_vx = voxelFromSubvoxel(.next_down, x0_sv);
|
||||
const end_x_vx = voxelFromSubvoxel(.border_up, x0_sv + ray_sv.getX());
|
||||
|
||||
var x: i32 = start_x;
|
||||
nx: while (x >= end_x) : (x -= 1) {
|
||||
const fx = @as(f32, @floatFromInt(x)) + 1.0;
|
||||
const min_y = blockCoord(.border_up, (fx - x0) * dydx + y0);
|
||||
const max_y = blockCoord(.border_down, (fx - x0) * dydx + y1);
|
||||
var x_vx: i32 = start_x_vx;
|
||||
nx: while (x_vx >= end_x_vx) : (x_vx -= 1) {
|
||||
const x_sv = (x_vx + 1) * c.sv_per_vx;
|
||||
const min_y_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y0_sv);
|
||||
const max_y_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(x_sv - x0_sv, ray_sv.getY(), ray_sv.getX()) + y1_sv);
|
||||
var it = Iterator2(i32).init(.{
|
||||
.min = .{ min_y, min_z },
|
||||
.max = .{ max_y, max_z },
|
||||
.min = .{ min_y_vx, min_z_vx },
|
||||
.max = .{ max_y_vx, max_z_vx },
|
||||
});
|
||||
while (it.next()) |yz| {
|
||||
const y, const z = yz;
|
||||
if (!isSolid(chunks, x, y, z)) continue;
|
||||
while (it.next()) |yz_vx| {
|
||||
const y_vx, const z_vx = yz_vx;
|
||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
||||
|
||||
const dx = fx - x0;
|
||||
const dy = dydx * dx;
|
||||
const distance = Vector2.init(dx, dy).len();
|
||||
const dx = x_sv - x0_sv;
|
||||
const fdx: f32 = @floatFromInt(dx);
|
||||
const fdy: f32 = fdx * fdydx;
|
||||
|
||||
if (distance >= closest_hit_distance) {
|
||||
break :nx;
|
||||
}
|
||||
|
||||
closest_hit = .{
|
||||
.projected_distance = -(ray.getX() - dx),
|
||||
.normal = .unit_x,
|
||||
hit = .{
|
||||
.projected_distance_sv = -(ray_sv.getX() - dx),
|
||||
.normal_frac = .unit_x_frac,
|
||||
};
|
||||
closest_hit_distance = distance;
|
||||
hit_distance_squared = fdx * fdx + fdy * fdy;
|
||||
std.debug.print("-X fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, hit_distance_squared });
|
||||
|
||||
break :nx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Positive Y
|
||||
if (ray.getY() > 0.0) {
|
||||
const y0 = max_origin.getY();
|
||||
const x0 = min_origin.getX();
|
||||
const x1 = max_origin.getX();
|
||||
if (ray_sv.getY() > 0) {
|
||||
const y0_sv = max_origin_sv.getY();
|
||||
const x0_sv = min_origin_sv.getX();
|
||||
const x1_sv = max_origin_sv.getX();
|
||||
|
||||
const start_y: i32 = @intFromFloat(@ceil(y0));
|
||||
const end_y: i32 = @intFromFloat(@floor(y0 + ray.getY()));
|
||||
const start_y_vx = voxelFromSubvoxel(.next_up, y0_sv);
|
||||
const end_y_vx = voxelFromSubvoxel(.border_down, y0_sv + ray_sv.getY());
|
||||
|
||||
var y: i32 = start_y;
|
||||
py: while (y <= end_y) : (y += 1) {
|
||||
const fy = @as(f32, @floatFromInt(y));
|
||||
const min_x: i32 = @intFromFloat(@floor(fy - y0) * dxdy + x0);
|
||||
const max_x: i32 = @intFromFloat(@ceil((fy - y0) * dxdy + x1 - 1.0));
|
||||
var y_vx = start_y_vx;
|
||||
py: while (y_vx <= end_y_vx) : (y_vx += 1) {
|
||||
const y_sv = y_vx * c.sv_per_vx;
|
||||
const min_x_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
|
||||
const max_x_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
|
||||
var it = Iterator2(i32).init(.{
|
||||
.min = .{ min_x, min_z },
|
||||
.max = .{ max_x, max_z },
|
||||
.min = .{ min_x_vx, min_z_vx },
|
||||
.max = .{ max_x_vx, max_z_vx },
|
||||
});
|
||||
while (it.next()) |xz| {
|
||||
const x, const z = xz;
|
||||
if (!isSolid(chunks, x, y, z)) continue;
|
||||
while (it.next()) |xz_vx| {
|
||||
const x_vx, const z_vx = xz_vx;
|
||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
||||
|
||||
const dy = fy - y0;
|
||||
const dx = dxdy * dy;
|
||||
const distance = Vector2.init(dx, dy).len();
|
||||
const dy = y_sv - y0_sv;
|
||||
const fdy: f32 = @floatFromInt(dy);
|
||||
const fdx: f32 = fdy * fdxdy;
|
||||
|
||||
if (distance >= closest_hit_distance) {
|
||||
break :py;
|
||||
const this_hit_distance_squared = fdx * fdx + fdy * fdy;
|
||||
std.debug.print("+Y fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, this_hit_distance_squared });
|
||||
if (this_hit_distance_squared < hit_distance_squared) {
|
||||
hit = .{
|
||||
.projected_distance_sv = ray_sv.getY() - dy,
|
||||
.normal_frac = .unit_ny_frac,
|
||||
};
|
||||
hit_distance_squared = this_hit_distance_squared;
|
||||
}
|
||||
|
||||
closest_hit = .{
|
||||
.projected_distance = ray.getY() - dy,
|
||||
.normal = .negate(.unit_y),
|
||||
};
|
||||
closest_hit_distance = distance;
|
||||
break :py;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negative Y
|
||||
if (ray.getY() < 0.0) {
|
||||
const y0 = min_origin.getY();
|
||||
const x0 = min_origin.getX();
|
||||
const x1 = max_origin.getX();
|
||||
if (ray_sv.getY() < 0.0) {
|
||||
const y0_sv = min_origin_sv.getY();
|
||||
const x0_sv = min_origin_sv.getX();
|
||||
const x1_sv = max_origin_sv.getX();
|
||||
|
||||
const start_y = blockCoord(.next_down_with_border, y0);
|
||||
const end_y = blockCoord(.border_down, y0 + ray.getY());
|
||||
const start_y_vx = voxelFromSubvoxel(.next_down, y0_sv);
|
||||
const end_y_vx = voxelFromSubvoxel(.border_up, y0_sv + ray_sv.getY());
|
||||
|
||||
var y: i32 = start_y;
|
||||
py: while (y >= end_y) : (y -= 1) {
|
||||
const fy = @as(f32, @floatFromInt(y)) + 1.0;
|
||||
const min_x: i32 = @intFromFloat(@floor(fy - y0) * dxdy + x0);
|
||||
const max_x: i32 = @intFromFloat(@ceil((fy - y0) * dxdy + x1 - 1.0));
|
||||
var y_vx = start_y_vx;
|
||||
ny: while (y_vx >= end_y_vx) : (y_vx -= 1) {
|
||||
const y_sv = (y_vx + 1) * c.sv_per_vx;
|
||||
const min_x_vx = voxelFromSubvoxel(.border_up, wideMulDivFloor(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x0_sv);
|
||||
const max_x_vx = voxelFromSubvoxel(.border_down, wideMulDivCeil(y_sv - y0_sv, ray_sv.getX(), ray_sv.getY()) + x1_sv);
|
||||
var it = Iterator2(i32).init(.{
|
||||
.min = .{ min_x, min_z },
|
||||
.max = .{ max_x, max_z },
|
||||
.min = .{ min_x_vx, min_z_vx },
|
||||
.max = .{ max_x_vx, max_z_vx },
|
||||
});
|
||||
while (it.next()) |xz| {
|
||||
const x, const z = xz;
|
||||
if (!isSolid(chunks, x, y, z)) continue;
|
||||
while (it.next()) |xz_vx| {
|
||||
const x_vx, const z_vx = xz_vx;
|
||||
if (!isSolid(chunks, .init(x_vx, y_vx, z_vx))) continue;
|
||||
|
||||
const dy = fy - y0;
|
||||
const dx = dxdy * dy;
|
||||
const distance = Vector2.init(dx, dy).len();
|
||||
const dy = y_sv - y0_sv;
|
||||
const fdy: f32 = @floatFromInt(dy);
|
||||
const fdx: f32 = fdy * fdxdy;
|
||||
|
||||
if (distance >= closest_hit_distance) {
|
||||
break :py;
|
||||
const this_hit_distance_squared = fdx * fdx + fdy * fdy;
|
||||
std.debug.print("-Y fdx={d} fdy={d} dist2={d}\n", .{ fdx, fdy, this_hit_distance_squared });
|
||||
if (this_hit_distance_squared < hit_distance_squared) {
|
||||
hit = .{
|
||||
.projected_distance_sv = -(ray_sv.getY() - dy),
|
||||
.normal_frac = .unit_y_frac,
|
||||
};
|
||||
hit_distance_squared = this_hit_distance_squared;
|
||||
}
|
||||
|
||||
closest_hit = .{
|
||||
.projected_distance = -(ray.getY() - dy),
|
||||
.normal = .unit_y,
|
||||
};
|
||||
closest_hit_distance = distance;
|
||||
break :ny;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest_hit;
|
||||
return hit;
|
||||
}
|
||||
|
||||
fn resetAllButtons(self: *Player) void {
|
||||
@@ -525,50 +569,52 @@ fn resetAllButtons(self: *Player) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn isSolid(chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk), x: i32, y: i32, z: i32) bool {
|
||||
const chunk_x = std.math.cast(i16, @divFloor(x, Chunk.chunk_size)) orelse return true;
|
||||
const chunk_y = std.math.cast(i16, @divFloor(y, Chunk.chunk_size)) orelse return true;
|
||||
const chunk_z = std.math.cast(i16, @divFloor(z, Chunk.chunk_size)) orelse return true;
|
||||
if (chunks.get(.{ chunk_x, chunk_y, chunk_z })) |chunk| {
|
||||
const local_x: u4 = @intCast(@mod(x, Chunk.chunk_size));
|
||||
const local_y: u4 = @intCast(@mod(y, Chunk.chunk_size));
|
||||
const local_z: u4 = @intCast(@mod(z, Chunk.chunk_size));
|
||||
return chunk.blocks[local_z][local_y][local_x] != .air;
|
||||
} else {
|
||||
return false;
|
||||
fn getVoxelAt(chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk), vx: Vector3Int) ?Blocks.Id {
|
||||
const min_ck = Vector3Int.initScalar(std.math.minInt(i16));
|
||||
const max_ck = Vector3Int.initScalar(std.math.maxInt(i16));
|
||||
const ck = vx.divScalar(c.vx_per_ck);
|
||||
if (@reduce(.Or, (ck.vector < min_ck.vector) | (ck.vector > max_ck.vector))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (chunks.get(.{
|
||||
@intCast(ck.getX()),
|
||||
@intCast(ck.getY()),
|
||||
@intCast(ck.getZ()),
|
||||
})) |chunk| {
|
||||
const ckvx = vx.modScalar(c.vx_per_ck);
|
||||
return chunk.blocks[@intCast(ckvx.getZ())][@intCast(ckvx.getY())][@intCast(ckvx.getX())];
|
||||
} else {
|
||||
return .air;
|
||||
}
|
||||
}
|
||||
|
||||
fn isSolid(chunks: *const std.AutoHashMapUnmanaged([3]i16, Chunk), vx: Vector3Int) bool {
|
||||
const maybe_id = getVoxelAt(chunks, vx);
|
||||
// NOTE `null` is considered solid, as it's out of bounds.
|
||||
return maybe_id != .air;
|
||||
}
|
||||
|
||||
const RoundingMode = enum {
|
||||
border_down,
|
||||
border_up,
|
||||
next_down_with_border,
|
||||
next_down_without_border,
|
||||
next_up_with_border,
|
||||
next_up_without_border,
|
||||
next_down,
|
||||
next_up,
|
||||
};
|
||||
|
||||
inline fn blockCoord(comptime rounding_mode: RoundingMode, coord: f32) i32 {
|
||||
return switch (rounding_mode) {
|
||||
.border_down => @intFromFloat(@ceil(coord - 1.0)),
|
||||
.border_up => @intFromFloat(@floor(coord)),
|
||||
.next_down_with_border => @intFromFloat(@floor(coord - 1.0)),
|
||||
.next_down_without_border => @intFromFloat(@ceil(coord - 2.0)),
|
||||
.next_up_with_border => @intFromFloat(@ceil(coord)),
|
||||
.next_up_without_border => @intFromFloat(@floor(coord + 1.0)),
|
||||
};
|
||||
inline fn wideMulDivFloor(a: i32, mul: i32, div: i32) i32 {
|
||||
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul), div));
|
||||
}
|
||||
|
||||
inline fn blockCoord2(comptime rounding_mode: RoundingMode, coord: Vector2) [2]i32 {
|
||||
return switch (rounding_mode) {
|
||||
.border_down => @as(Vector2.Vector, @intFromFloat(@ceil(coord.sub(.one).vector))),
|
||||
.border_up => @as(Vector2.Vector, @intFromFloat(@floor(coord.vector))),
|
||||
};
|
||||
inline fn wideMulDivCeil(a: i32, mul: i32, div: i32) i32 {
|
||||
return @intCast(@divFloor(@as(i64, a) * @as(i64, mul) + @as(i64, div) - 1, div));
|
||||
}
|
||||
|
||||
inline fn blockCoord3(comptime rounding_mode: RoundingMode, coord: Vector3) [3]i32 {
|
||||
inline fn voxelFromSubvoxel(comptime rounding_mode: RoundingMode, subvoxel: i32) i32 {
|
||||
return switch (rounding_mode) {
|
||||
.border_down => @as(Vector3.Vector, @intFromFloat(@ceil(coord.sub(.one).vector))),
|
||||
.border_up => @as(Vector3.Vector, @intFromFloat(@floor(coord.vector))),
|
||||
.border_down => @divFloor(subvoxel - 1, c.sv_per_vx),
|
||||
.border_up => @divFloor(subvoxel, c.sv_per_vx),
|
||||
.next_down => @divFloor(subvoxel - c.sv_per_vx, c.sv_per_vx),
|
||||
.next_up => @divFloor(subvoxel + (c.sv_per_vx - 1), c.sv_per_vx),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Vector2 = @import("math.zig").Vector2;
|
||||
const Vector2Int = @import("math.zig").Vector2Int;
|
||||
|
||||
pub const app_name = "voxel-game";
|
||||
pub const app_version_string = @import("config").version;
|
||||
@@ -11,12 +11,33 @@ pub const max_frametime = 1.0 / min_framerate;
|
||||
|
||||
pub const default_window_width = 1280;
|
||||
pub const default_window_height = 720;
|
||||
pub const default_window_size = Vector2.init(default_window_width, default_window_height);
|
||||
pub const default_window_size = Vector2Int.init(default_window_width, default_window_height);
|
||||
|
||||
pub const min_window_width = 640;
|
||||
pub const min_window_height = 360;
|
||||
pub const min_window_size = Vector2.init(default_window_width, default_window_height);
|
||||
pub const min_window_size = Vector2Int.init(default_window_width, default_window_height);
|
||||
|
||||
pub const window_title = "Voxel Game";
|
||||
|
||||
pub const temp_allocator_capacity = 16 * 1024 * 1024;
|
||||
|
||||
// Coordinate spaces:
|
||||
// - CS (clip space, as required by Vulkan)
|
||||
// - VS (view space, looking towards +Y, +X is right and +Z is up)
|
||||
// - WS (world space, origin at a corner of voxel (0, 0, 0), +Z is up)
|
||||
// Units:
|
||||
// - SV (subvoxel) |
|
||||
// - VX (voxels) | 1 [VX] = 4096 [SV]
|
||||
// - CK (chunks) | 1 [CK] = 16 [VX]
|
||||
// Relative units:
|
||||
// CKSV subvoxels relative to chunk | [0, 65536)
|
||||
// CKVX voxels relative to chunk | [0, 16)
|
||||
// VXSV subvoxels relative to voxel | [0, 4096)
|
||||
|
||||
pub const sv_per_vx = 4096;
|
||||
pub const vx_per_ck = 16;
|
||||
pub const sv_per_ck = sv_per_vx * vx_per_ck;
|
||||
|
||||
pub inline fn sv(comptime vx: comptime_float) comptime_int {
|
||||
return @intFromFloat(@round(vx * sv_per_vx));
|
||||
}
|
||||
|
||||
38
src/math.zig
38
src/math.zig
@@ -1,10 +1,14 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const Iterator2 = @import("math/Iterator2.zig").Iterator2;
|
||||
pub const Iterator3 = @import("math/Iterator3.zig").Iterator3;
|
||||
pub const Matrix4x4 = @import("math/Matrix4x4.zig").Matrix4x4;
|
||||
pub const Quaternion = @import("math/Quaternion.zig").Quaternion;
|
||||
pub const Vector2 = @import("math/Vector2.zig").Vector2;
|
||||
pub const Vector2Int = @import("math/Vector2Int.zig").Vector2Int;
|
||||
pub const Vector2x8 = @import("math/Vector2x8.zig").Vector2x8;
|
||||
pub const Vector3 = @import("math/Vector3.zig").Vector3;
|
||||
pub const Vector3Int = @import("math/Vector3Int.zig").Vector3Int;
|
||||
pub const Vector4 = @import("math/Vector4.zig").Vector4;
|
||||
|
||||
pub const f32x8 = @Vector(8, f32);
|
||||
@@ -35,3 +39,37 @@ pub inline fn lerp(a: f32, b: f32, t: f32) f32 {
|
||||
|
||||
pub const noise2 = @import("math/noise.zig").noise2;
|
||||
pub const noise2x8 = @import("math/noise.zig").noise2x8;
|
||||
|
||||
pub inline fn asFloatFrac(frac: i32) f32 {
|
||||
const numerator: f64 = @floatFromInt(frac);
|
||||
const denominator: f64 = std.math.maxInt(i32);
|
||||
return @floatCast(numerator / denominator);
|
||||
}
|
||||
|
||||
pub inline fn asIntFrac(frac: f32) i32 {
|
||||
const fraction: f64 = @floatCast(frac);
|
||||
const scale: f64 = std.math.maxInt(i32);
|
||||
return @intFromFloat(@round(fraction * scale));
|
||||
}
|
||||
|
||||
pub inline fn mulIntFloat(int: i32, float: f32) i32 {
|
||||
const int_float: f64 = @floatFromInt(int);
|
||||
const float_wide: f64 = @floatCast(float);
|
||||
return @intFromFloat(@round(int_float * float_wide));
|
||||
}
|
||||
|
||||
pub inline fn mulFrac(a: i32, b: i32) i32 {
|
||||
const denominator: i64 = std.math.maxInt(i32);
|
||||
const rounding_bias: i64 = denominator >> 1;
|
||||
const a_wide: i64 = a;
|
||||
const b_wide: i64 = b;
|
||||
return @intCast(@divFloor(a_wide * b_wide + rounding_bias, denominator));
|
||||
}
|
||||
|
||||
pub inline fn mulFracFrac(a: i32, b: i32) i32 {
|
||||
const denominator: i64 = std.math.maxInt(i32) * std.math.maxInt(i32);
|
||||
const rounding_bias: i64 = denominator >> 1;
|
||||
const a_wide: i64 = a;
|
||||
const b_wide: i64 = b;
|
||||
return .{ .vector = @intCast(@divFloor(a_wide * b_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Vector2Int = @import("Vector2Int.zig").Vector2Int;
|
||||
const Vector3 = @import("Vector3.zig").Vector3;
|
||||
const Vector4 = @import("Vector3.zig").Vector4;
|
||||
|
||||
@@ -7,26 +8,33 @@ pub const Vector2 = extern struct {
|
||||
vector: Vector,
|
||||
|
||||
pub const Vector = @Vector(2, f32);
|
||||
pub const Array = [2]f32;
|
||||
pub const Mask = enum(i32) { x = 0, y = 1 };
|
||||
|
||||
pub const zero = Vector2.init(0, 0);
|
||||
pub const one = Vector2.init(1, 1);
|
||||
pub const zero = Vector2.initScalar(0);
|
||||
pub const one = Vector2.initScalar(1);
|
||||
pub const unit_x = Vector2.init(1, 0);
|
||||
pub const unit_y = Vector2.init(0, 1);
|
||||
pub const unit_nx = Vector2.init(-1, 0);
|
||||
pub const unit_ny = Vector2.init(0, -1);
|
||||
|
||||
// --- INIT ---
|
||||
|
||||
pub inline fn initScalar(scalar: f32) Vector2 {
|
||||
return .{ .vector = @splat(scalar) };
|
||||
}
|
||||
|
||||
pub inline fn init(x: f32, y: f32) Vector2 {
|
||||
return .{ .vector = .{ x, y } };
|
||||
}
|
||||
|
||||
pub inline fn initArray(array: [2]f32) Vector2 {
|
||||
pub inline fn initArray(array: Array) Vector2 {
|
||||
return .{ .vector = array };
|
||||
}
|
||||
|
||||
// --- CONVERSION ---
|
||||
|
||||
pub inline fn asArray(self: Vector2) [2]f32 {
|
||||
pub inline fn asArray(self: Vector2) Array {
|
||||
return self.vector;
|
||||
}
|
||||
|
||||
@@ -35,6 +43,16 @@ pub const Vector2 = extern struct {
|
||||
return @as(@Vector(2, T), @intFromFloat(@round(self.vector * scale_vector)));
|
||||
}
|
||||
|
||||
pub inline fn asVector2Int(self: Vector2) Vector2Int {
|
||||
return .{ .vector = @intFromFloat(@round(self.vector)) };
|
||||
}
|
||||
|
||||
pub inline fn asVector2IntFrac(self: Vector2) Vector2Int {
|
||||
const fraction: @Vector(2, f64) = @floatCast(self.vector);
|
||||
const scale: @Vector(2, f64) = @splat(std.math.maxInt(i32));
|
||||
return .{ .vector = @intFromFloat(@round(fraction * scale)) };
|
||||
}
|
||||
|
||||
pub inline fn asVector3(self: Vector2, z: f32) Vector3 {
|
||||
const z_vector: @Vector(3, f32) = .{ undefined, undefined, z };
|
||||
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
|
||||
|
||||
191
src/math/Vector2Int.zig
Normal file
191
src/math/Vector2Int.zig
Normal file
@@ -0,0 +1,191 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Vector2 = @import("Vector2.zig").Vector2;
|
||||
const Vector3Int = @import("Vector3Int.zig").Vector3Int;
|
||||
|
||||
pub const Vector2Int = extern struct {
|
||||
vector: Vector,
|
||||
|
||||
pub const Vector = @Vector(2, i32);
|
||||
pub const Array = [2]i32;
|
||||
pub const Mask = enum(i32) { x = 0, y = 1 };
|
||||
|
||||
pub const zero = Vector2Int.initScalar(0);
|
||||
pub const one = Vector2Int.initScalar(1);
|
||||
pub const one_frac = Vector2Int.initScalar(std.math.maxInt(i32));
|
||||
pub const unit_x = Vector2Int.init(1, 0);
|
||||
pub const unit_y = Vector2Int.init(0, 1);
|
||||
pub const unit_nx = Vector2Int.init(-1, 0);
|
||||
pub const unit_ny = Vector2Int.init(0, -1);
|
||||
pub const unit_x_frac = Vector2Int.init(std.math.maxInt(i32), 0);
|
||||
pub const unit_y_frac = Vector2Int.init(0, std.math.maxInt(i32));
|
||||
pub const unit_nx_frac = Vector2Int.init(-std.math.maxInt(i32), 0);
|
||||
pub const unit_ny_frac = Vector2Int.init(0, -std.math.maxInt(i32));
|
||||
|
||||
// --- INIT ---
|
||||
|
||||
pub inline fn initScalar(scalar: i32) Vector2Int {
|
||||
return .{ .vector = @splat(scalar) };
|
||||
}
|
||||
|
||||
pub inline fn init(x: i32, y: i32) Vector2Int {
|
||||
return .{ .vector = .{ x, y } };
|
||||
}
|
||||
|
||||
pub inline fn initArray(array: Array) Vector2Int {
|
||||
return .{ .vector = array };
|
||||
}
|
||||
|
||||
// --- CONVERSION ---
|
||||
|
||||
pub inline fn asArray(self: Vector2Int) Array {
|
||||
return self.vector;
|
||||
}
|
||||
|
||||
pub inline fn asVector2(self: Vector2Int) Vector2 {
|
||||
return .{ .vector = @floatFromInt(self.vector) };
|
||||
}
|
||||
|
||||
pub inline fn asVector2Frac(self: Vector2Int) Vector2 {
|
||||
const numerator: @Vector(2, f64) = @floatFromInt(self.vector);
|
||||
const denominator: @Vector(2, f64) = @splat(std.math.maxInt(i32));
|
||||
return .{ .vector = @floatCast(numerator / denominator) };
|
||||
}
|
||||
|
||||
pub inline fn asVector3Int(self: Vector2Int, z: i32) Vector3Int {
|
||||
const z_vector: @Vector(3, i32) = .{ undefined, undefined, z };
|
||||
return .{ .vector = @shuffle(i32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
|
||||
}
|
||||
|
||||
// --- ACCESSORS ---
|
||||
|
||||
pub inline fn getX(self: Vector2Int) i32 {
|
||||
return self.vector[0];
|
||||
}
|
||||
|
||||
pub inline fn getY(self: Vector2Int) i32 {
|
||||
return self.vector[1];
|
||||
}
|
||||
|
||||
pub inline fn setX(self: Vector2Int, x: i32) Vector2Int {
|
||||
const x_vector: Vector = @splat(x);
|
||||
return .{ .vector = @shuffle(i32, self.vector, x_vector, .{ ~@as(i32, 0), 1 }) };
|
||||
}
|
||||
|
||||
pub inline fn setY(self: Vector2Int, y: i32) Vector2Int {
|
||||
const y_vector: Vector = @splat(y);
|
||||
return .{ .vector = @shuffle(i32, self.vector, y_vector, .{ 0, ~@as(i32, 1) }) };
|
||||
}
|
||||
|
||||
// --- COMPONENT-WISE ---
|
||||
|
||||
pub inline fn add(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
return .{ .vector = self.vector + other.vector };
|
||||
}
|
||||
|
||||
pub inline fn sub(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
return .{ .vector = self.vector - other.vector };
|
||||
}
|
||||
|
||||
pub inline fn mul(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
return .{ .vector = self.vector * other.vector };
|
||||
}
|
||||
|
||||
pub inline fn mulFrac(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
const other_wide: @Vector(2, i64) = other.vector;
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn mulFracFrac(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
const other_wide: @Vector(2, i64) = other.vector;
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn div(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
return .{ .vector = @divFloor(self.vector, other.vector) };
|
||||
}
|
||||
|
||||
pub inline fn mod(self: Vector2Int, other: Vector2Int) Vector2Int {
|
||||
return .{ .vector = @mod(self.vector, other.vector) };
|
||||
}
|
||||
|
||||
pub inline fn negate(self: Vector2Int) Vector2Int {
|
||||
return .{ .vector = -self.vector };
|
||||
}
|
||||
|
||||
pub inline fn mulScalar(self: Vector2Int, scalar: i32) Vector2Int {
|
||||
const scalar_vector: Vector = @splat(scalar);
|
||||
return .{ .vector = self.vector * scalar_vector };
|
||||
}
|
||||
|
||||
pub inline fn mulScalarFloat(self: Vector2Int, scalar: f32) Vector2Int {
|
||||
const self_float: @Vector(2, f64) = @floatFromInt(self.vector);
|
||||
const scalar_vector_float: @Vector(2, f64) = @splat(scalar);
|
||||
return .{ .vector = @intFromFloat(@round(self_float * scalar_vector_float)) };
|
||||
}
|
||||
|
||||
pub inline fn mulScalarFrac(self: Vector2Int, scalar: i32) Vector2Int {
|
||||
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
const scalar_wide: @Vector(2, i64) = @splat(scalar);
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn mulScalarFracFrac(self: Vector2Int, scalar: i32) Vector2Int {
|
||||
const denominator: @Vector(2, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(2, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
const scalar_wide: @Vector(2, i64) = @splat(scalar);
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn divScalar(self: Vector2Int, scalar: i32) Vector2Int {
|
||||
const scalar_vector: Vector = @splat(scalar);
|
||||
return .{ .vector = @divFloor(self.vector, scalar_vector) };
|
||||
}
|
||||
|
||||
pub inline fn divScalarFloat(self: Vector2Int, scalar: f32) Vector2Int {
|
||||
const self_float: @Vector(2, f64) = @floatFromInt(self.vector);
|
||||
const scalar_vector_float: @Vector(2, f64) = @splat(scalar);
|
||||
return .{ .vector = @intFromFloat(@round(self_float / scalar_vector_float)) };
|
||||
}
|
||||
|
||||
pub inline fn modScalar(self: Vector2Int, scalar: i32) Vector2Int {
|
||||
const scalar_vector: Vector = @splat(scalar);
|
||||
return .{ .vector = @mod(self.vector, scalar_vector) };
|
||||
}
|
||||
|
||||
// --- SWIZZLE ---
|
||||
|
||||
pub inline fn swizzle2(self: Vector2Int, comptime mask: [2]Mask) Vector2Int {
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
|
||||
}
|
||||
|
||||
pub inline fn swizzle3(self: Vector2Int, comptime mask: [3]Mask) Vector3Int {
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
|
||||
}
|
||||
|
||||
// --- OTHER ---
|
||||
|
||||
pub inline fn lenSquared(self: Vector2Int) i64 {
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
return @reduce(.Add, self_wide * self_wide);
|
||||
}
|
||||
|
||||
pub inline fn dot(self: Vector2Int, other: Vector2Int) i64 {
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
const other_wide: @Vector(2, i64) = other.vector;
|
||||
return @reduce(.Add, self_wide * other_wide);
|
||||
}
|
||||
|
||||
pub inline fn cross(self: Vector2Int, other: Vector2Int) i64 {
|
||||
return @as(i64, self.getX()) * @as(i64, other.getY()) - @as(i64, self.getY()) * @as(i64, other.getX());
|
||||
}
|
||||
};
|
||||
@@ -14,6 +14,8 @@ pub const Vector2x8 = extern struct {
|
||||
pub const one = Vector2x8.init(ps(1), ps(1));
|
||||
pub const unit_x = Vector2x8.init(ps(1), ps(0));
|
||||
pub const unit_y = Vector2x8.init(ps(0), ps(1));
|
||||
pub const unit_nx = Vector2x8.init(ps(-1), ps(0));
|
||||
pub const unit_ny = Vector2x8.init(ps(0), ps(-1));
|
||||
|
||||
// --- INIT ---
|
||||
|
||||
|
||||
@@ -2,33 +2,42 @@ const std = @import("std");
|
||||
|
||||
const Quaternion = @import("Quaternion.zig").Quaternion;
|
||||
const Vector2 = @import("Vector2.zig").Vector2;
|
||||
const Vector3Int = @import("Vector3Int.zig").Vector3Int;
|
||||
const Vector4 = @import("Vector4.zig").Vector4;
|
||||
|
||||
pub const Vector3 = extern struct {
|
||||
vector: Vector,
|
||||
|
||||
pub const Vector = @Vector(3, f32);
|
||||
pub const Array = [3]f32;
|
||||
pub const Mask = enum(i32) { x = 0, y = 1, z = 2 };
|
||||
|
||||
pub const zero = Vector3.init(0, 0, 0);
|
||||
pub const one = Vector3.init(1, 1, 1);
|
||||
pub const zero = Vector3.initScalar(0);
|
||||
pub const one = Vector3.initScalar(1);
|
||||
pub const unit_x = Vector3.init(1, 0, 0);
|
||||
pub const unit_y = Vector3.init(0, 1, 0);
|
||||
pub const unit_z = Vector3.init(0, 0, 1);
|
||||
pub const unit_nx = Vector3.init(-1, 0, 0);
|
||||
pub const unit_ny = Vector3.init(0, -1, 0);
|
||||
pub const unit_nz = Vector3.init(0, 0, -1);
|
||||
|
||||
// --- INIT ---
|
||||
|
||||
pub inline fn initScalar(scalar: f32) Vector3 {
|
||||
return .{ .vector = @splat(scalar) };
|
||||
}
|
||||
|
||||
pub inline fn init(x: f32, y: f32, z: f32) Vector3 {
|
||||
return .{ .vector = .{ x, y, z } };
|
||||
}
|
||||
|
||||
pub inline fn initArray(array: [3]f32) Vector3 {
|
||||
pub inline fn initArray(array: Array) Vector3 {
|
||||
return .{ .vector = array };
|
||||
}
|
||||
|
||||
// --- CONVERSION ---
|
||||
|
||||
pub inline fn asArray(self: Vector3) [3]f32 {
|
||||
pub inline fn asArray(self: Vector3) Array {
|
||||
return self.vector;
|
||||
}
|
||||
|
||||
@@ -37,6 +46,16 @@ pub const Vector3 = extern struct {
|
||||
return @as(@Vector(3, T), @intFromFloat(@round(self.vector * scale_vector)));
|
||||
}
|
||||
|
||||
pub inline fn asVector3Int(self: Vector3) Vector3Int {
|
||||
return .{ .vector = @intFromFloat(@round(self.vector)) };
|
||||
}
|
||||
|
||||
pub inline fn asVector2IntFrac(self: Vector3) Vector3Int {
|
||||
const fraction: @Vector(3, f64) = @floatCast(self.vector);
|
||||
const scale: @Vector(3, f64) = @splat(std.math.maxInt(i32));
|
||||
return .{ .vector = @intFromFloat(@round(fraction * scale)) };
|
||||
}
|
||||
|
||||
pub inline fn asVector2(self: Vector3) Vector2 {
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1 }) };
|
||||
}
|
||||
|
||||
199
src/math/Vector3Int.zig
Normal file
199
src/math/Vector3Int.zig
Normal file
@@ -0,0 +1,199 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Vector2Int = @import("Vector2Int.zig").Vector2Int;
|
||||
const Vector3 = @import("Vector3.zig").Vector3;
|
||||
|
||||
pub const Vector3Int = extern struct {
|
||||
vector: Vector,
|
||||
|
||||
pub const Vector = @Vector(3, i32);
|
||||
pub const Array = [3]i32;
|
||||
pub const Mask = enum(i32) { x = 0, y = 1, z = 2 };
|
||||
|
||||
pub const zero = Vector3Int.initScalar(0);
|
||||
pub const one = Vector3Int.initScalar(1);
|
||||
pub const one_frac = Vector3Int.initScalar(std.math.maxInt(i32));
|
||||
pub const unit_x = Vector3Int.init(1, 0, 0);
|
||||
pub const unit_y = Vector3Int.init(0, 1, 0);
|
||||
pub const unit_z = Vector3Int.init(0, 0, 1);
|
||||
pub const unit_nx = Vector3Int.init(-1, 0, 0);
|
||||
pub const unit_ny = Vector3Int.init(0, -1, 0);
|
||||
pub const unit_nz = Vector3Int.init(0, 0, -1);
|
||||
pub const unit_x_frac = Vector3Int.init(std.math.maxInt(i32), 0, 0);
|
||||
pub const unit_y_frac = Vector3Int.init(0, std.math.maxInt(i32), 0);
|
||||
pub const unit_z_frac = Vector3Int.init(0, 0, std.math.maxInt(i32));
|
||||
pub const unit_nx_frac = Vector3Int.init(-std.math.maxInt(i32), 0, 0);
|
||||
pub const unit_ny_frac = Vector3Int.init(0, -std.math.maxInt(i32), 0);
|
||||
pub const unit_nz_frac = Vector3Int.init(0, 0, -std.math.maxInt(i32));
|
||||
|
||||
// --- INIT ---
|
||||
|
||||
pub inline fn initScalar(scalar: i32) Vector3Int {
|
||||
return .{ .vector = @splat(scalar) };
|
||||
}
|
||||
|
||||
pub inline fn init(x: i32, y: i32, z: i32) Vector3Int {
|
||||
return .{ .vector = .{ x, y, z } };
|
||||
}
|
||||
|
||||
pub inline fn initArray(array: Array) Vector3Int {
|
||||
return .{ .vector = array };
|
||||
}
|
||||
|
||||
// --- CONVERSION ---
|
||||
|
||||
pub inline fn asArray(self: Vector3Int) Array {
|
||||
return self.vector;
|
||||
}
|
||||
|
||||
pub inline fn asVector3(self: Vector3Int) Vector3 {
|
||||
return .{ .vector = @floatFromInt(self.vector) };
|
||||
}
|
||||
|
||||
pub inline fn asVector3Frac(self: Vector3Int) Vector3 {
|
||||
const numerator: @Vector(3, f64) = @floatFromInt(self.vector);
|
||||
const denominator: @Vector(3, f64) = @splat(std.math.maxInt(i32));
|
||||
return .{ .vector = @floatCast(numerator / denominator) };
|
||||
}
|
||||
|
||||
pub inline fn asVector2Int(self: Vector3Int) Vector2Int {
|
||||
return .{ .vector = @shuffle(i32, self.vector, undefined, [_]i32{ 0, 1 }) };
|
||||
}
|
||||
|
||||
// --- ACCESSORS ---
|
||||
|
||||
pub inline fn getX(self: Vector3Int) i32 {
|
||||
return self.vector[0];
|
||||
}
|
||||
|
||||
pub inline fn getY(self: Vector3Int) i32 {
|
||||
return self.vector[1];
|
||||
}
|
||||
|
||||
pub inline fn getZ(self: Vector3Int) i32 {
|
||||
return self.vector[2];
|
||||
}
|
||||
|
||||
pub inline fn setX(self: Vector3Int, x: i32) Vector3Int {
|
||||
const x_vector: Vector = @splat(x);
|
||||
return .{ .vector = @shuffle(i32, self.vector, x_vector, [_]i32{ ~@as(i32, 0), 1, 2 }) };
|
||||
}
|
||||
|
||||
pub inline fn setY(self: Vector3Int, y: i32) Vector3Int {
|
||||
const y_vector: Vector = @splat(y);
|
||||
return .{ .vector = @shuffle(i32, self.vector, y_vector, [_]i32{ 0, ~@as(i32, 1), 2 }) };
|
||||
}
|
||||
|
||||
pub inline fn setZ(self: Vector3Int, z: i32) Vector3Int {
|
||||
const z_vector: Vector = @splat(z);
|
||||
return .{ .vector = @shuffle(i32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
|
||||
}
|
||||
|
||||
// --- COMPONENT-WISE ---
|
||||
|
||||
pub inline fn add(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
return .{ .vector = self.vector + other.vector };
|
||||
}
|
||||
|
||||
pub inline fn sub(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
return .{ .vector = self.vector - other.vector };
|
||||
}
|
||||
|
||||
pub inline fn mul(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
return .{ .vector = self.vector * other.vector };
|
||||
}
|
||||
|
||||
pub inline fn mulFrac(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
|
||||
const self_wide: @Vector(3, i64) = self.vector;
|
||||
const other_wide: @Vector(3, i64) = other.vector;
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn mulFracFrac(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(2, u6), @splat(1));
|
||||
const self_wide: @Vector(3, i64) = self.vector;
|
||||
const other_wide: @Vector(3, i64) = other.vector;
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * other_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn div(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
return .{ .vector = @divFloor(self.vector, other.vector) };
|
||||
}
|
||||
|
||||
pub inline fn mod(self: Vector3Int, other: Vector3Int) Vector3Int {
|
||||
return .{ .vector = @mod(self.vector, other.vector) };
|
||||
}
|
||||
|
||||
pub inline fn negate(self: Vector3Int) Vector3Int {
|
||||
return .{ .vector = -self.vector };
|
||||
}
|
||||
|
||||
pub inline fn mulScalar(self: Vector3Int, scalar: i32) Vector3Int {
|
||||
const scalar_vector: Vector = @splat(scalar);
|
||||
return .{ .vector = self.vector * scalar_vector };
|
||||
}
|
||||
|
||||
pub inline fn mulScalarFloat(self: Vector3Int, scalar: f32) Vector3Int {
|
||||
const self_float: @Vector(3, f64) = @floatFromInt(self.vector);
|
||||
const scalar_vector_float: @Vector(3, f64) = @splat(scalar);
|
||||
return .{ .vector = @intFromFloat(@round(self_float * scalar_vector_float)) };
|
||||
}
|
||||
|
||||
pub inline fn mulScalarFrac(self: Vector3Int, scalar: i32) Vector3Int {
|
||||
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(3, u6), @splat(1));
|
||||
const self_wide: @Vector(3, i64) = self;
|
||||
const scalar_wide: @Vector(3, i64) = @splat(scalar);
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn mulScalarFracFrac(self: Vector3Int, scalar: i32) Vector3Int {
|
||||
const denominator: @Vector(3, i64) = @splat(std.math.maxInt(i32) * std.math.maxInt(i32));
|
||||
const rounding_bias: @Vector(3, i64) = denominator >> @as(@Vector(3, u6), @splat(1));
|
||||
const self_wide: @Vector(3, i64) = self;
|
||||
const scalar_wide: @Vector(3, i64) = @splat(scalar);
|
||||
return .{ .vector = @intCast(@divFloor(self_wide * scalar_wide + rounding_bias, denominator)) };
|
||||
}
|
||||
|
||||
pub inline fn divScalar(self: Vector3Int, scalar: i32) Vector3Int {
|
||||
const scalar_vector: Vector = @splat(scalar);
|
||||
return .{ .vector = @divFloor(self.vector, scalar_vector) };
|
||||
}
|
||||
|
||||
pub inline fn divScalarFloat(self: Vector3Int, scalar: f32) Vector3Int {
|
||||
const self_float: @Vector(3, f64) = @floatFromInt(self.vector);
|
||||
const scalar_vector_float: @Vector(3, f64) = @splat(scalar);
|
||||
return .{ .vector = @intFromFloat(@round(self_float / scalar_vector_float)) };
|
||||
}
|
||||
|
||||
pub inline fn modScalar(self: Vector3Int, scalar: i32) Vector3Int {
|
||||
const scalar_vector: Vector = @splat(scalar);
|
||||
return .{ .vector = @mod(self.vector, scalar_vector) };
|
||||
}
|
||||
|
||||
// --- SWIZZLE ---
|
||||
|
||||
pub inline fn swizzle2(self: Vector3Int, comptime mask: [2]Mask) Vector2Int {
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([2]i32, @bitCast(mask))) };
|
||||
}
|
||||
|
||||
pub inline fn swizzle3(self: Vector3Int, comptime mask: [3]Mask) Vector3Int {
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, @as([3]i32, @bitCast(mask))) };
|
||||
}
|
||||
|
||||
// --- OTHER ---
|
||||
|
||||
pub inline fn lenSquared(self: Vector3Int) i64 {
|
||||
const self_wide: @Vector(2, i64) = self.vector;
|
||||
return @reduce(.Add, self_wide * self_wide);
|
||||
}
|
||||
|
||||
pub inline fn dot(self: Vector3Int, other: Vector3Int) i64 {
|
||||
const self_wide: @Vector(3, i64) = self.vector;
|
||||
const other_wide: @Vector(3, i64) = other.vector;
|
||||
return @reduce(.Add, self_wide * other_wide);
|
||||
}
|
||||
};
|
||||
@@ -7,28 +7,37 @@ pub const Vector4 = extern struct {
|
||||
vector: Vector,
|
||||
|
||||
pub const Vector = @Vector(4, f32);
|
||||
pub const Array = [4]f32;
|
||||
pub const Mask = enum(i32) { x = 0, y = 1, z = 2, w = 3 };
|
||||
|
||||
pub const zero = Vector4.init(0, 0, 0, 0);
|
||||
pub const one = Vector4.init(1, 1, 1, 1);
|
||||
pub const zero = Vector4.initScalar(0);
|
||||
pub const one = Vector4.initScalar(1);
|
||||
pub const unit_x = Vector4.init(1, 0, 0, 0);
|
||||
pub const unit_y = Vector4.init(0, 1, 0, 0);
|
||||
pub const unit_z = Vector4.init(0, 0, 1, 0);
|
||||
pub const unit_w = Vector4.init(0, 0, 0, 1);
|
||||
pub const unit_nx = Vector4.init(-1, 0, 0, 0);
|
||||
pub const unit_ny = Vector4.init(0, -1, 0, 0);
|
||||
pub const unit_nz = Vector4.init(0, 0, -1, 0);
|
||||
pub const unit_nw = Vector4.init(0, 0, 0, -1);
|
||||
|
||||
// --- INIT ---
|
||||
|
||||
pub inline fn initScalar(scalar: f32) Vector4 {
|
||||
return .{ .vector = @splat(scalar) };
|
||||
}
|
||||
|
||||
pub inline fn init(x: f32, y: f32, z: f32, w: f32) Vector4 {
|
||||
return .{ .vector = .{ x, y, z, w } };
|
||||
}
|
||||
|
||||
pub inline fn initArray(array: [4]f32) Vector4 {
|
||||
pub inline fn initArray(array: Array) Vector4 {
|
||||
return .{ .vector = array };
|
||||
}
|
||||
|
||||
// --- CONVERSION ---
|
||||
|
||||
pub inline fn asArray(self: Vector4) [4]f32 {
|
||||
pub inline fn asArray(self: Vector4) Array {
|
||||
return self.vector;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user