mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Add rotateZ
for all rotations (#1197)
* Add rotateX rotateY rotateZ for all rotations * Update src/rotation.zig * Precompute all stair rotations * Add rotateZ to Planar * Add rotate functions to Block * Fix formatting issues * No X and Y rotations * Apply suggestions from code review Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Remove z * Precompute all Z rotations * Fix Degrees enum values * Apply review suggestions * Update src/rotation.zig Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Apply review suggestions --------- Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
This commit is contained in:
parent
6f26dde472
commit
112b1dbc9f
@ -13,6 +13,7 @@ const items = @import("items.zig");
|
|||||||
const models = @import("models.zig");
|
const models = @import("models.zig");
|
||||||
const rotation = @import("rotation.zig");
|
const rotation = @import("rotation.zig");
|
||||||
const RotationMode = rotation.RotationMode;
|
const RotationMode = rotation.RotationMode;
|
||||||
|
const Degrees = rotation.Degrees;
|
||||||
const Entity = main.server.Entity;
|
const Entity = main.server.Entity;
|
||||||
|
|
||||||
pub const BlockTag = enum(u32) {
|
pub const BlockTag = enum(u32) {
|
||||||
@ -362,6 +363,10 @@ pub const Block = packed struct { // MARK: Block
|
|||||||
return _mode[self.typ];
|
return _mode[self.typ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn rotateZ(self: Block, angle: Degrees) Block {
|
||||||
|
return .{.typ = self.typ, .data = self.mode().rotateZ(self.data, angle)};
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn lodReplacement(self: Block) u16 {
|
pub inline fn lodReplacement(self: Block) u16 {
|
||||||
return _lodReplacement[self.typ];
|
return _lodReplacement[self.typ];
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,12 @@ pub const Neighbor = enum(u3) { // MARK: Neighbor
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the neighbor that is rotated by 90 degrees counterclockwise around the z axis.
|
||||||
|
pub inline fn rotateZ(self: Neighbor) Neighbor {
|
||||||
|
const arr = [_]Neighbor{.dirUp, .dirDown, .dirPosY, .dirNegY, .dirNegX, .dirPosX};
|
||||||
|
return arr[@intFromEnum(self)];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Gets the index of a given position inside this chunk.
|
/// Gets the index of a given position inside this chunk.
|
||||||
|
170
src/rotation.zig
170
src/rotation.zig
@ -18,6 +18,13 @@ const RayIntersectionResult = struct {
|
|||||||
max: Vec3f,
|
max: Vec3f,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Degrees = enum(u2) {
|
||||||
|
@"0" = 0,
|
||||||
|
@"90" = 1,
|
||||||
|
@"180" = 2,
|
||||||
|
@"270" = 3,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Why not just use a tagged union?
|
// TODO: Why not just use a tagged union?
|
||||||
/// Each block gets 16 bit of additional storage(apart from the reference to the block type).
|
/// Each block gets 16 bit of additional storage(apart from the reference to the block type).
|
||||||
/// These 16 bits are accessed and interpreted by the `RotationMode`.
|
/// These 16 bits are accessed and interpreted by the `RotationMode`.
|
||||||
@ -27,6 +34,9 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
fn model(block: Block) u16 {
|
fn model(block: Block) u16 {
|
||||||
return blocks.meshes.modelIndexStart(block);
|
return blocks.meshes.modelIndexStart(block);
|
||||||
}
|
}
|
||||||
|
fn rotateZ(data: u16, _: Degrees) u16 {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, _: *Block, _: Block, blockPlacing: bool) bool {
|
fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, _: *Block, _: Block, blockPlacing: bool) bool {
|
||||||
return blockPlacing;
|
return blockPlacing;
|
||||||
}
|
}
|
||||||
@ -112,6 +122,9 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
|
|
||||||
model: *const fn(block: Block) u16 = &DefaultFunctions.model,
|
model: *const fn(block: Block) u16 = &DefaultFunctions.model,
|
||||||
|
|
||||||
|
// Rotates block data counterclockwise around the Z axis.
|
||||||
|
rotateZ: *const fn(data: u16, angle: Degrees) u16 = DefaultFunctions.rotateZ,
|
||||||
|
|
||||||
createBlockModel: *const fn(zon: ZonElement) u16 = &DefaultFunctions.createBlockModel,
|
createBlockModel: *const fn(zon: ZonElement) u16 = &DefaultFunctions.createBlockModel,
|
||||||
|
|
||||||
/// Updates the block data of a block in the world or places a block in the world.
|
/// Updates the block data of a block in the world or places a block in the world.
|
||||||
@ -183,6 +196,21 @@ pub const RotationModes = struct {
|
|||||||
return blocks.meshes.modelIndexStart(block) + @min(block.data, 5);
|
return blocks.meshes.modelIndexStart(block) + @min(block.data, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
comptime var rotationTable: [4][6]u8 = undefined;
|
||||||
|
comptime for(0..6) |i| {
|
||||||
|
rotationTable[0][i] = i;
|
||||||
|
};
|
||||||
|
comptime for(1..4) |a| {
|
||||||
|
for(0..6) |i| {
|
||||||
|
const neighbor: Neighbor = @enumFromInt(rotationTable[a - 1][i]);
|
||||||
|
rotationTable[a][i] = neighbor.rotateZ().toInt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 6) return 0;
|
||||||
|
return rotationTable[@intFromEnum(angle)][data];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, neighbor: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, neighbor: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
||||||
if(blockPlacing) {
|
if(blockPlacing) {
|
||||||
currentData.data = neighbor.?.reverse().toInt();
|
currentData.data = neighbor.?.reverse().toInt();
|
||||||
@ -226,6 +254,21 @@ pub const RotationModes = struct {
|
|||||||
return blocks.meshes.modelIndexStart(block) + @min(block.data, 3);
|
return blocks.meshes.modelIndexStart(block) + @min(block.data, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
comptime var rotationTable: [4][4]u8 = undefined;
|
||||||
|
comptime for(0..4) |i| {
|
||||||
|
rotationTable[0][i] = i;
|
||||||
|
};
|
||||||
|
comptime for(1..4) |a| {
|
||||||
|
for(0..4) |i| {
|
||||||
|
const neighbor: Neighbor = @enumFromInt(rotationTable[a - 1][i] + 2);
|
||||||
|
rotationTable[a][i] = neighbor.rotateZ().toInt() - 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 4) return 0;
|
||||||
|
return rotationTable[@intFromEnum(angle)][data];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, playerDir: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, playerDir: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
||||||
if(blockPlacing) {
|
if(blockPlacing) {
|
||||||
if(@abs(playerDir[0]) > @abs(playerDir[1])) {
|
if(@abs(playerDir[0]) > @abs(playerDir[1])) {
|
||||||
@ -263,6 +306,27 @@ pub const RotationModes = struct {
|
|||||||
fenceModels.clearRetainingCapacity();
|
fenceModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
comptime var rotationTable: [4][16]u8 = undefined;
|
||||||
|
comptime for(0..16) |i| {
|
||||||
|
rotationTable[0][i] = @intCast(i);
|
||||||
|
};
|
||||||
|
comptime for(1..4) |a| {
|
||||||
|
for(0..16) |i| {
|
||||||
|
const old: FenceData = @bitCast(@as(u4, @intCast(rotationTable[a - 1][i])));
|
||||||
|
const new: FenceData = .{
|
||||||
|
.isConnectedNegY = old.isConnectedNegX,
|
||||||
|
.isConnectedPosY = old.isConnectedPosX,
|
||||||
|
.isConnectedPosX = old.isConnectedNegY,
|
||||||
|
.isConnectedNegX = old.isConnectedPosY,
|
||||||
|
};
|
||||||
|
rotationTable[a][i] = @as(u4, @bitCast(new));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 16) return 0;
|
||||||
|
return rotationTable[@intFromEnum(angle)][data];
|
||||||
|
}
|
||||||
|
|
||||||
fn fenceTransform(quad: *main.models.QuadInfo, data: FenceData) void {
|
fn fenceTransform(quad: *main.models.QuadInfo, data: FenceData) void {
|
||||||
for(&quad.corners, &quad.cornerUV) |*corner, *cornerUV| {
|
for(&quad.corners, &quad.cornerUV) |*corner, *cornerUV| {
|
||||||
if(!data.isConnectedNegX and corner[0] == 0) {
|
if(!data.isConnectedNegX and corner[0] == 0) {
|
||||||
@ -345,15 +409,15 @@ pub const RotationModes = struct {
|
|||||||
const BranchData = packed struct(u6) {
|
const BranchData = packed struct(u6) {
|
||||||
enabledConnections: u6,
|
enabledConnections: u6,
|
||||||
|
|
||||||
pub fn init(blockData: u16) BranchData {
|
pub inline fn init(blockData: u16) BranchData {
|
||||||
return .{.enabledConnections = @truncate(blockData)};
|
return .{.enabledConnections = @truncate(blockData)};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isConnected(self: @This(), neighbor: Neighbor) bool {
|
pub inline fn isConnected(self: @This(), neighbor: Neighbor) bool {
|
||||||
return (self.enabledConnections & Neighbor.bitMask(neighbor)) != 0;
|
return (self.enabledConnections & Neighbor.bitMask(neighbor)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setConnection(self: *@This(), neighbor: Neighbor, value: bool) void {
|
pub inline fn setConnection(self: *@This(), neighbor: Neighbor, value: bool) void {
|
||||||
if(value) {
|
if(value) {
|
||||||
self.enabledConnections |= Neighbor.bitMask(neighbor);
|
self.enabledConnections |= Neighbor.bitMask(neighbor);
|
||||||
} else {
|
} else {
|
||||||
@ -608,6 +672,32 @@ pub const RotationModes = struct {
|
|||||||
return blocks.meshes.modelIndexStart(block) + (block.data & 63);
|
return blocks.meshes.modelIndexStart(block) + (block.data & 63);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
@setEvalBranchQuota(65_536);
|
||||||
|
|
||||||
|
comptime var rotationTable: [4][16]u8 = undefined;
|
||||||
|
comptime for(0..16) |i| {
|
||||||
|
rotationTable[0][i] = @intCast(i << 2);
|
||||||
|
};
|
||||||
|
comptime for(1..4) |a| {
|
||||||
|
for(0..16) |i| {
|
||||||
|
const old: BranchData = .init(rotationTable[a - 1][i]);
|
||||||
|
var new: BranchData = .init(0);
|
||||||
|
|
||||||
|
new.setConnection(Neighbor.dirPosX.rotateZ(), old.isConnected(Neighbor.dirPosX));
|
||||||
|
new.setConnection(Neighbor.dirNegX.rotateZ(), old.isConnected(Neighbor.dirNegX));
|
||||||
|
new.setConnection(Neighbor.dirPosY.rotateZ(), old.isConnected(Neighbor.dirPosY));
|
||||||
|
new.setConnection(Neighbor.dirNegY.rotateZ(), old.isConnected(Neighbor.dirNegY));
|
||||||
|
|
||||||
|
rotationTable[a][i] = new.enabledConnections;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 0b111111) return 0;
|
||||||
|
const rotationIndex = (data & 0b111100) >> 2;
|
||||||
|
const upDownFlags = data & 0b000011;
|
||||||
|
return rotationTable[@intFromEnum(angle)][rotationIndex] | upDownFlags;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generateData(
|
pub fn generateData(
|
||||||
_: *main.game.World,
|
_: *main.game.World,
|
||||||
_: Vec3i,
|
_: Vec3i,
|
||||||
@ -712,6 +802,35 @@ pub const RotationModes = struct {
|
|||||||
return stairData & subBlockMask(x, y, z) == 0;
|
return stairData & subBlockMask(x, y, z) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
@setEvalBranchQuota(65_536);
|
||||||
|
|
||||||
|
comptime var rotationTable: [4][256]u8 = undefined;
|
||||||
|
comptime for(0..4) |a| {
|
||||||
|
for(0..256) |old| {
|
||||||
|
var new: u8 = 0;
|
||||||
|
|
||||||
|
for(0..2) |i| for(0..2) |j| for(0..2) |k| {
|
||||||
|
const sin: f32 = @sin((std.math.pi/2.0)*@as(f32, @floatFromInt(a)));
|
||||||
|
const cos: f32 = @cos((std.math.pi/2.0)*@as(f32, @floatFromInt(a)));
|
||||||
|
|
||||||
|
const x: f32 = (@as(f32, @floatFromInt(i)) - 0.5)*2.0;
|
||||||
|
const y: f32 = (@as(f32, @floatFromInt(j)) - 0.5)*2.0;
|
||||||
|
|
||||||
|
const rX = @intFromBool(x*cos - y*sin > 0);
|
||||||
|
const rY = @intFromBool(x*sin + y*cos > 0);
|
||||||
|
|
||||||
|
if(hasSubBlock(@intCast(old), @intCast(i), @intCast(j), @intCast(k))) {
|
||||||
|
new |= subBlockMask(rX, rY, @intCast(k));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rotationTable[a][old] = new;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 256) return 0;
|
||||||
|
return rotationTable[@intFromEnum(angle)][data];
|
||||||
|
}
|
||||||
|
|
||||||
fn init() void {}
|
fn init() void {}
|
||||||
fn deinit() void {}
|
fn deinit() void {}
|
||||||
fn reset() void {
|
fn reset() void {
|
||||||
@ -1088,6 +1207,28 @@ pub const RotationModes = struct {
|
|||||||
return blocks.meshes.modelIndexStart(block) + (@as(u5, @truncate(block.data)) -| 1);
|
return blocks.meshes.modelIndexStart(block) + (@as(u5, @truncate(block.data)) -| 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
comptime var rotationTable: [4][32]u8 = undefined;
|
||||||
|
comptime for(0..32) |i| {
|
||||||
|
rotationTable[0][i] = @intCast(i);
|
||||||
|
};
|
||||||
|
comptime for(1..4) |a| {
|
||||||
|
for(0..32) |i| {
|
||||||
|
const old: TorchData = @bitCast(@as(u5, @intCast(rotationTable[a - 1][i])));
|
||||||
|
const new: TorchData = .{
|
||||||
|
.center = old.center,
|
||||||
|
.negY = old.negX,
|
||||||
|
.posY = old.posX,
|
||||||
|
.posX = old.negY,
|
||||||
|
.negX = old.posY,
|
||||||
|
};
|
||||||
|
rotationTable[a][i] = @as(u5, @bitCast(new));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 32) return 0;
|
||||||
|
return rotationTable[@intFromEnum(angle)][data];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, relativeDir: Vec3i, neighbor: ?Neighbor, currentData: *Block, neighborBlock: Block, _: bool) bool {
|
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, relativeDir: Vec3i, neighbor: ?Neighbor, currentData: *Block, neighborBlock: Block, _: bool) bool {
|
||||||
if(neighbor == null) return false;
|
if(neighbor == null) return false;
|
||||||
const neighborModel = blocks.meshes.model(neighborBlock);
|
const neighborModel = blocks.meshes.model(neighborBlock);
|
||||||
@ -1192,6 +1333,29 @@ pub const RotationModes = struct {
|
|||||||
posZ: bool,
|
posZ: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
|
comptime var rotationTable: [4][64]u8 = undefined;
|
||||||
|
comptime for(0..64) |i| {
|
||||||
|
rotationTable[0][i] = @intCast(i);
|
||||||
|
};
|
||||||
|
comptime for(1..4) |a| {
|
||||||
|
for(0..64) |i| {
|
||||||
|
const old: CarpetData = @bitCast(@as(u6, @intCast(rotationTable[a - 1][i])));
|
||||||
|
const new: CarpetData = .{
|
||||||
|
.posZ = old.posZ,
|
||||||
|
.negZ = old.negZ,
|
||||||
|
.posY = old.posX,
|
||||||
|
.negY = old.negX,
|
||||||
|
.negX = old.posY,
|
||||||
|
.posX = old.negY,
|
||||||
|
};
|
||||||
|
rotationTable[a][i] = @as(u6, @bitCast(new));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(data >= 64) return 0;
|
||||||
|
return rotationTable[@intFromEnum(angle)][data];
|
||||||
|
}
|
||||||
|
|
||||||
fn init() void {
|
fn init() void {
|
||||||
rotatedModels = .init(main.globalAllocator.allocator);
|
rotatedModels = .init(main.globalAllocator.allocator);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user