From 3a6f55b8e7dead1bbac3c3bacadb06da4e2f8da0 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sat, 17 Aug 2024 11:01:22 +0200 Subject: [PATCH] Implement block drop rendering and fix a couple synchronization issues. --- assets/cubyz/shaders/item_drop.fs | 231 ++++++++---------------------- assets/cubyz/shaders/item_drop.vs | 102 +++++++++---- src/itemdrop.zig | 204 ++++++++++++-------------- src/renderer/chunk_meshing.zig | 2 +- src/server/server.zig | 36 +++-- 5 files changed, 256 insertions(+), 319 deletions(-) diff --git a/assets/cubyz/shaders/item_drop.fs b/assets/cubyz/shaders/item_drop.fs index c3e41c3b..63251471 100644 --- a/assets/cubyz/shaders/item_drop.fs +++ b/assets/cubyz/shaders/item_drop.fs @@ -3,9 +3,11 @@ in vec3 startPosition; in vec3 direction; in vec3 cameraSpacePos; -flat in int faceNormal; +in vec2 uv; +flat in int faceNormalIndex; +flat in vec3 faceNormal; flat in int voxelModel; -flat in int blockType; +flat in int textureIndex; flat in uvec3 lower; flat in uvec3 upper; @@ -16,6 +18,13 @@ uniform mat4 projectionMatrix; uniform float sizeScale; uniform int time; +uniform sampler2DArray texture_sampler; +uniform sampler2DArray emissionSampler; +uniform sampler2DArray reflectivityAndAbsorptionSampler; +uniform samplerCube reflectionMap; +uniform float reflectionMapSize; +uniform float contrast; + const float[6] normalVariations = float[6]( 1.0, 0.80, @@ -25,191 +34,71 @@ const float[6] normalVariations = float[6]( 0.85 ); -// blockDrops ------------------------------------------------------------------------------------------------------------------------ +layout(std430, binding = 1) buffer _animatedTexture +{ + float animatedTexture[]; +}; -const vec3[6] normals = vec3[6]( - vec3(0, 0, 1), - vec3(0, 0, -1), - vec3(1, 0, 0), - vec3(-1, 0, 0), - vec3(0, 1, 0), - vec3(0, -1, 0) +// block drops ------------------------------------------------------------------------------------------------------------------------- + +float lightVariation(vec3 normal) { + const vec3 directionalPart = vec3(0, contrast/2, contrast); + const float baseLighting = 1 - contrast; + return baseLighting + dot(normal, directionalPart); +} + +vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ + float M = max(max(abs(v.x), abs(v.y)), abs(v.z)); + float scale = (reflectionMapSize - 1)/reflectionMapSize; + if (abs(v.x) != M) v.x *= scale; + if (abs(v.y) != M) v.y *= scale; + if (abs(v.z) != M) v.z *= scale; + return texture(reflectionMap, v); +} + +float ditherThresholds[16] = float[16] ( + 1/17.0, 9/17.0, 3/17.0, 11/17.0, + 13/17.0, 5/17.0, 15/17.0, 7/17.0, + 4/17.0, 12/17.0, 2/17.0, 10/17.0, + 16/17.0, 8/17.0, 14/17.0, 6/17.0 ); -#define modelSize 16 -struct VoxelModel { - ivec4 minimum; - ivec4 maximum; - uint bitPackedData[modelSize*modelSize*modelSize/8]; -}; - - -struct TextureData { - uint textureIndices[6]; -}; - -layout(std430, binding = 1) buffer _textureData -{ - TextureData textureData[]; -}; -layout(std430, binding = 4) buffer _blockVoxelModels -{ - VoxelModel blockVoxelModels[]; -}; -uniform sampler2DArray texture_sampler; -uniform sampler2DArray emissionSampler; - -int getVoxel(int voxelIndex) { - voxelIndex = (voxelIndex & 0xf) | (voxelIndex>>1 & 0xf0) | (voxelIndex>>2 & 0xf00); - int shift = 4*(voxelIndex & 7); - int arrayIndex = voxelIndex >> 3; - return (int(blockVoxelModels[voxelModel].bitPackedData[arrayIndex])>>shift & 15) - 6; -} - -struct RayMarchResult { - bool hitAThing; - int normal; - int textureDir; - ivec3 voxelPosition; -}; - -RayMarchResult rayMarching(vec3 startPosition, vec3 direction) { // TODO: Mipmapped voxel models. (or maybe just remove them when they are far enough away?) - // Branchless implementation of "A Fast Voxel Traversal Algorithm for Ray Tracing" http://www.cse.yorku.ca/~amana/research/grid.pdf - vec3 step = sign(direction); - vec3 stepInIndex = step*vec3(1 << 10, 1 << 5, 1); - int overflowMask = 1<<14 | 1<<9 | 1<<4; - vec3 t1 = (floor(startPosition) - startPosition)/direction; - vec3 tDelta = 1/(direction); - vec3 t2 = t1 + tDelta; - tDelta = abs(tDelta); - vec3 tMax = max(t1, t2) - tDelta; - if(direction.x == 0) tMax.x = 1.0/0.0; - if(direction.y == 0) tMax.y = 1.0/0.0; - if(direction.z == 0) tMax.z = 1.0/0.0; - - ivec3 voxelPos = ivec3(floor(startPosition)); - int voxelIndex = voxelPos.x<<10 | voxelPos.y<<5 | voxelPos.z; // Stores the position as 0b0xxxx0yyyy0zzzz - - int lastNormal = faceNormal; - int block = getVoxel(voxelIndex); - float total_tMax = 0; - - int size = 16; - ivec3 sizeMask = ivec3(size - 1); - int it = 0; - while(block > 0 && it < 48) { - it++; - vec3 tNext = tMax + block*tDelta; - total_tMax = min(tNext.x, min(tNext.y, tNext.z)); - vec3 missingSteps = floor((total_tMax - tMax)/tDelta + 0.00001); - voxelIndex += int(dot(missingSteps, stepInIndex)); - tMax += missingSteps*tDelta; - if((voxelIndex & overflowMask) != 0) - return RayMarchResult(false, 0, 0, ivec3(0, 0, 0)); - block = getVoxel(voxelIndex); - } - if(total_tMax != 0) { - if(tMax.x > tMax.y) { - if(tMax.x > tMax.z) { - lastNormal = 2 + (1 + int(step.x))/2; - } else { - lastNormal = 4 + (1 + int(step.z))/2; - } - } else { - if(tMax.y > tMax.z) { - lastNormal = 0 + (1 + int(step.y))/2; - } else { - lastNormal = 4 + (1 + int(step.z))/2; - } - } - } - voxelPos.x = voxelIndex>>10 & 15; - voxelPos.y = voxelIndex>>5 & 15; - voxelPos.z = voxelIndex & 15; - int textureDir = -block; - if(textureDir == 6) textureDir = lastNormal; - vec3 modifiedCameraSpacePos = cameraSpacePos*(1 + total_tMax*sizeScale*length(direction)/length(cameraSpacePos)); - vec4 projection = projectionMatrix*vec4(modifiedCameraSpacePos, 1); - float depth = projection.z/projection.w; - gl_FragDepth = ((gl_DepthRange.diff * depth) + gl_DepthRange.near + gl_DepthRange.far)/2.0; - return RayMarchResult(true, lastNormal, textureDir, voxelPos); -} - -ivec2 getTextureCoords(ivec3 voxelPosition, int textureDir) { - switch(textureDir) { - case 0: - return ivec2(voxelPosition.x, voxelPosition.y); - case 1: - return ivec2(15 - voxelPosition.x, voxelPosition.y); - case 2: - return ivec2(voxelPosition.y, voxelPosition.z); - case 3: - return ivec2(15 - voxelPosition.y, voxelPosition.z); - case 4: - return ivec2(15 - voxelPosition.x, voxelPosition.z); - case 5: - return ivec2(voxelPosition.x, voxelPosition.z); - } -} - -float getLod(ivec3 voxelPosition, int normal, vec3 direction, float variance) { - return max(0, min(4, log2(variance*length(direction)/abs(dot(vec3(normals[normal]), direction))))); -} - -float perpendicularFwidth(vec3 direction) { // Estimates how big fwidth would be if the fragment normal was perpendicular to the light direction. - vec3 varianceX = dFdx(direction); - vec3 varianceY = dFdx(direction); - varianceX += direction; - varianceX = varianceX*length(direction)/length(varianceX); - varianceX -= direction; - varianceY += direction; - varianceY = varianceY*length(direction)/length(varianceY); - varianceY -= direction; - vec3 variance = abs(varianceX) + abs(varianceY); - return 8*length(variance); -} - -vec4 mipMapSample(sampler2DArray texture, ivec2 textureCoords, uint textureIndex, float lod) { // TODO: anisotropic filtering? - int lowerLod = int(floor(lod)); - int higherLod = lowerLod+1; - float interpolation = lod - lowerLod; - vec4 lower = texelFetch(texture, ivec3(textureCoords >> lowerLod, textureIndex), lowerLod); - vec4 higher = texelFetch(texture, ivec3(textureCoords >> higherLod, textureIndex), higherLod); - return higher*interpolation + (1 - interpolation)*lower; +bool passDitherTest(float alpha) { + ivec2 screenPos = ivec2(gl_FragCoord.xy); + return alpha > ditherThresholds[screenPos.x*4 + screenPos.y]; } void mainBlockDrop() { - RayMarchResult result; - float variance = perpendicularFwidth(direction); - if(variance <= 4.0) { - result = rayMarching(startPosition, direction); - } else { - result = RayMarchResult(true, faceNormal, faceNormal, ivec3(startPosition)); // At some point it doesn't make sense to even draw the model. - } - if(!result.hitAThing) discard; - uint textureIndex = textureData[blockType].textureIndices[result.textureDir]; - float normalVariation = normalVariations[result.normal]; - float lod = getLod(result.voxelPosition, result.normal, direction, variance); - ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir); - fragColor = mipMapSample(texture_sampler, textureCoords, textureIndex, lod)*vec4(ambientLight*normalVariation, 1); + float animatedTextureIndex = animatedTexture[textureIndex]; + float normalVariation = lightVariation(faceNormal); + vec3 textureCoords = vec3(uv, animatedTextureIndex); - if (fragColor.a <= 0.1f) fragColor.a = 1; // TODO: Proper alpha handling. + float reflectivity = texture(reflectivityAndAbsorptionSampler, textureCoords).a; + float fresnelReflection = (1 + dot(normalize(direction), faceNormal)); + fresnelReflection *= fresnelReflection; + fresnelReflection *= min(1, 2*reflectivity); // Limit it to 2*reflectivity to avoid making every block reflective. + reflectivity = reflectivity*fixedCubeMapLookup(reflect(direction, faceNormal)).x; + reflectivity = reflectivity*(1 - fresnelReflection) + fresnelReflection; - fragColor.rgb += mipMapSample(emissionSampler, textureCoords, textureIndex, lod).rgb; + vec3 pixelLight = max(vec3(normalVariation), texture(emissionSampler, textureCoords).r*4); // TODO: light*normalVariation + fragColor = texture(texture_sampler, textureCoords)*vec4(pixelLight, 1); + fragColor.rgb += reflectivity*pixelLight; - fragColor.rgb /= 4; + if(!passDitherTest(fragColor.a)) discard; + fragColor.a = 1; + gl_FragDepth = gl_FragCoord.z; } // itemDrops ------------------------------------------------------------------------------------------------------------------------- -layout(std430, binding = 2) buffer _itemVoxelModels +layout(std430, binding = 2) buffer _modelInfo { - uint itemVoxelModels[]; + uint modelInfo[]; }; uint getVoxel(uvec3 pos) { uint index = (pos.x | pos.y*upper.x)*upper.z | pos.z; - return itemVoxelModels[voxelModel + index]; + return modelInfo[voxelModel + index]; } vec4 decodeColor(uint block) { @@ -229,7 +118,7 @@ void mainItemDrop() { if(direction.z == 0) tMax.z = 1.0/0.0; uvec3 voxelPosition = uvec3(floor(startPosition)); - int lastNormal = faceNormal; + int lastNormal = faceNormalIndex; uint block = getVoxel(voxelPosition); float total_tMax = 0; @@ -286,7 +175,7 @@ void mainItemDrop() { } void main() { - if(blockType != 0) { + if(textureIndex >= 0) { mainBlockDrop(); } else { mainItemDrop(); diff --git a/assets/cubyz/shaders/item_drop.vs b/assets/cubyz/shaders/item_drop.vs index f4043470..4b0ea7e7 100644 --- a/assets/cubyz/shaders/item_drop.vs +++ b/assets/cubyz/shaders/item_drop.vs @@ -1,13 +1,13 @@ #version 430 -layout (location=0) in int positionAndNormals; - out vec3 startPosition; out vec3 direction; out vec3 cameraSpacePos; -flat out int faceNormal; +out vec2 uv; +flat out int faceNormalIndex; +flat out vec3 faceNormal; flat out int voxelModel; -flat out int blockType; +flat out int textureIndex; flat out uvec3 lower; flat out uvec3 upper; @@ -18,47 +18,95 @@ uniform int modelIndex; uniform int block; uniform float sizeScale; -layout(std430, binding = 2) buffer _itemVoxelModels +layout(std430, binding = 2) buffer _modelInfo { - uint itemVoxelModels[]; + uint modelInfo[]; }; -#define modelSize 16 -struct VoxelModel { - ivec4 minimum; - ivec4 maximum; - uint bitPackedData[modelSize*modelSize*modelSize/8]; +struct QuadInfo { + vec3 normal; + vec3 corners[4]; + vec2 cornerUV[4]; + uint textureSlot; }; -layout(std430, binding = 4) buffer _blockVoxelModels +layout(std430, binding = 4) buffer _quads { - VoxelModel blockVoxelModels[]; + QuadInfo quads[]; }; + +const int[24] positions = int[24]( + 0x010, + 0x110, + 0x011, + 0x111, + + 0x000, + 0x001, + 0x100, + 0x101, + + 0x100, + 0x101, + 0x110, + 0x111, + + 0x000, + 0x010, + 0x001, + 0x011, + + 0x001, + 0x011, + 0x101, + 0x111, + + 0x000, + 0x100, + 0x010, + 0x110 +); + void main() { - ivec3 pos = ivec3 ( - positionAndNormals >> 2 & 1, - positionAndNormals >> 1 & 1, - positionAndNormals >> 0 & 1 - ); - faceNormal = positionAndNormals >> 3; + int faceID = gl_VertexID >> 2; + int vertexID = gl_VertexID & 3; int voxelModelIndex = modelIndex; bool isBlock = block != 0; + vec3 pos; if(isBlock) { - lower = uvec3(blockVoxelModels[voxelModelIndex].minimum.xyz); - upper = uvec3(blockVoxelModels[voxelModelIndex].maximum.xyz); + uint modelAndTexture = modelInfo[voxelModelIndex + faceID*2]; + uint offsetByNormal = modelInfo[voxelModelIndex + faceID*2 + 1]; + uint quadIndex = modelAndTexture >> 16u; + textureIndex = int(modelAndTexture & 65535u); + + pos = quads[quadIndex].corners[vertexID]; + uv = quads[quadIndex].cornerUV[vertexID]; + if(offsetByNormal != 0) { + pos += quads[quadIndex].normal; + } + faceNormal = quads[quadIndex].normal; } else { - upper.x = itemVoxelModels[voxelModelIndex++]; - upper.y = itemVoxelModels[voxelModelIndex++]; - upper.z = itemVoxelModels[voxelModelIndex++]; + int position = positions[gl_VertexID]; + pos = vec3 ( + position >> 8 & 1, + position >> 4 & 1, + position >> 0 & 1 + ); + faceNormalIndex = faceID; + upper.x = modelInfo[voxelModelIndex++]; + upper.y = modelInfo[voxelModelIndex++]; + upper.z = modelInfo[voxelModelIndex++]; lower = uvec3(0); + + startPosition = lower + vec3(upper - lower)*0.999*pos; + pos = pos*(upper - lower)*sizeScale + sizeScale/2; + textureIndex = -1; } voxelModel = voxelModelIndex; - blockType = block; - startPosition = lower + vec3(upper - lower)*0.999*pos; - vec4 worldSpace = modelMatrix*vec4(pos*(upper - lower)*sizeScale + sizeScale/2, 1); + vec4 worldSpace = modelMatrix*vec4(pos, 1); direction = (transpose(mat3(modelMatrix))*worldSpace.xyz).xyz; vec4 cameraSpace = viewMatrix*worldSpace; diff --git a/src/itemdrop.zig b/src/itemdrop.zig index dbc16da6..bb9b9900 100644 --- a/src/itemdrop.zig +++ b/src/itemdrop.zig @@ -134,6 +134,16 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager return _data; } + pub fn getInitialList(self: *ItemDropManager, allocator: NeverFailingAllocator) JsonElement { + var list = JsonElement.initArray(allocator); + var ii: u32 = 0; + while(ii < self.size) : (ii += 1) { + const i = self.indices[ii]; + list.JsonArray.append(self.storeSingle(self.lastUpdates.JsonArray.allocator, i)); + } + return list; + } + fn storeSingle(self: *ItemDropManager, allocator: NeverFailingAllocator, i: u16) JsonElement { main.utils.assertLocked(&self.mutex); const obj = JsonElement.initObject(allocator); @@ -182,7 +192,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager pickupCooldown[i] -= 1; despawnTime[i] -= 1; if(despawnTime[i] < 0) { - self.remove(i); + self.removeLocked(i); } else { ii += 1; } @@ -272,9 +282,8 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager self.size += 1; } - pub fn remove(self: *ItemDropManager, i: u16) void { - self.mutex.lock(); - defer self.mutex.unlock(); + fn removeLocked(self: *ItemDropManager, i: u16) void { + main.utils.assertLocked(&self.mutex); self.size -= 1; const ii = self.list.items(.reverseIndex)[i]; self.indices[ii] = self.indices[self.size]; @@ -285,6 +294,12 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager } } + pub fn remove(self: *ItemDropManager, i: u16) void { + self.mutex.lock(); + defer self.mutex.unlock(); + self.removeLocked(i); + } + fn updateEnt(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void { main.utils.assertLocked(&self.mutex); const startedInABlock = self.checkBlocks(chunk, pos); @@ -506,58 +521,84 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer time: c_int, texture_sampler: c_int, emissionSampler: c_int, + reflectivityAndAbsorptionSampler: c_int, + reflectionMap: c_int, + reflectionMapSize: c_int, + contrast: c_int, } = undefined; var itemModelSSBO: graphics.SSBO = undefined; - var itemVAO: c_uint = undefined; - var itemVBOs: [2]c_uint = undefined; var modelData: main.List(u32) = undefined; var freeSlots: main.List(*ItemVoxelModel) = undefined; const ItemVoxelModel = struct { index: u31 = undefined, - size: Vec3i = undefined, + len: u31 = undefined, item: items.Item, + fn getSlot(len: u31) u31 { + for(freeSlots.items, 0..) |potentialSlot, i| { + if(std.meta.eql(len, potentialSlot.len)) { + _ = freeSlots.swapRemove(i); + const result = potentialSlot.index; + main.globalAllocator.destroy(potentialSlot); + return result; + } + } + const result: u31 = @intCast(modelData.items.len); + modelData.resize(result + len); + return result; + } + fn init(template: ItemVoxelModel) *ItemVoxelModel { const self = main.globalAllocator.create(ItemVoxelModel); self.* = ItemVoxelModel{ .item = template.item, }; - // Find sizes and free index: - const img = self.item.getImage(); - self.size = Vec3i{img.width, 1, img.height}; - var freeSlot: ?*ItemVoxelModel = null; - for(freeSlots.items, 0..) |potentialSlot, i| { - if(std.meta.eql(self.size, potentialSlot.size)) { - freeSlot = potentialSlot; - _ = freeSlots.swapRemove(i); - break; + if(self.item == .baseItem and self.item.baseItem.block != null and self.item.baseItem.image.imageData.ptr == graphics.Image.defaultImage.imageData.ptr) { + // Find sizes and free index: + const block = blocks.Block{.typ = self.item.baseItem.block.?, .data = 0}; // TODO: Natural standard + const modelIndex = blocks.meshes.model(block); + const model = &main.models.models.items[modelIndex]; + var data = main.List(u32).init(main.stackAllocator); + defer data.deinit(); + for(model.internalQuads) |quad| { + const textureIndex = blocks.meshes.textureIndex(block, main.models.quads.items[quad].textureSlot); + data.append(@as(u32, quad) << 16 | textureIndex); // modelAndTexture + data.append(0); // offsetByNormal } - } - const modelDataSize: u32 = @intCast(3 + @reduce(.Mul, self.size)); - var dataSection: []u32 = undefined; - if(freeSlot) |_freeSlot| { - main.globalAllocator.destroy(_freeSlot); - self.index = _freeSlot.index; + for(model.neighborFacingQuads) |list| { + for(list) |quad| { + const textureIndex = blocks.meshes.textureIndex(block, main.models.quads.items[quad].textureSlot); + data.append(@as(u32, quad) << 16 | textureIndex); // modelAndTexture + data.append(1); // offsetByNormal + } + } + self.len = @intCast(data.items.len); + self.index = getSlot(self.len); + @memcpy(modelData.items[self.index..][0..self.len], data.items); } else { - self.index = @intCast(modelData.items.len); - modelData.resize(self.index + modelDataSize); - } - dataSection = modelData.items[self.index..][0..modelDataSize]; - dataSection[0] = @intCast(self.size[0]); - dataSection[1] = @intCast(self.size[1]); - dataSection[2] = @intCast(self.size[2]); - var i: u32 = 3; - var z: u32 = 0; - while(z < 1) : (z += 1) { - var x: u32 = 0; - while(x < img.width) : (x += 1) { - var y: u32 = 0; - while(y < img.height) : (y += 1) { - dataSection[i] = img.getRGB(x, y).toARBG(); - i += 1; + // Find sizes and free index: + const img = self.item.getImage(); + const size = Vec3i{img.width, 1, img.height}; + self.len = @intCast(3 + @reduce(.Mul, size)); + self.index = getSlot(self.len); + var dataSection: []u32 = undefined; + dataSection = modelData.items[self.index..][0..self.len]; + dataSection[0] = @intCast(size[0]); + dataSection[1] = @intCast(size[1]); + dataSection[2] = @intCast(size[2]); + var i: u32 = 3; + var z: u32 = 0; + while(z < 1) : (z += 1) { + var x: u32 = 0; + while(x < img.width) : (x += 1) { + var y: u32 = 0; + while(y < img.height) : (y += 1) { + dataSection[i] = img.getRGB(x, y).toARBG(); + i += 1; + } } } } @@ -585,70 +626,6 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer itemModelSSBO.bufferData(i32, &[3]i32{1, 1, 1}); itemModelSSBO.bind(2); - const positions = [_]i32 { - 0b011000, - 0b011001, - 0b011010, - 0b011011, - - 0b001000, - 0b001001, - 0b001100, - 0b001101, - - 0b101000, - 0b101010, - 0b101100, - 0b101110, - - 0b010100, - 0b010101, - 0b010110, - 0b010111, - - 0b000010, - 0b000011, - 0b000110, - 0b000111, - - 0b100001, - 0b100011, - 0b100101, - 0b100111, - }; - const indices = [_]i32 { - 0, 1, 3, - 0, 3, 2, - - 4, 7, 5, - 4, 6, 7, - - 8, 9, 11, - 8, 11, 10, - - 12, 15, 13, - 12, 14, 15, - - 16, 17, 19, - 16, 19, 18, - - 20, 23, 21, - 20, 22, 23, - }; - c.glGenVertexArrays(1, &itemVAO); - c.glBindVertexArray(itemVAO); - c.glEnableVertexAttribArray(0); - - c.glGenBuffers(2, &itemVBOs); - c.glBindBuffer(c.GL_ARRAY_BUFFER, itemVBOs[0]); - c.glBufferData(c.GL_ARRAY_BUFFER, @intCast(positions.len*@sizeOf(i32)), &positions, c.GL_STATIC_DRAW); - c.glVertexAttribPointer(0, 1, c.GL_FLOAT, c.GL_FALSE, @sizeOf(i32), null); - - c.glBindBuffer(c.GL_ELEMENT_ARRAY_BUFFER, itemVBOs[1]); - c.glBufferData(c.GL_ELEMENT_ARRAY_BUFFER, @intCast(indices.len*@sizeOf(i32)), &indices, c.GL_STATIC_DRAW); - - c.glBindVertexArray(0); - modelData = main.List(u32).init(main.globalAllocator); freeSlots = main.List(*ItemVoxelModel).init(main.globalAllocator); } @@ -656,8 +633,6 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer pub fn deinit() void { itemShader.deinit(); itemModelSSBO.deinit(); - c.glDeleteVertexArrays(1, &itemVAO); - c.glDeleteBuffers(2, &itemVBOs); modelData.deinit(); voxelModels.clear(); for(freeSlots.items) |freeSlot| { @@ -668,9 +643,9 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer var voxelModels: utils.Cache(ItemVoxelModel, 32, 32, ItemVoxelModel.deinit) = .{}; - fn getModelIndex(item: items.Item) u31 { + fn getModel(item: items.Item) *ItemVoxelModel { const compareObject = ItemVoxelModel{.item = item}; - return voxelModels.findOrCreate(compareObject, ItemVoxelModel.init, null).index; + return voxelModels.findOrCreate(compareObject, ItemVoxelModel.init, null); } pub fn renderItemDrops(projMatrix: Mat4f, ambientLight: Vec3f, playerPos: Vec3d, time: u32) void { @@ -678,11 +653,15 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer itemShader.bind(); c.glUniform1i(itemUniforms.texture_sampler, 0); c.glUniform1i(itemUniforms.emissionSampler, 1); + c.glUniform1i(itemUniforms.reflectivityAndAbsorptionSampler, 2); + c.glUniform1i(itemUniforms.reflectionMap, 4); + c.glUniform1f(itemUniforms.reflectionMapSize, main.renderer.reflectionCubeMapSize); c.glUniform1i(itemUniforms.time, @as(u31, @truncate(time))); c.glUniformMatrix4fv(itemUniforms.projectionMatrix, 1, c.GL_TRUE, @ptrCast(&projMatrix)); c.glUniform3fv(itemUniforms.ambientLight, 1, @ptrCast(&ambientLight)); c.glUniformMatrix4fv(itemUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&game.camera.viewMatrix)); c.glUniform1f(itemUniforms.sizeScale, @floatCast(ItemDropManager.diameter/4.0)); + c.glUniform1f(itemUniforms.contrast, 0.12); const itemDrops = &game.world.?.itemDrops.super; itemDrops.mutex.lock(); defer itemDrops.mutex.unlock(); @@ -702,18 +681,19 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer modelMatrix = modelMatrix.mul(Mat4f.rotationZ(-rot[2])); c.glUniformMatrix4fv(itemUniforms.modelMatrix, 1, c.GL_TRUE, @ptrCast(&modelMatrix)); + const model = getModel(item); + c.glUniform1i(itemUniforms.modelIndex, model.index); + var vertices: u31 = 36; + if(item == .baseItem and item.baseItem.block != null and item.baseItem.image.imageData.ptr == graphics.Image.defaultImage.imageData.ptr) { const blockType = item.baseItem.block.?; - const block = blocks.Block{.typ = blockType, .data = 0}; - c.glUniform1i(itemUniforms.modelIndex, block.mode().model(block)); c.glUniform1i(itemUniforms.block, blockType); + vertices = model.len/2*6; } else { - const index = getModelIndex(item); - c.glUniform1i(itemUniforms.modelIndex, index); c.glUniform1i(itemUniforms.block, 0); } - c.glBindVertexArray(itemVAO); - c.glDrawElements(c.GL_TRIANGLES, 36, c.GL_UNSIGNED_INT, null); + c.glBindVertexArray(main.renderer.chunk_meshing.vao); + c.glDrawElements(c.GL_TRIANGLES, vertices, c.GL_UNSIGNED_INT, null); } } } diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 7f5bd20c..73c33367 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -62,7 +62,7 @@ pub var occlusionTestUniforms: struct { playerPositionInteger: c_int, playerPositionFraction: c_int, } = undefined; -var vao: c_uint = undefined; +pub var vao: c_uint = undefined; var vbo: c_uint = undefined; pub var faceBuffer: graphics.LargeBuffer(FaceData) = undefined; pub var lightBuffer: graphics.LargeBuffer(u32) = undefined; diff --git a/src/server/server.zig b/src/server/server.zig index a3e9b6e1..41a28fc5 100644 --- a/src/server/server.zig +++ b/src/server/server.zig @@ -252,14 +252,7 @@ fn deinit() void { command.deinit(); } -fn update() void { // MARK: update() - world.?.update(); - mutex.lock(); - for(users.items) |user| { - user.update(); - } - mutex.unlock(); - +fn sendEntityUpdates(comptime getInitialList: bool, allocator: utils.NeverFailingAllocator) if(getInitialList) []const u8 else void { // Send the entity updates: const updateList = main.JsonElement.initArray(main.stackAllocator); defer updateList.free(main.stackAllocator); @@ -276,13 +269,37 @@ fn update() void { // MARK: update() world.?.itemDropManager.lastUpdates.free(alloc); world.?.itemDropManager.lastUpdates = main.JsonElement.initArray(alloc); } + var initialList: []const u8 = undefined; + if(getInitialList) { + const list = main.JsonElement.initArray(main.stackAllocator); + defer list.free(main.stackAllocator); + list.JsonArray.append(.{.JsonNull = {}}); + const itemDropList = world.?.itemDropManager.getInitialList(main.stackAllocator); + list.JsonArray.appendSlice(itemDropList.JsonArray.items); + itemDropList.JsonArray.items.len = 0; + itemDropList.free(main.stackAllocator); + initialList = list.toStringEfficient(allocator, &.{}); + } world.?.itemDropManager.mutex.unlock(); mutex.lock(); for(users.items) |user| { main.network.Protocols.entity.send(user.conn, updateData); } mutex.unlock(); + if(getInitialList) { + return initialList; + } +} +fn update() void { // MARK: update() + world.?.update(); + mutex.lock(); + for(users.items) |user| { + user.update(); + } + mutex.unlock(); + + sendEntityUpdates(false, main.stackAllocator); // Send the entity data: @@ -415,6 +432,9 @@ pub fn connect(user: *User) void { if(user.connected.load(.unordered)) main.network.Protocols.entity.send(user.conn, data); } + const initialList = sendEntityUpdates(true, main.stackAllocator); + main.network.Protocols.entity.send(user.conn, initialList); + main.stackAllocator.free(initialList); const message = std.fmt.allocPrint(main.stackAllocator.allocator, "{s} #ffff00joined", .{user.name}) catch unreachable; defer main.stackAllocator.free(message); mutex.lock();