mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-08 19:50:23 -04:00
Use a dedicated ModelIndex and QuadIndex to make more clear what it is and how to use it.
I also bumped model index size to 32 bits (storage is currently limited to 20 bits though) We can afford this, since it's CPU side and it's only stored perblock type.
This commit is contained in:
parent
37eb01ec37
commit
01cfb786aa
@ -11,6 +11,7 @@ const Color = graphics.Color;
|
|||||||
const TextureArray = graphics.TextureArray;
|
const TextureArray = graphics.TextureArray;
|
||||||
const items = @import("items.zig");
|
const items = @import("items.zig");
|
||||||
const models = @import("models.zig");
|
const models = @import("models.zig");
|
||||||
|
const ModelIndex = models.ModelIndex;
|
||||||
const rotation = @import("rotation.zig");
|
const rotation = @import("rotation.zig");
|
||||||
const RotationMode = rotation.RotationMode;
|
const RotationMode = rotation.RotationMode;
|
||||||
const Degrees = rotation.Degrees;
|
const Degrees = rotation.Degrees;
|
||||||
@ -436,7 +437,7 @@ pub const meshes = struct { // MARK: meshes
|
|||||||
fogColor: u32,
|
fogColor: u32,
|
||||||
};
|
};
|
||||||
var size: u32 = 0;
|
var size: u32 = 0;
|
||||||
var _modelIndex: [maxBlockCount]u16 = undefined;
|
var _modelIndex: [maxBlockCount]ModelIndex = undefined;
|
||||||
var textureData: [maxBlockCount]TextureData = undefined;
|
var textureData: [maxBlockCount]TextureData = undefined;
|
||||||
/// Stores the number of textures after each block was added. Used to clean additional textures when the world is switched.
|
/// Stores the number of textures after each block was added. Used to clean additional textures when the world is switched.
|
||||||
var maxTextureCount: [maxBlockCount]u32 = undefined;
|
var maxTextureCount: [maxBlockCount]u32 = undefined;
|
||||||
@ -546,11 +547,11 @@ pub const meshes = struct { // MARK: meshes
|
|||||||
_ = arenaForWorld.reset(.free_all);
|
_ = arenaForWorld.reset(.free_all);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn model(block: Block) u16 {
|
pub inline fn model(block: Block) ModelIndex {
|
||||||
return block.mode().model(block);
|
return block.mode().model(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn modelIndexStart(block: Block) u16 {
|
pub inline fn modelIndexStart(block: Block) ModelIndex {
|
||||||
return _modelIndex[block.typ];
|
return _modelIndex[block.typ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/game.zig
16
src/game.zig
@ -154,13 +154,13 @@ pub const collision = struct {
|
|||||||
var resultBox: ?Box = null;
|
var resultBox: ?Box = null;
|
||||||
var minDistance: f64 = std.math.floatMax(f64);
|
var minDistance: f64 = std.math.floatMax(f64);
|
||||||
if(block.collide()) {
|
if(block.collide()) {
|
||||||
const model = &models.models.items[block.mode().model(block)];
|
const model = block.mode().model(block).model();
|
||||||
|
|
||||||
const pos = Vec3d{@floatFromInt(x), @floatFromInt(y), @floatFromInt(z)};
|
const pos = Vec3d{@floatFromInt(x), @floatFromInt(y), @floatFromInt(z)};
|
||||||
|
|
||||||
for(model.neighborFacingQuads) |quads| {
|
for(model.neighborFacingQuads) |quads| {
|
||||||
for(quads) |quadIndex| {
|
for(quads) |quadIndex| {
|
||||||
const quad = &models.quads.items[quadIndex];
|
const quad = quadIndex.quadInfo();
|
||||||
if(triangleAABB(.{quad.corners[0] + quad.normal + pos, quad.corners[2] + quad.normal + pos, quad.corners[1] + quad.normal + pos}, entityPosition, entityBoundingBoxExtent)) {
|
if(triangleAABB(.{quad.corners[0] + quad.normal + pos, quad.corners[2] + quad.normal + pos, quad.corners[1] + quad.normal + pos}, entityPosition, entityBoundingBoxExtent)) {
|
||||||
const min = @min(@min(quad.corners[0], quad.corners[1]), @min(quad.corners[2], quad.corners[3])) + quad.normal + pos;
|
const min = @min(@min(quad.corners[0], quad.corners[1]), @min(quad.corners[2], quad.corners[3])) + quad.normal + pos;
|
||||||
const max = @max(@max(quad.corners[0], quad.corners[1]), @max(quad.corners[2], quad.corners[3])) + quad.normal + pos;
|
const max = @max(@max(quad.corners[0], quad.corners[1]), @max(quad.corners[2], quad.corners[3])) + quad.normal + pos;
|
||||||
@ -189,7 +189,7 @@ pub const collision = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(model.internalQuads) |quadIndex| {
|
for(model.internalQuads) |quadIndex| {
|
||||||
const quad = &models.quads.items[quadIndex];
|
const quad = quadIndex.quadInfo();
|
||||||
if(triangleAABB(.{quad.corners[0] + pos, quad.corners[2] + pos, quad.corners[1] + pos}, entityPosition, entityBoundingBoxExtent)) {
|
if(triangleAABB(.{quad.corners[0] + pos, quad.corners[2] + pos, quad.corners[1] + pos}, entityPosition, entityBoundingBoxExtent)) {
|
||||||
const min = @min(@min(quad.corners[0], quad.corners[1]), @min(quad.corners[2], quad.corners[3])) + pos;
|
const min = @min(@min(quad.corners[0], quad.corners[1]), @min(quad.corners[2], quad.corners[3])) + pos;
|
||||||
const max = @max(@max(quad.corners[0], quad.corners[1]), @max(quad.corners[2], quad.corners[3])) + pos;
|
const max = @max(@max(quad.corners[0], quad.corners[1]), @max(quad.corners[2], quad.corners[3])) + pos;
|
||||||
@ -303,8 +303,8 @@ pub const collision = struct {
|
|||||||
const blockPos: Vec3d = .{@floatFromInt(x), @floatFromInt(y), @floatFromInt(z)};
|
const blockPos: Vec3d = .{@floatFromInt(x), @floatFromInt(y), @floatFromInt(z)};
|
||||||
|
|
||||||
const blockBox: Box = .{
|
const blockBox: Box = .{
|
||||||
.min = blockPos + @as(Vec3d, @floatCast(main.models.models.items[block.mode().model(block)].min)),
|
.min = blockPos + @as(Vec3d, @floatCast(block.mode().model(block).model().min)),
|
||||||
.max = blockPos + @as(Vec3d, @floatCast(main.models.models.items[block.mode().model(block)].max)),
|
.max = blockPos + @as(Vec3d, @floatCast(block.mode().model(block).model().max)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if(boundingBox.min[2] > blockBox.max[2] or boundingBox.max[2] < blockBox.min[2]) {
|
if(boundingBox.min[2] > blockBox.max[2] or boundingBox.max[2] < blockBox.min[2]) {
|
||||||
@ -365,17 +365,17 @@ pub const collision = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn isBlockIntersecting(block: Block, posX: i32, posY: i32, posZ: i32, center: Vec3d, extent: Vec3d) bool {
|
fn isBlockIntersecting(block: Block, posX: i32, posY: i32, posZ: i32, center: Vec3d, extent: Vec3d) bool {
|
||||||
const model = &models.models.items[block.mode().model(block)];
|
const model = block.mode().model(block).model();
|
||||||
const position = Vec3d{@floatFromInt(posX), @floatFromInt(posY), @floatFromInt(posZ)};
|
const position = Vec3d{@floatFromInt(posX), @floatFromInt(posY), @floatFromInt(posZ)};
|
||||||
for(model.neighborFacingQuads) |quads| {
|
for(model.neighborFacingQuads) |quads| {
|
||||||
for(quads) |quadIndex| {
|
for(quads) |quadIndex| {
|
||||||
const quad = &models.quads.items[quadIndex];
|
const quad = quadIndex.quadInfo();
|
||||||
if(triangleAABB(.{quad.corners[0] + quad.normal + position, quad.corners[2] + quad.normal + position, quad.corners[1] + quad.normal + position}, center, extent) or
|
if(triangleAABB(.{quad.corners[0] + quad.normal + position, quad.corners[2] + quad.normal + position, quad.corners[1] + quad.normal + position}, center, extent) or
|
||||||
triangleAABB(.{quad.corners[1] + quad.normal + position, quad.corners[2] + quad.normal + position, quad.corners[3] + quad.normal + position}, center, extent)) return true;
|
triangleAABB(.{quad.corners[1] + quad.normal + position, quad.corners[2] + quad.normal + position, quad.corners[3] + quad.normal + position}, center, extent)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(model.internalQuads) |quadIndex| {
|
for(model.internalQuads) |quadIndex| {
|
||||||
const quad = &models.quads.items[quadIndex];
|
const quad = quadIndex.quadInfo();
|
||||||
if(triangleAABB(.{quad.corners[0] + position, quad.corners[2] + position, quad.corners[1] + position}, center, extent) or
|
if(triangleAABB(.{quad.corners[0] + position, quad.corners[2] + position, quad.corners[1] + position}, center, extent) or
|
||||||
triangleAABB(.{quad.corners[1] + position, quad.corners[2] + position, quad.corners[3] + position}, center, extent)) return true;
|
triangleAABB(.{quad.corners[1] + position, quad.corners[2] + position, quad.corners[3] + position}, center, extent)) return true;
|
||||||
}
|
}
|
||||||
|
@ -2081,7 +2081,7 @@ pub fn generateBlockTexture(blockType: u16) Texture {
|
|||||||
|
|
||||||
var faceData: main.ListUnmanaged(main.renderer.chunk_meshing.FaceData) = .{};
|
var faceData: main.ListUnmanaged(main.renderer.chunk_meshing.FaceData) = .{};
|
||||||
defer faceData.deinit(main.stackAllocator);
|
defer faceData.deinit(main.stackAllocator);
|
||||||
const model = &main.models.models.items[main.blocks.meshes.model(block)];
|
const model = main.blocks.meshes.model(block).model();
|
||||||
if(block.hasBackFace()) {
|
if(block.hasBackFace()) {
|
||||||
model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, 1, 1, 1, true);
|
model.appendInternalQuadsToList(&faceData, main.stackAllocator, block, 1, 1, 1, true);
|
||||||
for(main.chunk.Neighbor.iterable) |neighbor| {
|
for(main.chunk.Neighbor.iterable) |neighbor| {
|
||||||
|
@ -571,19 +571,18 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer
|
|||||||
// Find sizes and free index:
|
// Find sizes and free index:
|
||||||
var block = blocks.Block{.typ = self.item.baseItem.block.?, .data = 0};
|
var block = blocks.Block{.typ = self.item.baseItem.block.?, .data = 0};
|
||||||
block.data = block.mode().naturalStandard;
|
block.data = block.mode().naturalStandard;
|
||||||
const modelIndex = blocks.meshes.model(block);
|
const model = blocks.meshes.model(block).model();
|
||||||
const model = &main.models.models.items[modelIndex];
|
|
||||||
var data = main.List(u32).init(main.stackAllocator);
|
var data = main.List(u32).init(main.stackAllocator);
|
||||||
defer data.deinit();
|
defer data.deinit();
|
||||||
for(model.internalQuads) |quad| {
|
for(model.internalQuads) |quad| {
|
||||||
const textureIndex = blocks.meshes.textureIndex(block, main.models.quads.items[quad].textureSlot);
|
const textureIndex = blocks.meshes.textureIndex(block, quad.quadInfo().textureSlot);
|
||||||
data.append(@as(u32, quad) << 16 | textureIndex); // modelAndTexture
|
data.append(@as(u32, quad.index) << 16 | textureIndex); // modelAndTexture
|
||||||
data.append(0); // offsetByNormal
|
data.append(0); // offsetByNormal
|
||||||
}
|
}
|
||||||
for(model.neighborFacingQuads) |list| {
|
for(model.neighborFacingQuads) |list| {
|
||||||
for(list) |quad| {
|
for(list) |quad| {
|
||||||
const textureIndex = blocks.meshes.textureIndex(block, main.models.quads.items[quad].textureSlot);
|
const textureIndex = blocks.meshes.textureIndex(block, quad.quadInfo().textureSlot);
|
||||||
data.append(@as(u32, quad) << 16 | textureIndex); // modelAndTexture
|
data.append(@as(u32, quad.index) << 16 | textureIndex); // modelAndTexture
|
||||||
data.append(1); // offsetByNormal
|
data.append(1); // offsetByNormal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,11 +49,31 @@ const Quad = struct {
|
|||||||
uvs: [4]usize,
|
uvs: [4]usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ModelIndex = packed struct {
|
||||||
|
index: u32,
|
||||||
|
|
||||||
|
pub fn model(self: ModelIndex) *const Model {
|
||||||
|
return &models.items()[self.index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const QuadIndex = packed struct {
|
||||||
|
index: u16,
|
||||||
|
|
||||||
|
pub fn quadInfo(self: QuadIndex) *const QuadInfo {
|
||||||
|
return &quads.items[self.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extraQuadInfo(self: QuadIndex) *const ExtraQuadInfo {
|
||||||
|
return &extraQuadInfos.items[self.index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const Model = struct {
|
pub const Model = struct {
|
||||||
min: Vec3f,
|
min: Vec3f,
|
||||||
max: Vec3f,
|
max: Vec3f,
|
||||||
internalQuads: []u16,
|
internalQuads: []QuadIndex,
|
||||||
neighborFacingQuads: [6][]u16,
|
neighborFacingQuads: [6][]QuadIndex,
|
||||||
isNeighborOccluded: [6]bool,
|
isNeighborOccluded: [6]bool,
|
||||||
allNeighborsOccluded: bool,
|
allNeighborsOccluded: bool,
|
||||||
noNeighborsOccluded: bool,
|
noNeighborsOccluded: bool,
|
||||||
@ -88,7 +108,7 @@ pub const Model = struct {
|
|||||||
return @popCount(@as(u3, @bitCast(hasTwoOnes))) == 2 and @popCount(@as(u3, @bitCast(hasTwoZeroes))) == 2;
|
return @popCount(@as(u3, @bitCast(hasTwoOnes))) == 2 and @popCount(@as(u3, @bitCast(hasTwoZeroes))) == 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(quadInfos: []const QuadInfo) u16 {
|
pub fn init(quadInfos: []const QuadInfo) ModelIndex {
|
||||||
const adjustedQuads = main.stackAllocator.alloc(QuadInfo, quadInfos.len);
|
const adjustedQuads = main.stackAllocator.alloc(QuadInfo, quadInfos.len);
|
||||||
defer main.stackAllocator.free(adjustedQuads);
|
defer main.stackAllocator.free(adjustedQuads);
|
||||||
for(adjustedQuads, quadInfos) |*dest, *src| {
|
for(adjustedQuads, quadInfos) |*dest, *src| {
|
||||||
@ -103,7 +123,7 @@ pub const Model = struct {
|
|||||||
// Snap the normals as well:
|
// Snap the normals as well:
|
||||||
dest.normal = snapToGrid(dest.normal);
|
dest.normal = snapToGrid(dest.normal);
|
||||||
}
|
}
|
||||||
const modelIndex: u16 = @intCast(models.items.len);
|
const modelIndex: ModelIndex = .{.index = models.len};
|
||||||
const self = models.addOne();
|
const self = models.addOne();
|
||||||
var amounts: [6]usize = .{0, 0, 0, 0, 0, 0};
|
var amounts: [6]usize = .{0, 0, 0, 0, 0, 0};
|
||||||
var internalAmount: usize = 0;
|
var internalAmount: usize = 0;
|
||||||
@ -123,9 +143,9 @@ pub const Model = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(0..6) |i| {
|
for(0..6) |i| {
|
||||||
self.neighborFacingQuads[i] = main.globalAllocator.alloc(u16, amounts[i]);
|
self.neighborFacingQuads[i] = main.globalAllocator.alloc(QuadIndex, amounts[i]);
|
||||||
}
|
}
|
||||||
self.internalQuads = main.globalAllocator.alloc(u16, internalAmount);
|
self.internalQuads = main.globalAllocator.alloc(QuadIndex, internalAmount);
|
||||||
|
|
||||||
var indices: [6]usize = .{0, 0, 0, 0, 0, 0};
|
var indices: [6]usize = .{0, 0, 0, 0, 0, 0};
|
||||||
var internalIndex: usize = 0;
|
var internalIndex: usize = 0;
|
||||||
@ -153,7 +173,7 @@ pub const Model = struct {
|
|||||||
self.noNeighborsOccluded = true;
|
self.noNeighborsOccluded = true;
|
||||||
for(0..6) |neighbor| {
|
for(0..6) |neighbor| {
|
||||||
for(self.neighborFacingQuads[neighbor]) |quad| {
|
for(self.neighborFacingQuads[neighbor]) |quad| {
|
||||||
if(fullyOccludesNeighbor(&quads.items[quad])) {
|
if(fullyOccludesNeighbor(quad.quadInfo())) {
|
||||||
self.isNeighborOccluded[neighbor] = true;
|
self.isNeighborOccluded[neighbor] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,7 +196,7 @@ pub const Model = struct {
|
|||||||
return ind;
|
return ind;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loadModel(data: []const u8) u16 {
|
pub fn loadModel(data: []const u8) ModelIndex {
|
||||||
const quadInfos = loadRawModelDataFromObj(main.stackAllocator, data);
|
const quadInfos = loadRawModelDataFromObj(main.stackAllocator, data);
|
||||||
defer main.stackAllocator.free(quadInfos);
|
defer main.stackAllocator.free(quadInfos);
|
||||||
for(quadInfos) |*quad| {
|
for(quadInfos) |*quad| {
|
||||||
@ -364,11 +384,11 @@ pub const Model = struct {
|
|||||||
|
|
||||||
pub fn getRawFaces(model: Model, quadList: *main.List(QuadInfo)) void {
|
pub fn getRawFaces(model: Model, quadList: *main.List(QuadInfo)) void {
|
||||||
for(model.internalQuads) |quadIndex| {
|
for(model.internalQuads) |quadIndex| {
|
||||||
quadList.append(quads.items[quadIndex]);
|
quadList.append(quadIndex.quadInfo().*);
|
||||||
}
|
}
|
||||||
for(0..6) |neighbor| {
|
for(0..6) |neighbor| {
|
||||||
for(model.neighborFacingQuads[neighbor]) |quadIndex| {
|
for(model.neighborFacingQuads[neighbor]) |quadIndex| {
|
||||||
var quad = quads.items[quadIndex];
|
var quad = quadIndex.quadInfo().*;
|
||||||
for(&quad.corners) |*corner| {
|
for(&quad.corners) |*corner| {
|
||||||
corner.* += quad.normal;
|
corner.* += quad.normal;
|
||||||
}
|
}
|
||||||
@ -377,16 +397,16 @@ pub const Model = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mergeModels(modelList: []u16) u16 {
|
pub fn mergeModels(modelList: []ModelIndex) ModelIndex {
|
||||||
var quadList = main.List(QuadInfo).init(main.stackAllocator);
|
var quadList = main.List(QuadInfo).init(main.stackAllocator);
|
||||||
defer quadList.deinit();
|
defer quadList.deinit();
|
||||||
for(modelList) |model| {
|
for(modelList) |model| {
|
||||||
models.items[model].getRawFaces(&quadList);
|
model.model().getRawFaces(&quadList);
|
||||||
}
|
}
|
||||||
return Model.init(quadList.items);
|
return Model.init(quadList.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transformModel(model: Model, transformFunction: anytype, transformFunctionParameters: anytype) u16 {
|
pub fn transformModel(model: Model, transformFunction: anytype, transformFunctionParameters: anytype) ModelIndex {
|
||||||
var quadList = main.List(QuadInfo).init(main.stackAllocator);
|
var quadList = main.List(QuadInfo).init(main.stackAllocator);
|
||||||
defer quadList.deinit();
|
defer quadList.deinit();
|
||||||
model.getRawFaces(&quadList);
|
model.getRawFaces(&quadList);
|
||||||
@ -396,9 +416,9 @@ pub const Model = struct {
|
|||||||
return Model.init(quadList.items);
|
return Model.init(quadList.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appendQuadsToList(quadList: []const u16, list: *main.ListUnmanaged(FaceData), allocator: NeverFailingAllocator, block: main.blocks.Block, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
fn appendQuadsToList(quadList: []const QuadIndex, list: *main.ListUnmanaged(FaceData), allocator: NeverFailingAllocator, block: main.blocks.Block, x: i32, y: i32, z: i32, comptime backFace: bool) void {
|
||||||
for(quadList) |quadIndex| {
|
for(quadList) |quadIndex| {
|
||||||
const texture = main.blocks.meshes.textureIndex(block, quads.items[quadIndex].textureSlot);
|
const texture = main.blocks.meshes.textureIndex(block, quadIndex.quadInfo().textureSlot);
|
||||||
list.append(allocator, FaceData.init(texture, quadIndex, x, y, z, backFace));
|
list.append(allocator, FaceData.init(texture, quadIndex, x, y, z, backFace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,22 +432,22 @@ pub const Model = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var nameToIndex: std.StringHashMap(u16) = undefined;
|
var nameToIndex: std.StringHashMap(ModelIndex) = undefined;
|
||||||
|
|
||||||
pub fn getModelIndex(string: []const u8) u16 {
|
pub fn getModelIndex(string: []const u8) ModelIndex {
|
||||||
return nameToIndex.get(string) orelse {
|
return nameToIndex.get(string) orelse {
|
||||||
std.log.err("Couldn't find voxelModel with name: {s}.", .{string});
|
std.log.err("Couldn't find voxelModel with name: {s}.", .{string});
|
||||||
return 0;
|
return .{.index = 0};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub var quads: main.List(QuadInfo) = undefined;
|
var quads: main.List(QuadInfo) = undefined;
|
||||||
pub var extraQuadInfos: main.List(ExtraQuadInfo) = undefined;
|
var extraQuadInfos: main.List(ExtraQuadInfo) = undefined;
|
||||||
pub var models: main.List(Model) = undefined;
|
var models: main.VirtualList(Model, 1 << 20) = undefined;
|
||||||
|
|
||||||
var quadDeduplication: std.AutoHashMap([@sizeOf(QuadInfo)]u8, u16) = undefined;
|
var quadDeduplication: std.AutoHashMap([@sizeOf(QuadInfo)]u8, QuadIndex) = undefined;
|
||||||
|
|
||||||
fn addQuad(info_: QuadInfo) error{Degenerate}!u16 {
|
fn addQuad(info_: QuadInfo) error{Degenerate}!QuadIndex {
|
||||||
var info = info_;
|
var info = info_;
|
||||||
if(quadDeduplication.get(std.mem.toBytes(info))) |id| {
|
if(quadDeduplication.get(std.mem.toBytes(info))) |id| {
|
||||||
return id;
|
return id;
|
||||||
@ -440,7 +460,7 @@ fn addQuad(info_: QuadInfo) error{Degenerate}!u16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cornerEqualities >= 2) return error.Degenerate; // One corner equality is fine, since then the quad degenerates to a triangle, which has a non-zero area.
|
if(cornerEqualities >= 2) return error.Degenerate; // One corner equality is fine, since then the quad degenerates to a triangle, which has a non-zero area.
|
||||||
const index: u16 = @intCast(quads.items.len);
|
const index: QuadIndex = .{.index = @intCast(quads.items.len)};
|
||||||
if(info.opaqueInLod == 2) {
|
if(info.opaqueInLod == 2) {
|
||||||
info.opaqueInLod = 0;
|
info.opaqueInLod = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -534,7 +554,7 @@ fn openBox(min: Vec3f, max: Vec3f, uvOffset: Vec2f, openSide: enum {x, y, z}) [4
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registerModel(id: []const u8, data: []const u8) u16 {
|
pub fn registerModel(id: []const u8, data: []const u8) ModelIndex {
|
||||||
const model = Model.loadModel(data);
|
const model = Model.loadModel(data);
|
||||||
nameToIndex.put(id, model) catch unreachable;
|
nameToIndex.put(id, model) catch unreachable;
|
||||||
return model;
|
return model;
|
||||||
@ -542,7 +562,7 @@ pub fn registerModel(id: []const u8, data: []const u8) u16 {
|
|||||||
|
|
||||||
// TODO: Entity models.
|
// TODO: Entity models.
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
models = .init(main.globalAllocator);
|
models = .init();
|
||||||
quads = .init(main.globalAllocator);
|
quads = .init(main.globalAllocator);
|
||||||
extraQuadInfos = .init(main.globalAllocator);
|
extraQuadInfos = .init(main.globalAllocator);
|
||||||
quadDeduplication = .init(main.globalAllocator.allocator);
|
quadDeduplication = .init(main.globalAllocator.allocator);
|
||||||
@ -553,7 +573,7 @@ pub fn init() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset() void {
|
pub fn reset() void {
|
||||||
for(models.items) |model| {
|
for(models.items()) |model| {
|
||||||
model.deinit();
|
model.deinit();
|
||||||
}
|
}
|
||||||
models.clearRetainingCapacity();
|
models.clearRetainingCapacity();
|
||||||
@ -567,7 +587,7 @@ pub fn reset() void {
|
|||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
quadSSBO.deinit();
|
quadSSBO.deinit();
|
||||||
nameToIndex.deinit();
|
nameToIndex.deinit();
|
||||||
for(models.items) |model| {
|
for(models.items()) |model| {
|
||||||
model.deinit();
|
model.deinit();
|
||||||
}
|
}
|
||||||
models.deinit();
|
models.deinit();
|
||||||
|
@ -7,6 +7,7 @@ const Block = blocks.Block;
|
|||||||
const chunk = main.chunk;
|
const chunk = main.chunk;
|
||||||
const game = main.game;
|
const game = main.game;
|
||||||
const models = main.models;
|
const models = main.models;
|
||||||
|
const QuadIndex = models.QuadIndex;
|
||||||
const renderer = main.renderer;
|
const renderer = main.renderer;
|
||||||
const graphics = main.graphics;
|
const graphics = main.graphics;
|
||||||
const c = graphics.c;
|
const c = graphics.c;
|
||||||
@ -252,10 +253,10 @@ pub const FaceData = extern struct {
|
|||||||
},
|
},
|
||||||
blockAndQuad: packed struct(u32) {
|
blockAndQuad: packed struct(u32) {
|
||||||
texture: u16,
|
texture: u16,
|
||||||
quadIndex: u16,
|
quadIndex: QuadIndex,
|
||||||
},
|
},
|
||||||
|
|
||||||
pub inline fn init(texture: u16, quadIndex: u16, x: i32, y: i32, z: i32, comptime backFace: bool) FaceData {
|
pub inline fn init(texture: u16, quadIndex: QuadIndex, x: i32, y: i32, z: i32, comptime backFace: bool) FaceData {
|
||||||
return FaceData{
|
return FaceData{
|
||||||
.position = .{.x = @intCast(x), .y = @intCast(y), .z = @intCast(z), .isBackFace = backFace},
|
.position = .{.x = @intCast(x), .y = @intCast(y), .z = @intCast(z), .isBackFace = backFace},
|
||||||
.blockAndQuad = .{.texture = texture, .quadIndex = quadIndex},
|
.blockAndQuad = .{.texture = texture, .quadIndex = quadIndex},
|
||||||
@ -349,7 +350,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
@floatFromInt(face.position.y),
|
@floatFromInt(face.position.y),
|
||||||
@floatFromInt(face.position.z),
|
@floatFromInt(face.position.z),
|
||||||
};
|
};
|
||||||
for(main.models.quads.items[face.blockAndQuad.quadIndex].corners) |cornerPos| {
|
for(face.blockAndQuad.quadIndex.quadInfo().corners) |cornerPos| {
|
||||||
self.min = @min(self.min, basePos + cornerPos);
|
self.min = @min(self.min, basePos + cornerPos);
|
||||||
self.max = @max(self.max, basePos + cornerPos);
|
self.max = @max(self.max, basePos + cornerPos);
|
||||||
}
|
}
|
||||||
@ -455,8 +456,10 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getLight(parent: *ChunkMesh, blockPos: Vec3i, textureIndex: u16, quadIndex: u16) [4]u32 {
|
fn getLight(parent: *ChunkMesh, blockPos: Vec3i, textureIndex: u16, quadIndex: QuadIndex) [4]u32 {
|
||||||
const normal = models.quads.items[quadIndex].normal;
|
const quadInfo = quadIndex.quadInfo();
|
||||||
|
const extraQuadInfo = quadIndex.extraQuadInfo();
|
||||||
|
const normal = quadInfo.normal;
|
||||||
if(!blocks.meshes.textureOcclusionData.items[textureIndex]) { // No ambient occlusion (→ no smooth lighting)
|
if(!blocks.meshes.textureOcclusionData.items[textureIndex]) { // No ambient occlusion (→ no smooth lighting)
|
||||||
const fullValues = getLightAt(parent, blockPos[0], blockPos[1], blockPos[2]);
|
const fullValues = getLightAt(parent, blockPos[0], blockPos[1], blockPos[2]);
|
||||||
var rawVals: [6]u5 = undefined;
|
var rawVals: [6]u5 = undefined;
|
||||||
@ -465,12 +468,12 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
}
|
}
|
||||||
return packLightValues(@splat(rawVals));
|
return packLightValues(@splat(rawVals));
|
||||||
}
|
}
|
||||||
if(models.extraQuadInfos.items[quadIndex].hasOnlyCornerVertices) { // Fast path for simple quads.
|
if(extraQuadInfo.hasOnlyCornerVertices) { // Fast path for simple quads.
|
||||||
var rawVals: [4][6]u5 = undefined;
|
var rawVals: [4][6]u5 = undefined;
|
||||||
for(0..4) |i| {
|
for(0..4) |i| {
|
||||||
const vertexPos = models.quads.items[quadIndex].corners[i];
|
const vertexPos = quadInfo.corners[i];
|
||||||
const fullPos = blockPos +% @as(Vec3i, @intFromFloat(vertexPos));
|
const fullPos = blockPos +% @as(Vec3i, @intFromFloat(vertexPos));
|
||||||
const fullValues = if(models.extraQuadInfos.items[quadIndex].alignedNormalDirection) |dir|
|
const fullValues = if(extraQuadInfo.alignedNormalDirection) |dir|
|
||||||
getCornerLightAligned(parent, fullPos, dir)
|
getCornerLightAligned(parent, fullPos, dir)
|
||||||
else
|
else
|
||||||
getCornerLight(parent, fullPos, normal);
|
getCornerLight(parent, fullPos, normal);
|
||||||
@ -488,7 +491,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
while(dy <= 1) : (dy += 1) {
|
while(dy <= 1) : (dy += 1) {
|
||||||
var dz: u31 = 0;
|
var dz: u31 = 0;
|
||||||
while(dz <= 1) : (dz += 1) {
|
while(dz <= 1) : (dz += 1) {
|
||||||
cornerVals[dx][dy][dz] = if(models.extraQuadInfos.items[quadIndex].alignedNormalDirection) |dir|
|
cornerVals[dx][dy][dz] = if(extraQuadInfo.alignedNormalDirection) |dir|
|
||||||
getCornerLightAligned(parent, blockPos +% Vec3i{dx, dy, dz}, dir)
|
getCornerLightAligned(parent, blockPos +% Vec3i{dx, dy, dz}, dir)
|
||||||
else
|
else
|
||||||
getCornerLight(parent, blockPos +% Vec3i{dx, dy, dz}, normal);
|
getCornerLight(parent, blockPos +% Vec3i{dx, dy, dz}, normal);
|
||||||
@ -498,7 +501,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
}
|
}
|
||||||
var rawVals: [4][6]u5 = undefined;
|
var rawVals: [4][6]u5 = undefined;
|
||||||
for(0..4) |i| {
|
for(0..4) |i| {
|
||||||
const vertexPos = models.quads.items[quadIndex].corners[i];
|
const vertexPos = quadInfo.corners[i];
|
||||||
const lightPos = vertexPos + @as(Vec3f, @floatFromInt(blockPos));
|
const lightPos = vertexPos + @as(Vec3f, @floatFromInt(blockPos));
|
||||||
const interp = lightPos - @as(Vec3f, @floatFromInt(blockPos));
|
const interp = lightPos - @as(Vec3f, @floatFromInt(blockPos));
|
||||||
var val: [6]f32 = .{0, 0, 0, 0, 0, 0};
|
var val: [6]f32 = .{0, 0, 0, 0, 0, 0};
|
||||||
@ -548,7 +551,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
var iStart = i;
|
var iStart = i;
|
||||||
for(0..7) |normal| {
|
for(0..7) |normal| {
|
||||||
for(coreList) |face| {
|
for(coreList) |face| {
|
||||||
if(main.models.extraQuadInfos.items[face.blockAndQuad.quadIndex].alignedNormalDirection) |normalDir| {
|
if(face.blockAndQuad.quadIndex.extraQuadInfo().alignedNormalDirection) |normalDir| {
|
||||||
if(normalDir.toInt() == normal) {
|
if(normalDir.toInt() == normal) {
|
||||||
fullBuffer[i] = face;
|
fullBuffer[i] = face;
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -568,7 +571,7 @@ const PrimitiveMesh = struct { // MARK: PrimitiveMesh
|
|||||||
}
|
}
|
||||||
for(0..7) |normal| {
|
for(0..7) |normal| {
|
||||||
for(optionalList) |face| {
|
for(optionalList) |face| {
|
||||||
if(main.models.extraQuadInfos.items[face.blockAndQuad.quadIndex].alignedNormalDirection) |normalDir| {
|
if(face.blockAndQuad.quadIndex.extraQuadInfo().alignedNormalDirection) |normalDir| {
|
||||||
if(normalDir.toInt() == normal) {
|
if(normalDir.toInt() == normal) {
|
||||||
fullBuffer[i] = face;
|
fullBuffer[i] = face;
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -603,7 +606,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
const dz = z + chunkDz;
|
const dz = z + chunkDz;
|
||||||
self.isBackFace = self.face.position.isBackFace;
|
self.isBackFace = self.face.position.isBackFace;
|
||||||
const quadIndex = self.face.blockAndQuad.quadIndex;
|
const quadIndex = self.face.blockAndQuad.quadIndex;
|
||||||
const normalVector = models.quads.items[quadIndex].normal;
|
const normalVector = quadIndex.quadInfo().normal;
|
||||||
self.shouldBeCulled = vec.dot(normalVector, @floatFromInt(Vec3i{dx, dy, dz})) > 0; // TODO: Adjust for arbitrary voxel models.
|
self.shouldBeCulled = vec.dot(normalVector, @floatFromInt(Vec3i{dx, dy, dz})) > 0; // TODO: Adjust for arbitrary voxel models.
|
||||||
const fullDx = dx - @as(i32, @intFromFloat(normalVector[0])); // TODO: This calculation should only be done for border faces.
|
const fullDx = dx - @as(i32, @intFromFloat(normalVector[0])); // TODO: This calculation should only be done for border faces.
|
||||||
const fullDy = dy - @as(i32, @intFromFloat(normalVector[1]));
|
const fullDy = dy - @as(i32, @intFromFloat(normalVector[1]));
|
||||||
@ -750,10 +753,9 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn canBeSeenThroughOtherBlock(block: Block, other: Block, neighbor: chunk.Neighbor) bool {
|
fn canBeSeenThroughOtherBlock(block: Block, other: Block, neighbor: chunk.Neighbor) bool {
|
||||||
const rotatedModel = blocks.meshes.model(block);
|
const rotatedModel = blocks.meshes.model(block).model();
|
||||||
const model = &models.models.items[rotatedModel];
|
_ = rotatedModel; // TODO: Check if the neighbor model occludes this one. (maybe not that relevant)
|
||||||
_ = model; // TODO: Check if the neighbor model occludes this one. (maybe not that relevant)
|
return block.typ != 0 and (other.typ == 0 or (block != other and other.viewThrough()) or other.alwaysViewThrough() or !blocks.meshes.model(other).model().isNeighborOccluded[neighbor.reverse().toInt()]);
|
||||||
return block.typ != 0 and (other.typ == 0 or (block != other and other.viewThrough()) or other.alwaysViewThrough() or !models.models.items[blocks.meshes.model(other)].isNeighborOccluded[neighbor.reverse().toInt()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initLight(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
fn initLight(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
||||||
@ -851,13 +853,13 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn appendInternalQuads(block: Block, x: i32, y: i32, z: i32, comptime backFace: bool, list: *main.ListUnmanaged(FaceData), allocator: main.heap.NeverFailingAllocator) void {
|
fn appendInternalQuads(block: Block, x: i32, y: i32, z: i32, comptime backFace: bool, list: *main.ListUnmanaged(FaceData), allocator: main.heap.NeverFailingAllocator) void {
|
||||||
const model = blocks.meshes.model(block);
|
const model = blocks.meshes.model(block).model();
|
||||||
models.models.items[model].appendInternalQuadsToList(list, allocator, block, x, y, z, backFace);
|
model.appendInternalQuadsToList(list, allocator, block, x, y, z, backFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appendNeighborFacingQuads(block: Block, neighbor: chunk.Neighbor, x: i32, y: i32, z: i32, comptime backFace: bool, list: *main.ListUnmanaged(FaceData), allocator: main.heap.NeverFailingAllocator) void {
|
fn appendNeighborFacingQuads(block: Block, neighbor: chunk.Neighbor, x: i32, y: i32, z: i32, comptime backFace: bool, list: *main.ListUnmanaged(FaceData), allocator: main.heap.NeverFailingAllocator) void {
|
||||||
const model = blocks.meshes.model(block);
|
const model = blocks.meshes.model(block).model();
|
||||||
models.models.items[model].appendNeighborFacingQuadsToList(list, allocator, block, neighbor, x, y, z, backFace);
|
model.appendNeighborFacingQuadsToList(list, allocator, block, neighbor, x, y, z, backFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateMesh(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
pub fn generateMesh(self: *ChunkMesh, lightRefreshList: *main.List(*ChunkMesh)) void {
|
||||||
@ -892,7 +894,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
defer main.stackAllocator.free(paletteCache);
|
defer main.stackAllocator.free(paletteCache);
|
||||||
for(0..self.chunk.data.paletteLength) |i| {
|
for(0..self.chunk.data.paletteLength) |i| {
|
||||||
const block = self.chunk.data.palette[i];
|
const block = self.chunk.data.palette[i];
|
||||||
const model = &models.models.items[blocks.meshes.model(block)];
|
const model = blocks.meshes.model(block).model();
|
||||||
var result: OcclusionInfo = .{};
|
var result: OcclusionInfo = .{};
|
||||||
if(model.noNeighborsOccluded or block.viewThrough()) {
|
if(model.noNeighborsOccluded or block.viewThrough()) {
|
||||||
result.canSeeAllNeighbors = true;
|
result.canSeeAllNeighbors = true;
|
||||||
|
@ -73,7 +73,7 @@ pub const ChannelChunk = struct {
|
|||||||
|
|
||||||
fn calculateIncomingOcclusion(result: *[3]u8, block: blocks.Block, voxelSize: u31, neighbor: chunk.Neighbor) void {
|
fn calculateIncomingOcclusion(result: *[3]u8, block: blocks.Block, voxelSize: u31, neighbor: chunk.Neighbor) void {
|
||||||
if(block.typ == 0) return;
|
if(block.typ == 0) return;
|
||||||
if(main.models.models.items[blocks.meshes.model(block)].isNeighborOccluded[neighbor.toInt()]) {
|
if(blocks.meshes.model(block).model().isNeighborOccluded[neighbor.toInt()]) {
|
||||||
var absorption: [3]u8 = extractColor(block.absorption());
|
var absorption: [3]u8 = extractColor(block.absorption());
|
||||||
absorption[0] *|= @intCast(voxelSize);
|
absorption[0] *|= @intCast(voxelSize);
|
||||||
absorption[1] *|= @intCast(voxelSize);
|
absorption[1] *|= @intCast(voxelSize);
|
||||||
@ -86,7 +86,7 @@ pub const ChannelChunk = struct {
|
|||||||
|
|
||||||
fn calculateOutgoingOcclusion(result: *[3]u8, block: blocks.Block, voxelSize: u31, neighbor: chunk.Neighbor) void {
|
fn calculateOutgoingOcclusion(result: *[3]u8, block: blocks.Block, voxelSize: u31, neighbor: chunk.Neighbor) void {
|
||||||
if(block.typ == 0) return;
|
if(block.typ == 0) return;
|
||||||
const model = &main.models.models.items[blocks.meshes.model(block)];
|
const model = blocks.meshes.model(block).model();
|
||||||
if(model.isNeighborOccluded[neighbor.toInt()] and !model.isNeighborOccluded[neighbor.reverse().toInt()]) { // Avoid calculating the absorption twice.
|
if(model.isNeighborOccluded[neighbor.toInt()] and !model.isNeighborOccluded[neighbor.reverse().toInt()]) { // Avoid calculating the absorption twice.
|
||||||
var absorption: [3]u8 = extractColor(block.absorption());
|
var absorption: [3]u8 = extractColor(block.absorption());
|
||||||
absorption[0] *|= @intCast(voxelSize);
|
absorption[0] *|= @intCast(voxelSize);
|
||||||
|
@ -958,8 +958,7 @@ pub fn addBreakingAnimation(pos: Vec3i, breakingProgress: f32) void {
|
|||||||
const texture = main.blocks.meshes.blockBreakingTextures.items[animationFrame];
|
const texture = main.blocks.meshes.blockBreakingTextures.items[animationFrame];
|
||||||
|
|
||||||
const block = getBlock(pos[0], pos[1], pos[2]) orelse return;
|
const block = getBlock(pos[0], pos[1], pos[2]) orelse return;
|
||||||
const modelIndex = main.blocks.meshes.model(block);
|
const model = main.blocks.meshes.model(block).model();
|
||||||
const model = &main.models.models.items[modelIndex];
|
|
||||||
|
|
||||||
for(model.internalQuads) |quadIndex| {
|
for(model.internalQuads) |quadIndex| {
|
||||||
addBreakingAnimationFace(pos, quadIndex, texture, null, block.transparent());
|
addBreakingAnimationFace(pos, quadIndex, texture, null, block.transparent());
|
||||||
@ -971,7 +970,7 @@ pub fn addBreakingAnimation(pos: Vec3i, breakingProgress: f32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addBreakingAnimationFace(pos: Vec3i, quadIndex: u16, texture: u16, neighbor: ?chunk.Neighbor, isTransparent: bool) void {
|
fn addBreakingAnimationFace(pos: Vec3i, quadIndex: main.models.QuadIndex, texture: u16, neighbor: ?chunk.Neighbor, isTransparent: bool) void {
|
||||||
const worldPos = pos +% if(neighbor) |n| n.relPos() else Vec3i{0, 0, 0};
|
const worldPos = pos +% if(neighbor) |n| n.relPos() else Vec3i{0, 0, 0};
|
||||||
const relPos = worldPos & @as(Vec3i, @splat(main.chunk.chunkMask));
|
const relPos = worldPos & @as(Vec3i, @splat(main.chunk.chunkMask));
|
||||||
const mesh = getMeshAndIncreaseRefCount(.{.wx = worldPos[0], .wy = worldPos[1], .wz = worldPos[2], .voxelSize = 1}) orelse return;
|
const mesh = getMeshAndIncreaseRefCount(.{.wx = worldPos[0], .wy = worldPos[1], .wz = worldPos[2], .voxelSize = 1}) orelse return;
|
||||||
@ -1006,7 +1005,7 @@ fn addBreakingAnimationFace(pos: Vec3i, quadIndex: u16, texture: u16, neighbor:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn removeBreakingAnimationFace(pos: Vec3i, quadIndex: u16, neighbor: ?chunk.Neighbor) void {
|
fn removeBreakingAnimationFace(pos: Vec3i, quadIndex: main.models.QuadIndex, neighbor: ?chunk.Neighbor) void {
|
||||||
const worldPos = pos +% if(neighbor) |n| n.relPos() else Vec3i{0, 0, 0};
|
const worldPos = pos +% if(neighbor) |n| n.relPos() else Vec3i{0, 0, 0};
|
||||||
const relPos = worldPos & @as(Vec3i, @splat(main.chunk.chunkMask));
|
const relPos = worldPos & @as(Vec3i, @splat(main.chunk.chunkMask));
|
||||||
const mesh = getMeshAndIncreaseRefCount(.{.wx = worldPos[0], .wy = worldPos[1], .wz = worldPos[2], .voxelSize = 1}) orelse return;
|
const mesh = getMeshAndIncreaseRefCount(.{.wx = worldPos[0], .wy = worldPos[1], .wz = worldPos[2], .voxelSize = 1}) orelse return;
|
||||||
@ -1022,8 +1021,7 @@ fn removeBreakingAnimationFace(pos: Vec3i, quadIndex: u16, neighbor: ?chunk.Neig
|
|||||||
|
|
||||||
pub fn removeBreakingAnimation(pos: Vec3i) void {
|
pub fn removeBreakingAnimation(pos: Vec3i) void {
|
||||||
const block = getBlock(pos[0], pos[1], pos[2]) orelse return;
|
const block = getBlock(pos[0], pos[1], pos[2]) orelse return;
|
||||||
const modelIndex = main.blocks.meshes.model(block);
|
const model = main.blocks.meshes.model(block).model();
|
||||||
const model = &main.models.models.items[modelIndex];
|
|
||||||
|
|
||||||
for(model.internalQuads) |quadIndex| {
|
for(model.internalQuads) |quadIndex| {
|
||||||
removeBreakingAnimationFace(pos, quadIndex, null);
|
removeBreakingAnimationFace(pos, quadIndex, null);
|
||||||
|
172
src/rotation.zig
172
src/rotation.zig
@ -5,6 +5,7 @@ const Block = blocks.Block;
|
|||||||
const chunk = @import("chunk.zig");
|
const chunk = @import("chunk.zig");
|
||||||
const Neighbor = chunk.Neighbor;
|
const Neighbor = chunk.Neighbor;
|
||||||
const main = @import("main.zig");
|
const main = @import("main.zig");
|
||||||
|
const ModelIndex = main.models.ModelIndex;
|
||||||
const vec = main.vec;
|
const vec = main.vec;
|
||||||
const Vec2f = vec.Vec2f;
|
const Vec2f = vec.Vec2f;
|
||||||
const Vec3i = vec.Vec3i;
|
const Vec3i = vec.Vec3i;
|
||||||
@ -31,7 +32,7 @@ pub const Degrees = enum(u2) {
|
|||||||
/// With the `RotationMode` interface there is almost no limit to what can be done with those 16 bit.
|
/// With the `RotationMode` interface there is almost no limit to what can be done with those 16 bit.
|
||||||
pub const RotationMode = struct { // MARK: RotationMode
|
pub const RotationMode = struct { // MARK: RotationMode
|
||||||
const DefaultFunctions = struct {
|
const DefaultFunctions = struct {
|
||||||
fn model(block: Block) u16 {
|
fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block);
|
return blocks.meshes.modelIndexStart(block);
|
||||||
}
|
}
|
||||||
fn rotateZ(data: u16, _: Degrees) u16 {
|
fn rotateZ(data: u16, _: Degrees) u16 {
|
||||||
@ -40,7 +41,7 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
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;
|
||||||
}
|
}
|
||||||
fn createBlockModel(zon: ZonElement) u16 {
|
fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
return main.models.getModelIndex(zon.as([]const u8, "cubyz:cube"));
|
return main.models.getModelIndex(zon.as([]const u8, "cubyz:cube"));
|
||||||
}
|
}
|
||||||
fn updateData(_: *Block, _: Neighbor, _: Block) bool {
|
fn updateData(_: *Block, _: Neighbor, _: Block) bool {
|
||||||
@ -52,10 +53,10 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
fn rayIntersection(block: Block, _: ?main.items.Item, relativePlayerPos: Vec3f, playerDir: Vec3f) ?RayIntersectionResult {
|
fn rayIntersection(block: Block, _: ?main.items.Item, relativePlayerPos: Vec3f, playerDir: Vec3f) ?RayIntersectionResult {
|
||||||
return rayModelIntersection(blocks.meshes.model(block), relativePlayerPos, playerDir);
|
return rayModelIntersection(blocks.meshes.model(block), relativePlayerPos, playerDir);
|
||||||
}
|
}
|
||||||
fn rayModelIntersection(modelIndex: u32, relativePlayerPos: Vec3f, playerDir: Vec3f) ?RayIntersectionResult {
|
fn rayModelIntersection(modelIndex: ModelIndex, relativePlayerPos: Vec3f, playerDir: Vec3f) ?RayIntersectionResult {
|
||||||
// Check the true bounding box (using this algorithm here: https://tavianator.com/2011/ray_box.html):
|
// Check the true bounding box (using this algorithm here: https://tavianator.com/2011/ray_box.html):
|
||||||
const invDir = @as(Vec3f, @splat(1))/playerDir;
|
const invDir = @as(Vec3f, @splat(1))/playerDir;
|
||||||
const modelData = &main.models.models.items[modelIndex];
|
const modelData = modelIndex.model();
|
||||||
const min: Vec3f = modelData.min;
|
const min: Vec3f = modelData.min;
|
||||||
const max: Vec3f = modelData.max;
|
const max: Vec3f = modelData.max;
|
||||||
const t1 = (min - relativePlayerPos)*invDir;
|
const t1 = (min - relativePlayerPos)*invDir;
|
||||||
@ -120,12 +121,12 @@ pub const RotationMode = struct { // MARK: RotationMode
|
|||||||
/// The default rotation data intended for generation algorithms
|
/// The default rotation data intended for generation algorithms
|
||||||
naturalStandard: u16 = 0,
|
naturalStandard: u16 = 0,
|
||||||
|
|
||||||
model: *const fn(block: Block) u16 = &DefaultFunctions.model,
|
model: *const fn(block: Block) ModelIndex = &DefaultFunctions.model,
|
||||||
|
|
||||||
// Rotates block data counterclockwise around the Z axis.
|
// Rotates block data counterclockwise around the Z axis.
|
||||||
rotateZ: *const fn(data: u16, angle: Degrees) u16 = DefaultFunctions.rotateZ,
|
rotateZ: *const fn(data: u16, angle: Degrees) u16 = DefaultFunctions.rotateZ,
|
||||||
|
|
||||||
createBlockModel: *const fn(zon: ZonElement) u16 = &DefaultFunctions.createBlockModel,
|
createBlockModel: *const fn(zon: ZonElement) ModelIndex = &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.
|
||||||
/// return true if the placing was successful, false otherwise.
|
/// return true if the placing was successful, false otherwise.
|
||||||
@ -161,7 +162,7 @@ pub const RotationModes = struct {
|
|||||||
};
|
};
|
||||||
pub const Log = struct { // MARK: Log
|
pub const Log = struct { // MARK: Log
|
||||||
pub const id: []const u8 = "log";
|
pub const id: []const u8 = "log";
|
||||||
var rotatedModels: std.StringHashMap(u16) = undefined;
|
var rotatedModels: std.StringHashMap(ModelIndex) = undefined;
|
||||||
|
|
||||||
fn init() void {
|
fn init() void {
|
||||||
rotatedModels = .init(main.globalAllocator.allocator);
|
rotatedModels = .init(main.globalAllocator.allocator);
|
||||||
@ -175,14 +176,13 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
const baseModelIndex = main.models.getModelIndex(modelId);
|
const baseModel = main.models.getModelIndex(modelId).model();
|
||||||
const baseModel = main.models.models.items[baseModelIndex];
|
|
||||||
// Rotate the model:
|
// Rotate the model:
|
||||||
const modelIndex: u16 = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.identity()});
|
const modelIndex = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.identity()});
|
||||||
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationY(std.math.pi)});
|
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationY(std.math.pi)});
|
||||||
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(-std.math.pi/2.0).mul(Mat4f.rotationX(-std.math.pi/2.0))});
|
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(-std.math.pi/2.0).mul(Mat4f.rotationX(-std.math.pi/2.0))});
|
||||||
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi/2.0).mul(Mat4f.rotationX(-std.math.pi/2.0))});
|
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi/2.0).mul(Mat4f.rotationX(-std.math.pi/2.0))});
|
||||||
@ -192,8 +192,8 @@ pub const RotationModes = struct {
|
|||||||
return modelIndex;
|
return modelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + @min(block.data, 5);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + @min(block.data, 5)};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotateZ(data: u16, angle: Degrees) u16 {
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
@ -221,7 +221,7 @@ pub const RotationModes = struct {
|
|||||||
};
|
};
|
||||||
pub const Planar = struct { // MARK: Planar
|
pub const Planar = struct { // MARK: Planar
|
||||||
pub const id: []const u8 = "planar";
|
pub const id: []const u8 = "planar";
|
||||||
var rotatedModels: std.StringHashMap(u16) = undefined;
|
var rotatedModels: std.StringHashMap(ModelIndex) = undefined;
|
||||||
|
|
||||||
fn init() void {
|
fn init() void {
|
||||||
rotatedModels = .init(main.globalAllocator.allocator);
|
rotatedModels = .init(main.globalAllocator.allocator);
|
||||||
@ -235,14 +235,13 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
const baseModelIndex = main.models.getModelIndex(modelId);
|
const baseModel = main.models.getModelIndex(modelId).model();
|
||||||
const baseModel = main.models.models.items[baseModelIndex];
|
|
||||||
// Rotate the model:
|
// Rotate the model:
|
||||||
const modelIndex: u16 = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi/2.0)});
|
const modelIndex: ModelIndex = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi/2.0)});
|
||||||
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(-std.math.pi/2.0)});
|
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(-std.math.pi/2.0)});
|
||||||
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi)});
|
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi)});
|
||||||
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.identity()});
|
_ = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.identity()});
|
||||||
@ -250,8 +249,8 @@ pub const RotationModes = struct {
|
|||||||
return modelIndex;
|
return modelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + @min(block.data, 3);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + @min(block.data, 3)};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotateZ(data: u16, angle: Degrees) u16 {
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
@ -286,7 +285,7 @@ pub const RotationModes = struct {
|
|||||||
pub const Fence = struct { // MARK: Fence
|
pub const Fence = struct { // MARK: Fence
|
||||||
pub const id: []const u8 = "fence";
|
pub const id: []const u8 = "fence";
|
||||||
pub const dependsOnNeighbors = true;
|
pub const dependsOnNeighbors = true;
|
||||||
var fenceModels: std.StringHashMap(u16) = undefined;
|
var fenceModels: std.StringHashMap(ModelIndex) = undefined;
|
||||||
const FenceData = packed struct(u4) {
|
const FenceData = packed struct(u4) {
|
||||||
isConnectedNegX: bool,
|
isConnectedNegX: bool,
|
||||||
isConnectedPosX: bool,
|
isConnectedPosX: bool,
|
||||||
@ -356,14 +355,13 @@ pub const RotationModes = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(fenceModels.get(modelId)) |modelIndex| return modelIndex;
|
if(fenceModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
const baseModelIndex = main.models.getModelIndex(modelId);
|
const baseModel = main.models.getModelIndex(modelId).model();
|
||||||
const baseModel = main.models.models.items[baseModelIndex];
|
|
||||||
// Rotate the model:
|
// Rotate the model:
|
||||||
const modelIndex: u16 = baseModel.transformModel(fenceTransform, .{@as(FenceData, @bitCast(@as(u4, 0)))});
|
const modelIndex: ModelIndex = baseModel.transformModel(fenceTransform, .{@as(FenceData, @bitCast(@as(u4, 0)))});
|
||||||
for(1..16) |fenceData| {
|
for(1..16) |fenceData| {
|
||||||
_ = baseModel.transformModel(fenceTransform, .{@as(FenceData, @bitCast(@as(u4, @intCast(fenceData))))});
|
_ = baseModel.transformModel(fenceTransform, .{@as(FenceData, @bitCast(@as(u4, @intCast(fenceData))))});
|
||||||
}
|
}
|
||||||
@ -371,15 +369,15 @@ pub const RotationModes = struct {
|
|||||||
return modelIndex;
|
return modelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + (block.data & 15);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + (block.data & 15)};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool {
|
pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool {
|
||||||
const blockBaseModel = blocks.meshes.modelIndexStart(block.*);
|
const blockBaseModelIndex = blocks.meshes.modelIndexStart(block.*);
|
||||||
const neighborBaseModel = blocks.meshes.modelIndexStart(neighborBlock);
|
const neighborBaseModelIndex = blocks.meshes.modelIndexStart(neighborBlock);
|
||||||
const neighborModel = blocks.meshes.model(neighborBlock);
|
const neighborModel = blocks.meshes.model(neighborBlock).model();
|
||||||
const targetVal = neighborBlock.solid() and (blockBaseModel == neighborBaseModel or main.models.models.items[neighborModel].isNeighborOccluded[neighbor.reverse().toInt()]);
|
const targetVal = neighborBlock.solid() and (blockBaseModelIndex == neighborBaseModelIndex or neighborModel.isNeighborOccluded[neighbor.reverse().toInt()]);
|
||||||
var currentData: FenceData = @bitCast(@as(u4, @truncate(block.data)));
|
var currentData: FenceData = @bitCast(@as(u4, @truncate(block.data)));
|
||||||
switch(neighbor) {
|
switch(neighbor) {
|
||||||
.dirNegX => {
|
.dirNegX => {
|
||||||
@ -405,7 +403,7 @@ pub const RotationModes = struct {
|
|||||||
pub const Branch = struct { // MARK: Branch
|
pub const Branch = struct { // MARK: Branch
|
||||||
pub const id: []const u8 = "branch";
|
pub const id: []const u8 = "branch";
|
||||||
pub const dependsOnNeighbors = true;
|
pub const dependsOnNeighbors = true;
|
||||||
var branchModels: std.AutoHashMap(u32, u16) = undefined;
|
var branchModels: std.AutoHashMap(u32, ModelIndex) = undefined;
|
||||||
const BranchData = packed struct(u6) {
|
const BranchData = packed struct(u6) {
|
||||||
enabledConnections: u6,
|
enabledConnections: u6,
|
||||||
|
|
||||||
@ -640,11 +638,11 @@ pub const RotationModes = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const radius = zon.get(f32, "radius", 4);
|
const radius = zon.get(f32, "radius", 4);
|
||||||
if(branchModels.get(@bitCast(radius))) |modelIndex| return modelIndex;
|
if(branchModels.get(@bitCast(radius))) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
var modelIndex: u16 = undefined;
|
var modelIndex: ModelIndex = undefined;
|
||||||
for(0..64) |i| {
|
for(0..64) |i| {
|
||||||
var quads = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
var quads = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
||||||
defer quads.deinit();
|
defer quads.deinit();
|
||||||
@ -668,8 +666,8 @@ pub const RotationModes = struct {
|
|||||||
return modelIndex;
|
return modelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + (block.data & 63);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + (block.data & 63)};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotateZ(data: u16, angle: Degrees) u16 {
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
@ -709,16 +707,16 @@ pub const RotationModes = struct {
|
|||||||
neighborBlock: Block,
|
neighborBlock: Block,
|
||||||
blockPlacing: bool,
|
blockPlacing: bool,
|
||||||
) bool {
|
) bool {
|
||||||
const blockBaseModel = blocks.meshes.modelIndexStart(currentBlock.*);
|
const blockBaseModelIndex = blocks.meshes.modelIndexStart(currentBlock.*);
|
||||||
const neighborBaseModel = blocks.meshes.modelIndexStart(neighborBlock);
|
const neighborBaseModelIndex = blocks.meshes.modelIndexStart(neighborBlock);
|
||||||
|
|
||||||
if(blockPlacing or blockBaseModel == neighborBaseModel or neighborBlock.solid()) {
|
if(blockPlacing or blockBaseModelIndex == neighborBaseModelIndex or neighborBlock.solid()) {
|
||||||
const neighborModel = blocks.meshes.model(neighborBlock);
|
const neighborModel = blocks.meshes.model(neighborBlock).model();
|
||||||
|
|
||||||
var currentData = BranchData.init(currentBlock.data);
|
var currentData = BranchData.init(currentBlock.data);
|
||||||
// Branch block upon placement should extend towards a block it was placed
|
// Branch block upon placement should extend towards a block it was placed
|
||||||
// on if the block is solid or also uses branch model.
|
// on if the block is solid or also uses branch model.
|
||||||
const targetVal = ((neighborBlock.solid() and !neighborBlock.viewThrough()) and (blockBaseModel == neighborBaseModel or main.models.models.items[neighborModel].isNeighborOccluded[neighbor.?.reverse().toInt()]));
|
const targetVal = ((neighborBlock.solid() and !neighborBlock.viewThrough()) and (blockBaseModelIndex == neighborBaseModelIndex or neighborModel.isNeighborOccluded[neighbor.?.reverse().toInt()]));
|
||||||
currentData.setConnection(neighbor.?, targetVal);
|
currentData.setConnection(neighbor.?, targetVal);
|
||||||
|
|
||||||
const result: u16 = currentData.enabledConnections;
|
const result: u16 = currentData.enabledConnections;
|
||||||
@ -766,7 +764,7 @@ pub const RotationModes = struct {
|
|||||||
const directionBitMask = Neighbor.bitMask(direction);
|
const directionBitMask = Neighbor.bitMask(direction);
|
||||||
|
|
||||||
if((block.data & directionBitMask) != 0) {
|
if((block.data & directionBitMask) != 0) {
|
||||||
const modelIndex = blocks.meshes.modelIndexStart(block) + directionBitMask;
|
const modelIndex = ModelIndex{.index = blocks.meshes.modelIndexStart(block).index + directionBitMask};
|
||||||
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
|
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
|
||||||
if(@abs(closestIntersectionDistance) > @abs(intersection.distance)) {
|
if(@abs(closestIntersectionDistance) > @abs(intersection.distance)) {
|
||||||
closestIntersectionDistance = intersection.distance;
|
closestIntersectionDistance = intersection.distance;
|
||||||
@ -793,7 +791,7 @@ pub const RotationModes = struct {
|
|||||||
};
|
};
|
||||||
pub const Stairs = struct { // MARK: Stairs
|
pub const Stairs = struct { // MARK: Stairs
|
||||||
pub const id: []const u8 = "stairs";
|
pub const id: []const u8 = "stairs";
|
||||||
var modelIndex: u16 = 0;
|
var modelIndex: ?ModelIndex = null;
|
||||||
|
|
||||||
fn subBlockMask(x: u1, y: u1, z: u1) u8 {
|
fn subBlockMask(x: u1, y: u1, z: u1) u8 {
|
||||||
return @as(u8, 1) << ((@as(u3, x)*2 + @as(u3, y))*2 + z);
|
return @as(u8, 1) << ((@as(u3, x)*2 + @as(u3, y))*2 + z);
|
||||||
@ -834,7 +832,7 @@ pub const RotationModes = struct {
|
|||||||
fn init() void {}
|
fn init() void {}
|
||||||
fn deinit() void {}
|
fn deinit() void {}
|
||||||
fn reset() void {
|
fn reset() void {
|
||||||
modelIndex = 0;
|
modelIndex = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GreedyFaceInfo = struct {min: Vec2f, max: Vec2f};
|
const GreedyFaceInfo = struct {min: Vec2f, max: Vec2f};
|
||||||
@ -902,10 +900,8 @@ pub const RotationModes = struct {
|
|||||||
return mem[0..faces];
|
return mem[0..faces];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(_: ZonElement) u16 {
|
pub fn createBlockModel(_: ZonElement) ModelIndex {
|
||||||
if(modelIndex != 0) {
|
if(modelIndex) |idx| return idx;
|
||||||
return modelIndex;
|
|
||||||
}
|
|
||||||
for(0..256) |i| {
|
for(0..256) |i| {
|
||||||
var quads = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
var quads = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
||||||
defer quads.deinit();
|
defer quads.deinit();
|
||||||
@ -1018,11 +1014,11 @@ pub const RotationModes = struct {
|
|||||||
modelIndex = index;
|
modelIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return modelIndex;
|
return modelIndex.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + (block.data & 255);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + (block.data & 255)};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool {
|
||||||
@ -1125,7 +1121,7 @@ pub const RotationModes = struct {
|
|||||||
pub const id: []const u8 = "torch";
|
pub const id: []const u8 = "torch";
|
||||||
pub const naturalStandard: u16 = 1;
|
pub const naturalStandard: u16 = 1;
|
||||||
pub const dependsOnNeighbors = true;
|
pub const dependsOnNeighbors = true;
|
||||||
var rotatedModels: std.StringHashMap(u16) = undefined;
|
var rotatedModels: std.StringHashMap(ModelIndex) = undefined;
|
||||||
const TorchData = packed struct(u5) {
|
const TorchData = packed struct(u5) {
|
||||||
center: bool,
|
center: bool,
|
||||||
negX: bool,
|
negX: bool,
|
||||||
@ -1146,7 +1142,7 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const baseModelId: []const u8 = zon.get([]const u8, "base", "cubyz:cube");
|
const baseModelId: []const u8 = zon.get([]const u8, "base", "cubyz:cube");
|
||||||
const sideModelId: []const u8 = zon.get([]const u8, "side", "cubyz:cube");
|
const sideModelId: []const u8 = zon.get([]const u8, "side", "cubyz:cube");
|
||||||
const key: []const u8 = std.mem.concat(main.stackAllocator.allocator, u8, &.{baseModelId, sideModelId}) catch unreachable;
|
const key: []const u8 = std.mem.concat(main.stackAllocator.allocator, u8, &.{baseModelId, sideModelId}) catch unreachable;
|
||||||
@ -1154,16 +1150,14 @@ pub const RotationModes = struct {
|
|||||||
|
|
||||||
if(rotatedModels.get(key)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(key)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
const baseModelIndex = main.models.getModelIndex(baseModelId);
|
const baseModel = main.models.getModelIndex(baseModelId).model();
|
||||||
const baseModel = main.models.models.items[baseModelIndex];
|
const sideModel = main.models.getModelIndex(sideModelId).model();
|
||||||
const sideModelIndex = main.models.getModelIndex(sideModelId);
|
|
||||||
const sideModel = main.models.models.items[sideModelIndex];
|
|
||||||
// Rotate the model:
|
// Rotate the model:
|
||||||
var centerModel: u16 = undefined;
|
var centerModel: ModelIndex = undefined;
|
||||||
var negXModel: u16 = undefined;
|
var negXModel: ModelIndex = undefined;
|
||||||
var posXModel: u16 = undefined;
|
var posXModel: ModelIndex = undefined;
|
||||||
var negYModel: u16 = undefined;
|
var negYModel: ModelIndex = undefined;
|
||||||
var posYModel: u16 = undefined;
|
var posYModel: ModelIndex = undefined;
|
||||||
for(1..32) |i| {
|
for(1..32) |i| {
|
||||||
const torchData: TorchData = @bitCast(@as(u5, @intCast(i)));
|
const torchData: TorchData = @bitCast(@as(u5, @intCast(i)));
|
||||||
if(i & i - 1 == 0) {
|
if(i & i - 1 == 0) {
|
||||||
@ -1173,7 +1167,7 @@ pub const RotationModes = struct {
|
|||||||
if(torchData.negY) negYModel = sideModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi/2.0)});
|
if(torchData.negY) negYModel = sideModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(std.math.pi/2.0)});
|
||||||
if(torchData.posY) posYModel = sideModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(-std.math.pi/2.0)});
|
if(torchData.posY) posYModel = sideModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationZ(-std.math.pi/2.0)});
|
||||||
} else {
|
} else {
|
||||||
var models: [5]u16 = undefined;
|
var models: [5]ModelIndex = undefined;
|
||||||
var amount: usize = 0;
|
var amount: usize = 0;
|
||||||
if(torchData.center) {
|
if(torchData.center) {
|
||||||
models[amount] = centerModel;
|
models[amount] = centerModel;
|
||||||
@ -1203,8 +1197,8 @@ pub const RotationModes = struct {
|
|||||||
return modelIndex;
|
return modelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + (@as(u5, @truncate(block.data)) -| 1);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + (@as(u5, @truncate(block.data)) -| 1)};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotateZ(data: u16, angle: Degrees) u16 {
|
fn rotateZ(data: u16, angle: Degrees) u16 {
|
||||||
@ -1231,8 +1225,8 @@ pub const RotationModes = struct {
|
|||||||
|
|
||||||
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).model();
|
||||||
const neighborSupport = neighborBlock.solid() and main.models.models.items[neighborModel].neighborFacingQuads[neighbor.?.reverse().toInt()].len != 0;
|
const neighborSupport = neighborBlock.solid() and neighborModel.neighborFacingQuads[neighbor.?.reverse().toInt()].len != 0;
|
||||||
if(!neighborSupport) return false;
|
if(!neighborSupport) return false;
|
||||||
var data: TorchData = @bitCast(@as(u5, @truncate(currentData.data)));
|
var data: TorchData = @bitCast(@as(u5, @truncate(currentData.data)));
|
||||||
if(relativeDir[0] == 1) data.posX = true;
|
if(relativeDir[0] == 1) data.posX = true;
|
||||||
@ -1249,8 +1243,8 @@ pub const RotationModes = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool {
|
pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool {
|
||||||
const neighborModel = blocks.meshes.model(neighborBlock);
|
const neighborModel = blocks.meshes.model(neighborBlock).model();
|
||||||
const neighborSupport = neighborBlock.solid() and main.models.models.items[neighborModel].neighborFacingQuads[neighbor.reverse().toInt()].len != 0;
|
const neighborSupport = neighborBlock.solid() and neighborModel.neighborFacingQuads[neighbor.reverse().toInt()].len != 0;
|
||||||
var currentData: TorchData = @bitCast(@as(u5, @truncate(block.data)));
|
var currentData: TorchData = @bitCast(@as(u5, @truncate(block.data)));
|
||||||
switch(neighbor) {
|
switch(neighbor) {
|
||||||
.dirNegX => {
|
.dirNegX => {
|
||||||
@ -1282,7 +1276,7 @@ pub const RotationModes = struct {
|
|||||||
var resultBit: u16 = 0;
|
var resultBit: u16 = 0;
|
||||||
for([_]u16{1, 2, 4, 8, 16}) |bit| {
|
for([_]u16{1, 2, 4, 8, 16}) |bit| {
|
||||||
if(block.data & bit != 0) {
|
if(block.data & bit != 0) {
|
||||||
const modelIndex = blocks.meshes.modelIndexStart(block) + bit - 1;
|
const modelIndex = ModelIndex{.index = blocks.meshes.modelIndexStart(block).index + bit - 1};
|
||||||
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
|
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
|
||||||
if(result == null or result.?.distance > intersection.distance) {
|
if(result == null or result.?.distance > intersection.distance) {
|
||||||
result = intersection;
|
result = intersection;
|
||||||
@ -1323,7 +1317,7 @@ pub const RotationModes = struct {
|
|||||||
pub const Carpet = struct { // MARK: Carpet
|
pub const Carpet = struct { // MARK: Carpet
|
||||||
pub const id: []const u8 = "carpet";
|
pub const id: []const u8 = "carpet";
|
||||||
pub const naturalStandard: u16 = 0b10000;
|
pub const naturalStandard: u16 = 0b10000;
|
||||||
var rotatedModels: std.StringHashMap(u16) = undefined;
|
var rotatedModels: std.StringHashMap(ModelIndex) = undefined;
|
||||||
const CarpetData = packed struct(u6) {
|
const CarpetData = packed struct(u6) {
|
||||||
negX: bool,
|
negX: bool,
|
||||||
posX: bool,
|
posX: bool,
|
||||||
@ -1368,19 +1362,18 @@ pub const RotationModes = struct {
|
|||||||
rotatedModels.clearRetainingCapacity();
|
rotatedModels.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
if(rotatedModels.get(modelId)) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
const baseModelIndex = main.models.getModelIndex(modelId);
|
const baseModel = main.models.getModelIndex(modelId).model();
|
||||||
const baseModel = main.models.models.items[baseModelIndex];
|
|
||||||
// Rotate the model:
|
// Rotate the model:
|
||||||
var negXModel: u16 = undefined;
|
var negXModel: ModelIndex = undefined;
|
||||||
var posXModel: u16 = undefined;
|
var posXModel: ModelIndex = undefined;
|
||||||
var negYModel: u16 = undefined;
|
var negYModel: ModelIndex = undefined;
|
||||||
var posYModel: u16 = undefined;
|
var posYModel: ModelIndex = undefined;
|
||||||
var negZModel: u16 = undefined;
|
var negZModel: ModelIndex = undefined;
|
||||||
var posZModel: u16 = undefined;
|
var posZModel: ModelIndex = undefined;
|
||||||
for(1..64) |i| {
|
for(1..64) |i| {
|
||||||
const carpetData: CarpetData = @bitCast(@as(u6, @intCast(i)));
|
const carpetData: CarpetData = @bitCast(@as(u6, @intCast(i)));
|
||||||
if(i & i - 1 == 0) {
|
if(i & i - 1 == 0) {
|
||||||
@ -1391,7 +1384,7 @@ pub const RotationModes = struct {
|
|||||||
if(carpetData.negZ) negZModel = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.identity()});
|
if(carpetData.negZ) negZModel = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.identity()});
|
||||||
if(carpetData.posZ) posZModel = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationY(std.math.pi)});
|
if(carpetData.posZ) posZModel = baseModel.transformModel(rotationMatrixTransform, .{Mat4f.rotationY(std.math.pi)});
|
||||||
} else {
|
} else {
|
||||||
var models: [6]u16 = undefined;
|
var models: [6]ModelIndex = undefined;
|
||||||
var amount: usize = 0;
|
var amount: usize = 0;
|
||||||
if(carpetData.negX) {
|
if(carpetData.negX) {
|
||||||
models[amount] = negXModel;
|
models[amount] = negXModel;
|
||||||
@ -1425,8 +1418,8 @@ pub const RotationModes = struct {
|
|||||||
return modelIndex;
|
return modelIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(block: Block) u16 {
|
pub fn model(block: Block) ModelIndex {
|
||||||
return blocks.meshes.modelIndexStart(block) + (@as(u6, @truncate(block.data)) -| 1);
|
return .{.index = blocks.meshes.modelIndexStart(block).index + (@as(u6, @truncate(block.data)) -| 1)};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateData(_: *main.game.World, _: Vec3i, relativePlayerPos: Vec3f, playerDir: Vec3f, relativeDir: Vec3i, _: ?Neighbor, currentData: *Block, neighbor: Block, _: bool) bool {
|
pub fn generateData(_: *main.game.World, _: Vec3i, relativePlayerPos: Vec3f, playerDir: Vec3f, relativeDir: Vec3i, _: ?Neighbor, currentData: *Block, neighbor: Block, _: bool) bool {
|
||||||
@ -1460,7 +1453,7 @@ pub const RotationModes = struct {
|
|||||||
var resultBit: u16 = 0;
|
var resultBit: u16 = 0;
|
||||||
for([_]u16{1, 2, 4, 8, 16, 32}) |bit| {
|
for([_]u16{1, 2, 4, 8, 16, 32}) |bit| {
|
||||||
if(block.data & bit != 0) {
|
if(block.data & bit != 0) {
|
||||||
const modelIndex = blocks.meshes.modelIndexStart(block) + bit - 1;
|
const modelIndex = ModelIndex{.index = blocks.meshes.modelIndexStart(block).index + bit - 1};
|
||||||
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
|
if(RotationMode.DefaultFunctions.rayModelIntersection(modelIndex, relativePlayerPos, playerDir)) |intersection| {
|
||||||
if(result == null or result.?.distance > intersection.distance) {
|
if(result == null or result.?.distance > intersection.distance) {
|
||||||
result = intersection;
|
result = intersection;
|
||||||
@ -1489,7 +1482,7 @@ pub const RotationModes = struct {
|
|||||||
};
|
};
|
||||||
pub const Ore = struct { // MARK: Ore
|
pub const Ore = struct { // MARK: Ore
|
||||||
pub const id: []const u8 = "ore";
|
pub const id: []const u8 = "ore";
|
||||||
var modelCache: ?u16 = null;
|
var modelCache: ?ModelIndex = null;
|
||||||
|
|
||||||
fn init() void {}
|
fn init() void {}
|
||||||
fn deinit() void {}
|
fn deinit() void {}
|
||||||
@ -1497,15 +1490,14 @@ pub const RotationModes = struct {
|
|||||||
modelCache = null;
|
modelCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createBlockModel(zon: ZonElement) u16 {
|
pub fn createBlockModel(zon: ZonElement) ModelIndex {
|
||||||
const modelId = zon.as([]const u8, "cubyz:cube");
|
const modelId = zon.as([]const u8, "cubyz:cube");
|
||||||
if(!std.mem.eql(u8, modelId, "cubyz:cube")) {
|
if(!std.mem.eql(u8, modelId, "cubyz:cube")) {
|
||||||
std.log.err("Ores can only be use on cube models.", .{modelId});
|
std.log.err("Ores can only be use on cube models.", .{modelId});
|
||||||
}
|
}
|
||||||
if(modelCache) |modelIndex| return modelIndex;
|
if(modelCache) |modelIndex| return modelIndex;
|
||||||
|
|
||||||
const baseModelIndex = main.models.getModelIndex("cubyz:cube");
|
const baseModel = main.models.getModelIndex("cubyz:cube").model();
|
||||||
const baseModel = main.models.models.items[baseModelIndex];
|
|
||||||
var quadList = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
var quadList = main.List(main.models.QuadInfo).init(main.stackAllocator);
|
||||||
defer quadList.deinit();
|
defer quadList.deinit();
|
||||||
baseModel.getRawFaces(&quadList);
|
baseModel.getRawFaces(&quadList);
|
||||||
@ -1526,7 +1518,7 @@ pub const RotationModes = struct {
|
|||||||
|
|
||||||
pub fn modifyBlock(block: *Block, newBlockType: u16) bool {
|
pub fn modifyBlock(block: *Block, newBlockType: u16) bool {
|
||||||
if(block.transparent() or block.viewThrough()) return false;
|
if(block.transparent() or block.viewThrough()) return false;
|
||||||
if(!main.models.models.items[main.blocks.meshes.modelIndexStart(block.*)].allNeighborsOccluded) return false;
|
if(!main.blocks.meshes.modelIndexStart(block.*).model().allNeighborsOccluded) return false;
|
||||||
if(block.data != 0) return false;
|
if(block.data != 0) return false;
|
||||||
block.data = block.typ;
|
block.data = block.typ;
|
||||||
block.typ = newBlockType;
|
block.typ = newBlockType;
|
||||||
@ -1536,7 +1528,7 @@ pub const RotationModes = struct {
|
|||||||
pub fn canBeChangedInto(oldBlock: Block, newBlock: Block, _: main.items.ItemStack, shouldDropSourceBlockOnSuccess: *bool) RotationMode.CanBeChangedInto {
|
pub fn canBeChangedInto(oldBlock: Block, newBlock: Block, _: main.items.ItemStack, shouldDropSourceBlockOnSuccess: *bool) RotationMode.CanBeChangedInto {
|
||||||
if(oldBlock == newBlock) return .no;
|
if(oldBlock == newBlock) return .no;
|
||||||
if(oldBlock.transparent() or oldBlock.viewThrough()) return .no;
|
if(oldBlock.transparent() or oldBlock.viewThrough()) return .no;
|
||||||
if(!main.models.models.items[main.blocks.meshes.modelIndexStart(oldBlock)].allNeighborsOccluded) return .no;
|
if(!main.blocks.meshes.modelIndexStart(oldBlock).model().allNeighborsOccluded) return .no;
|
||||||
if(oldBlock.data != 0) return .no;
|
if(oldBlock.data != 0) return .no;
|
||||||
if(newBlock.data != oldBlock.typ) return .no;
|
if(newBlock.data != oldBlock.typ) return .no;
|
||||||
shouldDropSourceBlockOnSuccess.* = false;
|
shouldDropSourceBlockOnSuccess.* = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user