diff --git a/src/chunk.zig b/src/chunk.zig index 30c9dd88..b784e9fc 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -86,9 +86,9 @@ pub const ChunkPosition = struct { pub fn getMinDistanceSquared(self: ChunkPosition, playerPosition: Vec3d) f64 { var halfWidth = @intToFloat(f64, self.voxelSize*@divExact(chunkSize, 2)); - var dx = @fabs(@intToFloat(f64, self.wx) + halfWidth - playerPosition.x); - var dy = @fabs(@intToFloat(f64, self.wy) + halfWidth - playerPosition.y); - var dz = @fabs(@intToFloat(f64, self.wz) + halfWidth - playerPosition.z); + var dx = @fabs(@intToFloat(f64, self.wx) + halfWidth - playerPosition[0]); + var dy = @fabs(@intToFloat(f64, self.wy) + halfWidth - playerPosition[1]); + var dz = @fabs(@intToFloat(f64, self.wz) + halfWidth - playerPosition[2]); dx = @max(0, dx - halfWidth); dy = @max(0, dy - halfWidth); dz = @max(0, dz - halfWidth); @@ -440,7 +440,7 @@ pub const meshing = struct { c.glUniformMatrix4fv(uniforms.viewMatrix, 1, c.GL_FALSE, @ptrCast([*c]f32, &game.camera.viewMatrix)); - c.glUniform3f(uniforms.ambientLight, ambient.x, ambient.y, ambient.z); + c.glUniform3f(uniforms.ambientLight, ambient[0], ambient[1], ambient[2]); c.glUniform1i(uniforms.time, @bitCast(i32, time)); @@ -837,9 +837,9 @@ pub const meshing = struct { if(self.vertexCount == 0) return; c.glUniform3f( uniforms.modelPosition, - @floatCast(f32, @intToFloat(f64, self.pos.wx) - playerPosition.x), - @floatCast(f32, @intToFloat(f64, self.pos.wy) - playerPosition.y), - @floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition.z) + @floatCast(f32, @intToFloat(f64, self.pos.wx) - playerPosition[0]), + @floatCast(f32, @intToFloat(f64, self.pos.wy) - playerPosition[1]), + @floatCast(f32, @intToFloat(f64, self.pos.wz) - playerPosition[2]) ); c.glUniform1i(uniforms.visibilityMask, self.visibilityMask); self.faceData.bind(3); diff --git a/src/entity.zig b/src/entity.zig index 990d3c32..964d4fb5 100644 --- a/src/entity.zig +++ b/src/entity.zig @@ -31,18 +31,18 @@ pub const ClientEntity = struct { pub fn init(self: *ClientEntity) void { const pos = [_]f64 { - self.pos.x, - self.pos.y, - self.pos.z, - @floatCast(f64, self.rot.x), - @floatCast(f64, self.rot.y), - @floatCast(f64, self.rot.z), + self.pos[0], + self.pos[1], + self.pos[2], + @floatCast(f64, self.rot[0]), + @floatCast(f64, self.rot[1]), + @floatCast(f64, self.rot[2]), }; self.interpolatedValues.initPosition(&pos); } pub fn getRenderPosition(self: *const ClientEntity) Vec3d { - return Vec3d{.x = self.pos.x, .y = self.pos.y + self.height/2, .z = self.pos.z}; + return Vec3d{self.pos[0], self.pos[1] + self.height/2, self.pos[2]}; } pub fn updatePosition(self: *ClientEntity, pos: *const [6]f64, vel: *const [6]f64, time: i16) void { @@ -51,12 +51,12 @@ pub const ClientEntity = struct { pub fn update(self: *ClientEntity, time: i16, lastTime: i16) void { self.interpolatedValues.update(time, lastTime); - self.pos.x = self.interpolatedValues.outPos[0]; - self.pos.y = self.interpolatedValues.outPos[1]; - self.pos.z = self.interpolatedValues.outPos[2]; - self.rot.x = @floatCast(f32, self.interpolatedValues.outPos[3]); - self.rot.y = @floatCast(f32, self.interpolatedValues.outPos[4]); - self.rot.z = @floatCast(f32, self.interpolatedValues.outPos[5]); + self.pos[0] = self.interpolatedValues.outPos[0]; + self.pos[1] = self.interpolatedValues.outPos[1]; + self.pos[2] = self.interpolatedValues.outPos[2]; + self.rot[0] = @floatCast(f32, self.interpolatedValues.outPos[3]); + self.rot[1] = @floatCast(f32, self.interpolatedValues.outPos[4]); + self.rot[2] = @floatCast(f32, self.interpolatedValues.outPos[5]); } }; @@ -110,22 +110,22 @@ pub const ClientEntityManager = struct { for(entities.items) |ent| { if(ent.id == game.Player.id or ent.name.len == 0) continue; // don't render local player - const pos3d: Vec3d = ent.getRenderPosition().sub(playerPos); + const pos3d: Vec3d = ent.getRenderPosition() - playerPos; const pos4f: Vec4f = Vec4f{ - .x = @floatCast(f32, pos3d.x), - .y = @floatCast(f32, pos3d.y + 1.5), - .z = @floatCast(f32, pos3d.z), - .w = 1, + @floatCast(f32, pos3d[0]), + @floatCast(f32, pos3d[1] + 1.5), + @floatCast(f32, pos3d[2]), + 1, }; const rotatedPos = game.camera.viewMatrix.mulVec(pos4f); const projectedPos = projMatrix.mulVec(rotatedPos); - if(projectedPos.z < 0) continue; - const xCenter = (1 + projectedPos.x/projectedPos.w)*@intToFloat(f32, main.Window.width/2); - const yCenter = (1 - projectedPos.y/projectedPos.w)*@intToFloat(f32, main.Window.height/2); + if(projectedPos[2] < 0) continue; + const xCenter = (1 + projectedPos[0]/projectedPos[3])*@intToFloat(f32, main.Window.width/2); + const yCenter = (1 - projectedPos[1]/projectedPos[3])*@intToFloat(f32, main.Window.height/2); graphics.Draw.setColor(0xffff00ff); - graphics.Draw.rect(.{.x=xCenter, .y=yCenter}, .{.x=100, .y=20}); // TODO: Text rendering. + graphics.Draw.rect(.{xCenter, yCenter}, .{100, 20}); // TODO: Text rendering. } } @@ -150,16 +150,16 @@ pub const ClientEntityManager = struct { c.glUniform1i(uniforms.materialHasTexture, c.GL_TRUE); c.glUniform1i(uniforms.light, @bitCast(c_int, @as(u32, 0xffffffff))); // TODO: Lighting - const pos: Vec3d = ent.getRenderPosition().sub(playerPos); + const pos: Vec3d = ent.getRenderPosition() - playerPos; const modelMatrix = ( Mat4f.identity() // TODO: .scale(scale); - .mul(Mat4f.rotationZ(-ent.rot.z)) - .mul(Mat4f.rotationY(-ent.rot.y)) - .mul(Mat4f.rotationX(-ent.rot.x)) + .mul(Mat4f.rotationZ(-ent.rot[2])) + .mul(Mat4f.rotationY(-ent.rot[1])) + .mul(Mat4f.rotationX(-ent.rot[0])) .mul(Mat4f.translation(Vec3f{ - .x = @floatCast(f32, pos.x), - .y = @floatCast(f32, pos.y), - .z = @floatCast(f32, pos.z), + @floatCast(f32, pos[0]), + @floatCast(f32, pos[1]), + @floatCast(f32, pos[2]), })) ); const modelViewMatrix = modelMatrix.mul(game.camera.viewMatrix); diff --git a/src/game.zig b/src/game.zig index 8762a9b0..ecd1dd6c 100644 --- a/src/game.zig +++ b/src/game.zig @@ -19,31 +19,31 @@ const Fog = graphics.Fog; const renderer = @import("renderer.zig"); pub const camera = struct { - pub var rotation: Vec3f = Vec3f{.x=0, .y=0, .z=0}; - pub var direction: Vec3f = Vec3f{.x=0, .y=0, .z=0}; + pub var rotation: Vec3f = Vec3f{0, 0, 0}; + pub var direction: Vec3f = Vec3f{0, 0, 0}; pub var viewMatrix: Mat4f = Mat4f.identity(); pub fn moveRotation(mouseX: f32, mouseY: f32) void { // Mouse movement along the x-axis rotates the image along the y-axis. - rotation.x += mouseY; - if(rotation.x > std.math.pi/2.0) { - rotation.x = std.math.pi/2.0; - } else if(rotation.x < -std.math.pi/2.0) { - rotation.x = -std.math.pi/2.0; + rotation[0] += mouseY; + if(rotation[0] > std.math.pi/2.0) { + rotation[0] = std.math.pi/2.0; + } else if(rotation[0] < -std.math.pi/2.0) { + rotation[0] = -std.math.pi/2.0; } // Mouse movement along the y-axis rotates the image along the x-axis. - rotation.y += mouseX; + rotation[1] += mouseX; - direction = Vec3f.rotateX(Vec3f{.x=0, .y=0, .z=-1}, -rotation.x).rotateY(-rotation.y); + direction = vec.rotateY(vec.rotateX(Vec3f{0, 0, -1}, -rotation[0]), -rotation[1]); } pub fn updateViewMatrix() void { - viewMatrix = Mat4f.rotationX(rotation.x).mul(Mat4f.rotationY(rotation.y)); + viewMatrix = Mat4f.rotationX(rotation[0]).mul(Mat4f.rotationY(rotation[1])); } }; pub const Player = struct { - var pos: Vec3d = Vec3d{.x=0, .y=0, .z=0}; - var vel: Vec3d = Vec3d{.x=0, .y=0, .z=0}; + var pos: Vec3d = Vec3d{0, 0, 0}; + var vel: Vec3d = Vec3d{0, 0, 0}; pub var id: u32 = 0; pub var isFlying: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(true); var mutex: std.Thread.Mutex = std.Thread.Mutex{}; @@ -73,7 +73,7 @@ pub const World = struct { conn: *Connection, manager: *ConnectionManager, ambientLight: f32 = 0, - clearColor: Vec4f = Vec4f{.x=0, .y=0, .z=0, .w=1}, + clearColor: Vec4f = Vec4f{0, 0, 0, 1}, name: []const u8, milliTime: i64, gameTime: std.atomic.Atomic(i64) = std.atomic.Atomic(i64).init(0), @@ -106,9 +106,9 @@ pub const World = struct { // TODO: Consider using a per-world allocator. self.blockPalette = try assets.BlockPalette.init(renderer.RenderStructure.allocator, jsonObject.getChild("blockPalette")); var jsonSpawn = jsonObject.getChild("spawn"); - self.spawn.x = jsonSpawn.get(f32, "x", 0); - self.spawn.y = jsonSpawn.get(f32, "y", 0); - self.spawn.z = jsonSpawn.get(f32, "z", 0); + self.spawn[0] = jsonSpawn.get(f32, "x", 0); + self.spawn[1] = jsonSpawn.get(f32, "y", 0); + self.spawn[2] = jsonSpawn.get(f32, "z", 0); // TODO: // if(Server.world != null) { @@ -140,34 +140,34 @@ pub const World = struct { var dayTime = std.math.absInt(@mod(self.gameTime.load(.Monotonic), dayCycle) -% dayCycle/2) catch 0; if(dayTime < dayCycle/4 - dayCycle/16) { self.ambientLight = 0.1; - self.clearColor.x = 0; - self.clearColor.y = 0; - self.clearColor.z = 0; + self.clearColor[0] = 0; + self.clearColor[1] = 0; + self.clearColor[2] = 0; } else if(dayTime > dayCycle/4 + dayCycle/16) { self.ambientLight = 1; - self.clearColor.x = 0.8; - self.clearColor.y = 0.8; - self.clearColor.z = 1.0; + self.clearColor[0] = 0.8; + self.clearColor[1] = 0.8; + self.clearColor[2] = 1.0; } else { // b: if(dayTime > dayCycle/4) { - self.clearColor.z = @intToFloat(f32, dayTime - dayCycle/4)/@intToFloat(f32, dayCycle/16); + self.clearColor[2] = @intToFloat(f32, dayTime - dayCycle/4)/@intToFloat(f32, dayCycle/16); } else { - self.clearColor.z = 0; + self.clearColor[2] = 0; } // g: if(dayTime > dayCycle/4 + dayCycle/32) { - self.clearColor.y = 0.8; + self.clearColor[1] = 0.8; } else if(dayTime > dayCycle/4 - dayCycle/32) { - self.clearColor.y = 0.8 + 0.8*@intToFloat(f32, dayTime - dayCycle/4 - dayCycle/32)/@intToFloat(f32, dayCycle/16); + self.clearColor[1] = 0.8 + 0.8*@intToFloat(f32, dayTime - dayCycle/4 - dayCycle/32)/@intToFloat(f32, dayCycle/16); } else { - self.clearColor.y = 0; + self.clearColor[1] = 0; } // r: if(dayTime > dayCycle/4) { - self.clearColor.x = 0.8; + self.clearColor[0] = 0.8; } else { - self.clearColor.x = 0.8 + 0.8*@intToFloat(f32, dayTime - dayCycle/4)/@intToFloat(f32, dayCycle/16); + self.clearColor[0] = 0.8 + 0.8*@intToFloat(f32, dayTime - dayCycle/4)/@intToFloat(f32, dayCycle/16); } dayTime -= dayCycle/4; dayTime <<= 3; @@ -271,50 +271,50 @@ pub var world: ?*World = &testWorld; pub var projectionMatrix: Mat4f = Mat4f.identity(); pub var lodProjectionMatrix: Mat4f = Mat4f.identity(); -pub var fog = Fog{.active = true, .color=.{.x=0, .y=1, .z=0.5}, .density=1.0/15.0/256.0}; +pub var fog = Fog{.active = true, .color=.{0, 1, 0.5}, .density=1.0/15.0/256.0}; pub fn update(deltaTime: f64) !void { - var movement = Vec3d{.x=0, .y=0, .z=0}; - var forward = Vec3d.rotateY(Vec3d{.x=0, .y=0, .z=-1}, -camera.rotation.y); - var right = Vec3d{.x=forward.z, .y=0, .z=-forward.x}; + var movement = Vec3d{0, 0, 0}; + var forward = vec.rotateY(Vec3d{0, 0, -1}, -camera.rotation[1]); + var right = Vec3d{forward[2], 0, -forward[0]}; if(keyboard.forward.pressed) { if(keyboard.sprint.pressed) { if(Player.isFlying.load(.Monotonic)) { - movement.addEqual(forward.mulScalar(128)); + movement += forward*@splat(3, @as(f64, 128)); } else { - movement.addEqual(forward.mulScalar(8)); + movement += forward*@splat(3, @as(f64, 8)); } } else { - movement.addEqual(forward.mulScalar(4)); + movement += forward*@splat(3, @as(f64, 4)); } } if(keyboard.backward.pressed) { - movement.addEqual(forward.mulScalar(-4)); + movement += forward*@splat(3, @as(f64, -4)); } if(keyboard.left.pressed) { - movement.addEqual(right.mulScalar(4)); + movement += right*@splat(3, @as(f64, 4)); } if(keyboard.right.pressed) { - movement.addEqual(right.mulScalar(-4)); + movement += right*@splat(3, @as(f64, -4)); } if(keyboard.jump.pressed) { if(Player.isFlying.load(.Monotonic)) { if(keyboard.sprint.pressed) { - movement.y = 59.45; + movement[1] = 59.45; } else { - movement.y = 5.45; + movement[1] = 5.45; } } else { // TODO: if (Cubyz.player.isOnGround()) - movement.y = 5.45; + movement[1] = 5.45; } } if(keyboard.fall.pressed) { if(Player.isFlying.load(.Monotonic)) { if(keyboard.sprint.pressed) { - movement.y = -59.45; + movement[1] = -59.45; } else { - movement.y = -5.45; + movement[1] = -5.45; } } } @@ -322,7 +322,7 @@ pub fn update(deltaTime: f64) !void { { Player.mutex.lock(); defer Player.mutex.unlock(); - Player.pos.addEqual(movement.mulScalar(deltaTime)); + Player.pos += movement*@splat(3, deltaTime); } try world.?.update(); } \ No newline at end of file diff --git a/src/graphics.zig b/src/graphics.zig index df4bcdbd..8e913fc7 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -111,8 +111,8 @@ pub const Draw = struct { rectShader.bind(); c.glUniform2f(rectUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height)); - c.glUniform2f(rectUniforms.start, pos.x, pos.y); - c.glUniform2f(rectUniforms.size, dim.x, dim.y); + c.glUniform2f(rectUniforms.start, pos[0], pos[1]); + c.glUniform2f(rectUniforms.size, dim[0], dim[1]); c.glUniform1i(rectUniforms.rectColor, color); c.glBindVertexArray(rectVAO); @@ -158,8 +158,8 @@ pub const Draw = struct { lineShader.bind(); c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height)); - c.glUniform2f(lineUniforms.start, pos1.x, pos1.y); - c.glUniform2f(lineUniforms.direction, pos2.x - pos1.x, pos2.y - pos1.y); + c.glUniform2f(lineUniforms.start, pos1[0], pos1[1]); + c.glUniform2f(lineUniforms.direction, pos2[0] - pos1[0], pos2[1] - pos1[1]); c.glUniform1i(lineUniforms.lineColor, color); c.glBindVertexArray(lineVAO); @@ -198,8 +198,8 @@ pub const Draw = struct { lineShader.bind(); c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height)); - c.glUniform2f(lineUniforms.start, pos.x, pos.y); // Move the coordinates, so they are in the center of a pixel. - c.glUniform2f(lineUniforms.direction, dim.x - 1, dim.y - 1); // The height is a lot smaller because the inner edge of the rect is drawn. + c.glUniform2f(lineUniforms.start, pos[0], pos[1]); // Move the coordinates, so they are in the center of a pixel. + c.glUniform2f(lineUniforms.direction, dim[0] - 1, dim[1] - 1); // The height is a lot smaller because the inner edge of the rect is drawn. c.glUniform1i(lineUniforms.lineColor, color); c.glBindVertexArray(lineVAO); @@ -247,7 +247,7 @@ pub const Draw = struct { circleShader.bind(); c.glUniform2f(circleUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height)); - c.glUniform2f(circleUniforms.center, center.x, center.y); // Move the coordinates, so they are in the center of a pixel. + c.glUniform2f(circleUniforms.center, center[0], center[1]); // Move the coordinates, so they are in the center of a pixel. c.glUniform1f(circleUniforms.radius, radius); // The height is a lot smaller because the inner edge of the rect is drawn. c.glUniform1i(circleUniforms.circleColor, color); @@ -280,8 +280,8 @@ pub const Draw = struct { imageShader.bind(); c.glUniform2f(imageUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height)); - c.glUniform2f(imageUniforms.start, pos.x, pos.y); - c.glUniform2f(imageUniforms.size, dim.x, dim.y); + c.glUniform2f(imageUniforms.start, pos[0], pos[1]); + c.glUniform2f(imageUniforms.size, dim[0], dim[1]); c.glUniform1i(imageUniforms.color, color); c.glBindVertexArray(rectVAO); diff --git a/src/main.zig b/src/main.zig index 7f5cc5d6..112c645d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -104,25 +104,25 @@ pub const Window = struct { } // Mouse deltas are averaged over multiple frames using a circular buffer: const deltasLen: u2 = 3; - var deltas: [deltasLen]Vec2f = [_]Vec2f{Vec2f{.x=0, .y=0}} ** 3; + var deltas: [deltasLen]Vec2f = [_]Vec2f{Vec2f{0, 0}} ** 3; var deltaBufferPosition: u2 = 0; - var currentPos: Vec2f = Vec2f{.x=0, .y=0}; + var currentPos: Vec2f = Vec2f{0, 0}; var ignoreDataAfterRecentGrab: bool = true; fn cursorPosition(_: ?*c.GLFWwindow, x: f64, y: f64) callconv(.C) void { const newPos = Vec2f { - .x = @floatCast(f32, x), - .y = @floatCast(f32, y), + @floatCast(f32, x), + @floatCast(f32, y), }; if(grabbed and !ignoreDataAfterRecentGrab) { - deltas[deltaBufferPosition].addEqual(newPos.sub(currentPos).mulScalar(settings.mouseSensitivity)); - var averagedDelta: Vec2f = Vec2f{.x=0, .y=0}; + deltas[deltaBufferPosition] += (newPos - currentPos)*@splat(2, settings.mouseSensitivity); + var averagedDelta: Vec2f = Vec2f{0, 0}; for(deltas) |delta| { - averagedDelta.addEqual(delta); + averagedDelta += delta; } - averagedDelta.divEqualScalar(deltasLen); - game.camera.moveRotation(averagedDelta.x*0.0089, averagedDelta.y*0.0089); + averagedDelta /= @splat(2, @as(f32, deltasLen)); + game.camera.moveRotation(averagedDelta[0]*0.0089, averagedDelta[1]*0.0089); deltaBufferPosition = (deltaBufferPosition + 1)%deltasLen; - deltas[deltaBufferPosition] = Vec2f{.x=0, .y=0}; + deltas[deltaBufferPosition] = Vec2f{0, 0}; } ignoreDataAfterRecentGrab = false; currentPos = newPos; diff --git a/src/network.zig b/src/network.zig index 9308d4b7..53fc600c 100644 --- a/src/network.zig +++ b/src/network.zig @@ -763,15 +763,15 @@ pub const Protocols: struct { } lastPositionSent = time; var data: [62]u8 = undefined; - std.mem.writeIntBig(u64, data[0..8], @bitCast(u64, playerPos.x)); - std.mem.writeIntBig(u64, data[8..16], @bitCast(u64, playerPos.y)); - std.mem.writeIntBig(u64, data[16..24], @bitCast(u64, playerPos.z)); - std.mem.writeIntBig(u64, data[24..32], @bitCast(u64, playerVel.x)); - std.mem.writeIntBig(u64, data[32..40], @bitCast(u64, playerVel.y)); - std.mem.writeIntBig(u64, data[40..48], @bitCast(u64, playerVel.z)); - std.mem.writeIntBig(u32, data[48..52], @bitCast(u32, game.camera.rotation.x)); - std.mem.writeIntBig(u32, data[52..56], @bitCast(u32, game.camera.rotation.y)); - std.mem.writeIntBig(u32, data[56..60], @bitCast(u32, game.camera.rotation.z)); + std.mem.writeIntBig(u64, data[0..8], @bitCast(u64, playerPos[0])); + std.mem.writeIntBig(u64, data[8..16], @bitCast(u64, playerPos[1])); + std.mem.writeIntBig(u64, data[16..24], @bitCast(u64, playerPos[2])); + std.mem.writeIntBig(u64, data[24..32], @bitCast(u64, playerVel[0])); + std.mem.writeIntBig(u64, data[32..40], @bitCast(u64, playerVel[1])); + std.mem.writeIntBig(u64, data[40..48], @bitCast(u64, playerVel[2])); + std.mem.writeIntBig(u32, data[48..52], @bitCast(u32, game.camera.rotation[0])); + std.mem.writeIntBig(u32, data[52..56], @bitCast(u32, game.camera.rotation[1])); + std.mem.writeIntBig(u32, data[56..60], @bitCast(u32, game.camera.rotation[2])); std.mem.writeIntBig(u16, data[60..62], time); try conn.sendUnimportant(id, &data); } @@ -993,9 +993,9 @@ pub const Protocols: struct { }, type_teleport => { game.Player.setPosBlocking(Vec3d{ - .x = @bitCast(f64, std.mem.readIntBig(u64, data[1..9])), - .y = @bitCast(f64, std.mem.readIntBig(u64, data[9..17])), - .z = @bitCast(f64, std.mem.readIntBig(u64, data[17..25])), + @bitCast(f64, std.mem.readIntBig(u64, data[1..9])), + @bitCast(f64, std.mem.readIntBig(u64, data[9..17])), + @bitCast(f64, std.mem.readIntBig(u64, data[17..25])), }); }, type_cure => { @@ -1114,9 +1114,9 @@ pub const Protocols: struct { pub fn sendTPCoordinates(conn: *Connection, pos: Vec3d) !void { var data: [1+24]u8 = undefined; data[0] = type_teleport; - std.mem.writeIntBig(u64, data[1..9], @bitCast(u64, pos.x)); - std.mem.writeIntBig(u64, data[9..17], @bitCast(u64, pos.y)); - std.mem.writeIntBig(u64, data[17..25], @bitCast(u64, pos.z)); + std.mem.writeIntBig(u64, data[1..9], @bitCast(u64, pos[0])); + std.mem.writeIntBig(u64, data[9..17], @bitCast(u64, pos[1])); + std.mem.writeIntBig(u64, data[17..25], @bitCast(u64, pos[2])); try conn.sendImportant(id, &data); } diff --git a/src/renderer.zig b/src/renderer.zig index fe147bc1..80f3f614 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -132,7 +132,7 @@ const buffers = struct { fn clearAndBind(clearColor: Vec4f) void { c.glBindFramebuffer(c.GL_FRAMEBUFFER, buffer); - c.glClearColor(clearColor.x, clearColor.y, clearColor.z, 1); + c.glClearColor(clearColor[0], clearColor[1], clearColor[2], 1); c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); // Clears the position separately to prevent issues with default value. const positionClearColor = [_]f32 {0, 0, 6.55e4, 1}; // z value corresponds to the highest 16-bit float value. @@ -182,15 +182,15 @@ pub fn render(playerPosition: Vec3d) !void { if(game.world) |world| { // // TODO: Handle colors and sun position in the world. var ambient: Vec3f = undefined; - ambient.x = @max(0.1, world.ambientLight); - ambient.y = @max(0.1, world.ambientLight); - ambient.z = @max(0.1, world.ambientLight); - var skyColor = Vec3f.xyz(world.clearColor); + ambient[0] = @max(0.1, world.ambientLight); + ambient[1] = @max(0.1, world.ambientLight); + ambient[2] = @max(0.1, world.ambientLight); + var skyColor = vec.xyz(world.clearColor); game.fog.color = skyColor; // TODO: // Cubyz.fog.setActive(ClientSettings.FOG_COEFFICIENT != 0); // Cubyz.fog.setDensity(1 / (ClientSettings.EFFECTIVE_RENDER_DISTANCE*ClientSettings.FOG_COEFFICIENT)); - skyColor.mulEqualScalar(0.25); + skyColor *= @splat(3, @as(f32, 0.25)); try renderWorld(world, ambient, skyColor, playerPosition); try RenderStructure.updateMeshes(startTime + maximumMeshTime); @@ -209,16 +209,16 @@ pub fn render(playerPosition: Vec3d) !void { pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPos: Vec3d) !void { _ = world; - buffers.clearAndBind(Vec4f{.x=skyColor.x, .y=skyColor.y, .z=skyColor.z, .w=1}); + buffers.clearAndBind(Vec4f{skyColor[0], skyColor[1], skyColor[2], 1}); // TODO:// Clean up old chunk meshes: // Meshes.cleanUp(); game.camera.updateViewMatrix(); // Uses FrustumCulling on the chunks. - var frustum = Frustum.init(Vec3f{.x=0, .y=0, .z=0}, game.camera.viewMatrix, settings.fov, zFarLOD, main.Window.width, main.Window.height); + var frustum = Frustum.init(Vec3f{0, 0, 0}, game.camera.viewMatrix, settings.fov, zFarLOD, main.Window.width, main.Window.height); const time = @intCast(u32, std.time.milliTimestamp() & std.math.maxInt(u32)); - var waterFog = Fog{.active=true, .color=.{.x=0.0, .y=0.1, .z=0.2}, .density=0.1}; + var waterFog = Fog{.active=true, .color=.{0.0, 0.1, 0.2}, .density=0.1}; // Update the uniforms. The uniforms are needed to render the replacement meshes. chunk.meshing.bindShaderAndUniforms(game.lodProjectionMatrix, ambientLight, time); @@ -268,7 +268,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo // } c.glDepthRangef(0, 0.05); - entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{.x=1, .y=0.5, .z=0.25}, playerPos); + entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{1, 0.5, 0.25}, playerPos); // BlockDropRenderer.render(frustumInt, ambientLight, directionalLight, playerPosition); @@ -495,30 +495,30 @@ pub const Frustum = struct { pub fn init(cameraPos: Vec3f, rotationMatrix: Mat4f, fovY: f32, _zFar: f32, width: u31, height: u31) Frustum { var invRotationMatrix = rotationMatrix.transpose(); - var cameraDir = Vec3f.xyz(invRotationMatrix.mulVec(Vec4f{.x=0, .y=0, .z=1, .w=1})); - var cameraUp = Vec3f.xyz(invRotationMatrix.mulVec(Vec4f{.x=0, .y=1, .z=0, .w=1})); - var cameraRight = Vec3f.xyz(invRotationMatrix.mulVec(Vec4f{.x=1, .y=0, .z=0, .w=1})); + var cameraDir = vec.xyz(invRotationMatrix.mulVec(Vec4f{0, 0, 1, 1})); + var cameraUp = vec.xyz(invRotationMatrix.mulVec(Vec4f{0, 1, 0, 1})); + var cameraRight = vec.xyz(invRotationMatrix.mulVec(Vec4f{1, 0, 0, 1})); const halfVSide = _zFar*std.math.tan(std.math.degreesToRadians(f32, fovY)*0.5); const halfHSide = halfVSide*@intToFloat(f32, width)/@intToFloat(f32, height); - const frontMultFar = cameraDir.mulScalar(_zFar); + const frontMultFar = cameraDir*@splat(3, _zFar); var self: Frustum = undefined; - self.planes[0] = Plane{.pos = cameraPos.add(frontMultFar), .norm=cameraDir.mulScalar(-1)}; // far - self.planes[1] = Plane{.pos = cameraPos, .norm=cameraUp.cross(frontMultFar.add(cameraRight.mulScalar(halfHSide)))}; // right - self.planes[2] = Plane{.pos = cameraPos, .norm=frontMultFar.sub(cameraRight.mulScalar(halfHSide)).cross(cameraUp)}; // left - self.planes[3] = Plane{.pos = cameraPos, .norm=cameraRight.cross(frontMultFar.sub(cameraUp.mulScalar(halfVSide)))}; // top - self.planes[4] = Plane{.pos = cameraPos, .norm=frontMultFar.add(cameraUp.mulScalar(halfVSide)).cross(cameraRight)}; // bottom + self.planes[0] = Plane{.pos = cameraPos + frontMultFar, .norm=-cameraDir}; // far + self.planes[1] = Plane{.pos = cameraPos, .norm=vec.cross(cameraUp, frontMultFar + cameraRight*@splat(3, halfHSide))}; // right + self.planes[2] = Plane{.pos = cameraPos, .norm=vec.cross(frontMultFar - cameraRight*@splat(3, halfHSide), cameraUp)}; // left + self.planes[3] = Plane{.pos = cameraPos, .norm=vec.cross(cameraRight, frontMultFar - cameraUp*@splat(3, halfVSide))}; // top + self.planes[4] = Plane{.pos = cameraPos, .norm=vec.cross(frontMultFar + cameraUp*@splat(3, halfVSide), cameraRight)}; // bottom return self; } pub fn testAAB(self: Frustum, pos: Vec3f, dim: Vec3f) bool { inline for(self.planes) |plane| { - var dist: f32 = pos.sub(plane.pos).dot(plane.norm); + var dist: f32 = vec.dot(pos - plane.pos, plane.norm); // Find the most positive corner: - dist += @max(0, dim.x*plane.norm.x); - dist += @max(0, dim.y*plane.norm.y); - dist += @max(0, dim.z*plane.norm.z); + dist += @max(0, dim[0]*plane.norm[0]); + dist += @max(0, dim[1]*plane.norm[1]); + dist += @max(0, dim[2]*plane.norm[2]); if(dist < 128) return false; } return true; @@ -599,27 +599,27 @@ pub const MeshSelection = struct { // Test blocks: const closestDistance: f64 = 6.0; // selection now limited // Implementation of "A Fast Voxel Traversal Algorithm for Ray Tracing" http://www.cse.yorku.ca/~amana/research/grid.pdf - const stepX = @floatToInt(chunk.ChunkCoordinate, std.math.sign(dir.x)); - const stepY = @floatToInt(chunk.ChunkCoordinate, std.math.sign(dir.y)); - const stepZ = @floatToInt(chunk.ChunkCoordinate, std.math.sign(dir.z)); - const invDirX: f64 = 1/dir.x; - const invDirY: f64 = 1/dir.y; - const invDirZ: f64 = 1/dir.z; + const stepX = @floatToInt(chunk.ChunkCoordinate, std.math.sign(dir[0])); + const stepY = @floatToInt(chunk.ChunkCoordinate, std.math.sign(dir[1])); + const stepZ = @floatToInt(chunk.ChunkCoordinate, std.math.sign(dir[2])); + const invDirX: f64 = 1/dir[0]; + const invDirY: f64 = 1/dir[1]; + const invDirZ: f64 = 1/dir[2]; const tDeltaX: f64 = @fabs(invDirX); const tDeltaY: f64 = @fabs(invDirY); const tDeltaZ: f64 = @fabs(invDirZ); - var tMaxX: f64 = (@floor(pos.x) - pos.x)*invDirX; - var tMaxY: f64 = (@floor(pos.y) - pos.y)*invDirY; - var tMaxZ: f64 = (@floor(pos.z) - pos.z)*invDirZ; + var tMaxX: f64 = (@floor(pos[0]) - pos[0])*invDirX; + var tMaxY: f64 = (@floor(pos[1]) - pos[1])*invDirY; + var tMaxZ: f64 = (@floor(pos[2]) - pos[2])*invDirZ; tMaxX = @max(tMaxX, tMaxX + tDeltaX*@intToFloat(f64, stepX)); tMaxY = @max(tMaxY, tMaxY + tDeltaY*@intToFloat(f64, stepY)); tMaxZ = @max(tMaxZ, tMaxZ + tDeltaZ*@intToFloat(f64, stepZ)); - if(dir.x == 0) tMaxX = std.math.inf_f64; - if(dir.y == 0) tMaxY = std.math.inf_f64; - if(dir.z == 0) tMaxZ = std.math.inf_f64; - var x = @floatToInt(chunk.ChunkCoordinate, @floor(pos.x)); - var y = @floatToInt(chunk.ChunkCoordinate, @floor(pos.y)); - var z = @floatToInt(chunk.ChunkCoordinate, @floor(pos.z)); + if(dir[0] == 0) tMaxX = std.math.inf_f64; + if(dir[1] == 0) tMaxY = std.math.inf_f64; + if(dir[2] == 0) tMaxZ = std.math.inf_f64; + var x = @floatToInt(chunk.ChunkCoordinate, @floor(pos[0])); + var y = @floatToInt(chunk.ChunkCoordinate, @floor(pos[1])); + var z = @floatToInt(chunk.ChunkCoordinate, @floor(pos[2])); var total_tMax: f64 = 0; @@ -630,12 +630,12 @@ pub const MeshSelection = struct { if(block.typ != 0) { // Check the true bounding box (using this algorithm here: https://tavianator.com/2011/ray_box.html): const voxelModel = &models.voxelModels.items[blocks.meshes.modelIndices(block)]; - const tx1 = (@intToFloat(f64, x) + @intToFloat(f64, voxelModel.minX)/16.0 - pos.x)*invDirX; - const tx2 = (@intToFloat(f64, x) + @intToFloat(f64, voxelModel.maxX)/16.0 - pos.x)*invDirX; - const ty1 = (@intToFloat(f64, y) + @intToFloat(f64, voxelModel.minY)/16.0 - pos.y)*invDirY; - const ty2 = (@intToFloat(f64, y) + @intToFloat(f64, voxelModel.maxY)/16.0 - pos.y)*invDirY; - const tz1 = (@intToFloat(f64, z) + @intToFloat(f64, voxelModel.minZ)/16.0 - pos.z)*invDirZ; - const tz2 = (@intToFloat(f64, z) + @intToFloat(f64, voxelModel.maxZ)/16.0 - pos.z)*invDirZ; + const tx1 = (@intToFloat(f64, x) + @intToFloat(f64, voxelModel.minX)/16.0 - pos[0])*invDirX; + const tx2 = (@intToFloat(f64, x) + @intToFloat(f64, voxelModel.maxX)/16.0 - pos[0])*invDirX; + const ty1 = (@intToFloat(f64, y) + @intToFloat(f64, voxelModel.minY)/16.0 - pos[1])*invDirY; + const ty2 = (@intToFloat(f64, y) + @intToFloat(f64, voxelModel.maxY)/16.0 - pos[1])*invDirY; + const tz1 = (@intToFloat(f64, z) + @intToFloat(f64, voxelModel.minZ)/16.0 - pos[2])*invDirZ; + const tz2 = (@intToFloat(f64, z) + @intToFloat(f64, voxelModel.maxZ)/16.0 - pos[2])*invDirZ; const tMin = @max( @min(tx1, tx2), @max( @@ -651,7 +651,7 @@ pub const MeshSelection = struct { ) ); if(tMin <= tMax and tMin <= closestDistance and tMax > 0) { - selectedBlockPos = Vec3i{.x=x, .y=y, .z=z}; + selectedBlockPos = Vec3i{x, y, z}; break; } } @@ -765,16 +765,16 @@ pub const MeshSelection = struct { // } pub fn render(projectionMatrix: Mat4f, viewMatrix: Mat4f, playerPos: Vec3d) void { if(selectedBlockPos) |_selectedBlockPos| { - var block = RenderStructure.getBlock(_selectedBlockPos.x, _selectedBlockPos.y, _selectedBlockPos.z) orelse return; + var block = RenderStructure.getBlock(_selectedBlockPos[0], _selectedBlockPos[1], _selectedBlockPos[2]) orelse return; var voxelModel = &models.voxelModels.items[blocks.meshes.modelIndices(block)]; shader.bind(); c.glUniformMatrix4fv(uniforms.projectionMatrix, 1, c.GL_FALSE, @ptrCast([*c]const f32, &projectionMatrix)); c.glUniformMatrix4fv(uniforms.viewMatrix, 1, c.GL_FALSE, @ptrCast([*c]const f32, &viewMatrix)); c.glUniform3f(uniforms.modelPosition, - @floatCast(f32, @intToFloat(f64, _selectedBlockPos.x) - playerPos.x), - @floatCast(f32, @intToFloat(f64, _selectedBlockPos.y) - playerPos.y), - @floatCast(f32, @intToFloat(f64, _selectedBlockPos.z) - playerPos.z) + @floatCast(f32, @intToFloat(f64, _selectedBlockPos[0]) - playerPos[0]), + @floatCast(f32, @intToFloat(f64, _selectedBlockPos[1]) - playerPos[1]), + @floatCast(f32, @intToFloat(f64, _selectedBlockPos[2]) - playerPos[2]) ); c.glUniform3f(uniforms.lowerBounds, @intToFloat(f32, voxelModel.minX)/16.0, @@ -895,9 +895,9 @@ pub const RenderStructure = struct { if(lastRD != renderDistance and lastFactor != LODFactor) { try network.Protocols.genericUpdate.sendRenderDistance(conn, renderDistance, LODFactor); } - const px = @floatToInt(chunk.ChunkCoordinate, playerPos.x); - const py = @floatToInt(chunk.ChunkCoordinate, playerPos.y); - const pz = @floatToInt(chunk.ChunkCoordinate, playerPos.z); + const px = @floatToInt(chunk.ChunkCoordinate, playerPos[0]); + const py = @floatToInt(chunk.ChunkCoordinate, playerPos[1]); + const pz = @floatToInt(chunk.ChunkCoordinate, playerPos[2]); var meshRequests = std.ArrayList(chunk.ChunkPosition).init(main.threadAllocator); defer meshRequests.deinit(); @@ -956,13 +956,13 @@ pub const RenderStructure = struct { try meshRequests.append(pos); } if(frustum.testAAB(Vec3f{ - .x = @floatCast(f32, @intToFloat(f64, x) - playerPos.x), - .y = @floatCast(f32, @intToFloat(f64, y) - playerPos.y), - .z = @floatCast(f32, @intToFloat(f64, z) - playerPos.z), + @floatCast(f32, @intToFloat(f64, x) - playerPos[0]), + @floatCast(f32, @intToFloat(f64, y) - playerPos[1]), + @floatCast(f32, @intToFloat(f64, z) - playerPos[2]), }, Vec3f{ - .x = @intToFloat(f32, size), - .y = @intToFloat(f32, size), - .z = @intToFloat(f32, size), + @intToFloat(f32, size), + @intToFloat(f32, size), + @intToFloat(f32, size), }) and node.?.mesh.visibilityMask != 0) { try meshes.append(&node.?.mesh); } diff --git a/src/vec.zig b/src/vec.zig index bc50a7ef..24e0e2f7 100644 --- a/src/vec.zig +++ b/src/vec.zig @@ -1,231 +1,62 @@ const std = @import("std"); -pub const Vec2i = GenericVector2(i32); -pub const Vec2f = GenericVector2(f32); -pub const Vec2d = GenericVector2(f64); -pub const Vec3i = GenericVector3(i32); -pub const Vec3f = extern struct {// This one gets a bit of extra functionality for rotating in 3d. - x: f32, - y: f32, - z: f32, - pub usingnamespace Vec3RotationMath(@This(), f32); - pub usingnamespace Vec3SpecificMath(@This(), f32); - pub usingnamespace GenericVectorMath(@This(), f32); +pub const Vec2i = @Vector(2, i32); +pub const Vec2f = @Vector(2, f32); +pub const Vec2d = @Vector(2, f64); +pub const Vec3i = @Vector(3, i32); +pub const Vec3f = @Vector(3, f32); +pub const Vec3d = @Vector(3, f64); +pub const Vec4i = @Vector(4, i32); +pub const Vec4f = @Vector(4, f32); +pub const Vec4d = @Vector(4, f64); - pub fn xyz(self: Vec4f) Vec3f { - return Vec3f{.x=self.x, .y=self.y, .z=self.z}; - } -}; -pub const Vec3d = GenericVector3(f64); -pub const Vec4i = GenericVector4(i32); -pub const Vec4f = GenericVector4(f32); -pub const Vec4d = GenericVector4(f64); - -fn Vec3RotationMath(comptime Vec: type, comptime T: type) type { - if(@typeInfo(Vec).Struct.fields.len == 3 and @typeInfo(T) == .Float) { - return struct{ - pub fn rotateX(self: Vec, angle: T) Vec { - const sin = @sin(angle); - const cos = @cos(angle); // TODO: Consider using sqrt here. - return Vec{ - .x = self.x, - .y = self.y*cos - self.z*sin, - .z = self.y*sin + self.z*cos, - }; - } - - pub fn rotateY(self: Vec, angle: T) Vec { - const sin = @sin(angle); - const cos = @cos(angle); // TODO: Consider using sqrt here. - return Vec{ - .x = self.x*cos + self.z*sin, - .y = self.y, - .z = -self.x*sin + self.z*cos, - }; - } - - pub fn rotateZ(self: Vec, angle: T) Vec { - const sin = @sin(angle); - const cos = @cos(angle); // TODO: Consider using sqrt here. - return Vec{ - .x = self.x*cos - self.y*sin, - .y = self.x*sin + self.y*cos, - .z = self.z, - }; - } - }; - } else { - return struct{}; - } +pub fn xyz(self: anytype) @Vector(3, @typeInfo(@TypeOf(self)).Vector.child) { + return @Vector(3, @typeInfo(@TypeOf(self)).Vector.child){self[0], self[1], self[2]}; } -fn Vec3SpecificMath(comptime Vec: type, comptime T: type) type { - _ = T; - return struct { - pub fn cross(self: Vec, other: Vec) Vec { - return Vec { - .x = self.y*other.z - self.z*other.y, - .y = self.z*other.x - self.x*other.z, - .z = self.x*other.y - self.y*other.x, - }; - } +pub fn dot(self: anytype, other: @TypeOf(self)) @typeInfo(@TypeOf(self)).Vector.child { + return @reduce(.Add, self*other); +} + +pub fn cross(self: anytype, other: @TypeOf(self)) @TypeOf(self) { + if(@typeInfo(@TypeOf(self)).Vector.len != 3) @compileError("Only available for vectors of length 3."); + return @TypeOf(self) { + self[1]*other[2] - self[2]*other[1], + self[2]*other[0] - self[0]*other[2], + self[0]*other[1] - self[1]*other[0], }; } -fn GenericVectorMath(comptime Vec: type, comptime T: type) type { - return struct { - pub fn add(self: Vec, other: Vec) Vec { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @field(self, field.name) + @field(other, field.name); - } - return result; - } - - pub fn sub(self: Vec, other: Vec) Vec { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @field(self, field.name) - @field(other, field.name); - } - return result; - } - - pub fn mul(self: Vec, other: Vec) Vec { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @field(self, field.name) * @field(other, field.name); - } - return result; - } - - pub fn mulScalar(self: Vec, scalar: T) Vec { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @field(self, field.name) * scalar; - } - return result; - } - - pub fn div(self: Vec, other: Vec) Vec { - if(@typeInfo(T) == .Float) { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @field(self, field.name) / @field(other, field.name); - } - return result; - } else { - @compileError("Not supported for integer types."); - } - } - - pub fn divScalar(self: Vec, scalar: T) Vec { - if(@typeInfo(T) == .Float) { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @field(self, field.name) / scalar; - } - return result; - } else { - @compileError("Not supported for integer types."); - } - } - - pub fn minimum(self: Vec, other: Vec) Vec { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @min(@field(self, field.name), @field(other, field.name)); - } - return result; - } - - pub fn maximum(self: Vec, other: Vec) Vec { - var result: Vec = undefined; - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(result, field.name) = @max(@field(self, field.name), @field(other, field.name)); - } - return result; - } - - pub fn addEqual(self: *Vec, other: Vec) void { - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(self, field.name) += @field(other, field.name); - } - } - - pub fn subEqual(self: *Vec, other: Vec) void { - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(self, field.name) -= @field(other, field.name); - } - } - - pub fn mulEqual(self: *Vec, other: Vec) void { - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(self, field.name) *= @field(other, field.name); - } - } - - pub fn mulEqualScalar(self: *Vec, scalar: T) void { - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(self, field.name) *= scalar; - } - } - - pub fn divEqual(self: *Vec, other: Vec) void { - if(@typeInfo(T) == .Float) { - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(self, field.name) /= @field(other, field.name); - } - } else { - @compileError("Not supported for integer types."); - } - } - - pub fn divEqualScalar(self: *Vec, scalar: T) void { - if(@typeInfo(T) == .Float) { - inline for(@typeInfo(Vec).Struct.fields) |field| { - @field(self, field.name) /= scalar; - } - } else { - @compileError("Not supported for integer types."); - } - } - - pub fn dot(self: Vec, other: Vec) T { - var result: T = 0; - inline for(@typeInfo(Vec).Struct.fields) |field| { - result += @field(self, field.name) * @field(other, field.name); - } - return result; - } +pub fn rotateX(self: anytype, angle: @typeInfo(@TypeOf(self)).Vector.child) @TypeOf(self) { + if(@typeInfo(@TypeOf(self)).Vector.len != 3) @compileError("Only available for vectors of length 3."); + const sin = @sin(angle); + const cos = @cos(angle); // TODO: Consider using sqrt here. + return @TypeOf(self){ + self[0], + self[1]*cos - self[2]*sin, + self[1]*sin + self[2]*cos, }; } -fn GenericVector2(comptime T: type) type { - return extern struct { - x: T, - y: T, - pub usingnamespace GenericVectorMath(@This(), T); +pub fn rotateY(self: anytype, angle: @typeInfo(@TypeOf(self)).Vector.child) @TypeOf(self) { + if(@typeInfo(@TypeOf(self)).Vector.len != 3) @compileError("Only available for vectors of length 3."); + const sin = @sin(angle); + const cos = @cos(angle); // TODO: Consider using sqrt here. + return @TypeOf(self){ + self[0]*cos + self[2]*sin, + self[1], + -self[0]*sin + self[2]*cos, }; } -fn GenericVector3(comptime T: type) type { - return extern struct { - x: T, - y: T, - z: T, - pub usingnamespace Vec3RotationMath(@This(), T); - pub usingnamespace Vec3SpecificMath(@This(), T); - pub usingnamespace GenericVectorMath(@This(), T); - }; -} - -fn GenericVector4(comptime T: type) type { - return extern struct { - x: T, - y: T, - z: T, - w: T, - pub usingnamespace GenericVectorMath(@This(), T); +pub fn rotateZ(self: anytype, angle: @typeInfo(@TypeOf(self)).Vector.child) @TypeOf(self) { + if(@typeInfo(@TypeOf(self)).Vector.len != 3) @compileError("Only available for vectors of length 3."); + const sin = @sin(angle); + const cos = @cos(angle); // TODO: Consider using sqrt here. + return @TypeOf(self){ + self[0]*cos - self[1]*sin, + self[0]*sin + self[1]*cos, + self[2], }; } @@ -234,10 +65,10 @@ pub const Mat4f = struct { pub fn identity() Mat4f { return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=1, .y=0, .z=0, .w=0}, - Vec4f{.x=0, .y=1, .z=0, .w=0}, - Vec4f{.x=0, .y=0, .z=1, .w=0}, - Vec4f{.x=0, .y=0, .z=0, .w=1}, + Vec4f{1, 0, 0, 0}, + Vec4f{0, 1, 0, 0}, + Vec4f{0, 0, 1, 0}, + Vec4f{0, 0, 0, 1}, } }; } @@ -245,10 +76,10 @@ pub const Mat4f = struct { pub fn translation(pos: Vec3f) Mat4f { return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=1, .y=0, .z=0, .w=0}, - Vec4f{.x=0, .y=1, .z=0, .w=0}, - Vec4f{.x=0, .y=0, .z=1, .w=0}, - Vec4f{.x=pos.x, .y=pos.y, .z=pos.z, .w=1}, + Vec4f{1, 0, 0, 0}, + Vec4f{0, 1, 0, 0}, + Vec4f{0, 0, 1, 0}, + Vec4f{pos[0], pos[1], pos[2], 1}, } }; } @@ -258,10 +89,10 @@ pub const Mat4f = struct { const c = @cos(rad); return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=1, .y=0, .z=0, .w=0}, - Vec4f{.x=0, .y=c, .z=s, .w=0}, - Vec4f{.x=0,.y=-s, .z=c, .w=0}, - Vec4f{.x=0, .y=0, .z=0, .w=1}, + Vec4f{1, 0, 0, 0}, + Vec4f{0, c, s, 0}, + Vec4f{0,-s, c, 0}, + Vec4f{0, 0, 0, 1}, } }; } @@ -271,10 +102,10 @@ pub const Mat4f = struct { const c = @cos(rad); return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=c, .y=0,.z=-s, .w=0}, - Vec4f{.x=0, .y=1, .z=0, .w=0}, - Vec4f{.x=s, .y=0, .z=c, .w=0}, - Vec4f{.x=0, .y=0, .z=0, .w=1}, + Vec4f{c, 0,-s, 0}, + Vec4f{0, 1, 0, 0}, + Vec4f{s, 0, c, 0}, + Vec4f{0, 0, 0, 1}, } }; } @@ -284,10 +115,10 @@ pub const Mat4f = struct { const c = @cos(rad); return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=c, .y=s, .z=0, .w=0}, - Vec4f{.x=-s,.y=c, .z=0, .w=0}, - Vec4f{.x=0, .y=0, .z=1, .w=0}, - Vec4f{.x=0, .y=0, .z=0, .w=1}, + Vec4f{c, s, 0, 0}, + Vec4f{-s,c, 0, 0}, + Vec4f{0, 0, 1, 0}, + Vec4f{0, 0, 0, 1}, } }; } @@ -297,10 +128,10 @@ pub const Mat4f = struct { const tanX = aspect*tanY; return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=1/tanX, .y=0, .z=0, .w=0}, - Vec4f{.x=0, .y=1/tanY, .z=0, .w=0}, - Vec4f{.x=0, .y=0, .z=(far + near)/(near - far), .w=-1}, - Vec4f{.x=0, .y=0, .z=2*near*far/(near - far), .w=0}, + Vec4f{1/tanX, 0, 0, 0}, + Vec4f{0, 1/tanY, 0, 0}, + Vec4f{0, 0, (far + near)/(near - far), -1}, + Vec4f{0, 0, 2*near*far/(near - far), 0}, } }; } @@ -308,10 +139,10 @@ pub const Mat4f = struct { pub fn transpose(self: Mat4f) Mat4f { return Mat4f { .columns = [4]Vec4f { // Keep in mind that this is the transpose! - Vec4f{.x=self.columns[0].x, .y=self.columns[1].x, .z=self.columns[2].x, .w=self.columns[3].x}, - Vec4f{.x=self.columns[0].y, .y=self.columns[1].y, .z=self.columns[2].y, .w=self.columns[3].y}, - Vec4f{.x=self.columns[0].z, .y=self.columns[1].z, .z=self.columns[2].z, .w=self.columns[3].z}, - Vec4f{.x=self.columns[0].w, .y=self.columns[1].w, .z=self.columns[2].w, .w=self.columns[3].w}, + Vec4f{self.columns[0][0], self.columns[1][0], self.columns[2][0], self.columns[3][0]}, + Vec4f{self.columns[0][1], self.columns[1][1], self.columns[2][1], self.columns[3][1]}, + Vec4f{self.columns[0][2], self.columns[1][2], self.columns[2][2], self.columns[3][2]}, + Vec4f{self.columns[0][3], self.columns[1][3], self.columns[2][3], self.columns[3][3]}, } }; } @@ -320,10 +151,10 @@ pub const Mat4f = struct { var transposeSelf = self.transpose(); var result: Mat4f = undefined; for(other.columns) |_, col| { - result.columns[col].x = transposeSelf.columns[0].dot(other.columns[col]); - result.columns[col].y = transposeSelf.columns[1].dot(other.columns[col]); - result.columns[col].z = transposeSelf.columns[2].dot(other.columns[col]); - result.columns[col].w = transposeSelf.columns[3].dot(other.columns[col]); + result.columns[col][0] = dot(transposeSelf.columns[0], other.columns[col]); + result.columns[col][1] = dot(transposeSelf.columns[1], other.columns[col]); + result.columns[col][2] = dot(transposeSelf.columns[2], other.columns[col]); + result.columns[col][3] = dot(transposeSelf.columns[3], other.columns[col]); } return result; } @@ -331,10 +162,10 @@ pub const Mat4f = struct { pub fn mulVec(self: Mat4f, vec: Vec4f) Vec4f { var transposeSelf = self.transpose(); var result: Vec4f = undefined; - result.x = transposeSelf.columns[0].dot(vec); - result.y = transposeSelf.columns[1].dot(vec); - result.z = transposeSelf.columns[2].dot(vec); - result.w = transposeSelf.columns[3].dot(vec); + result[0] = dot(transposeSelf.columns[0], vec); + result[1] = dot(transposeSelf.columns[1], vec); + result[2] = dot(transposeSelf.columns[2], vec); + result[3] = dot(transposeSelf.columns[3], vec); return result; } }; \ No newline at end of file