Implement block drop rendering and fix a couple synchronization issues.

This commit is contained in:
IntegratedQuantum 2024-08-17 11:01:22 +02:00
parent 44bb49ee5b
commit 3a6f55b8e7
5 changed files with 256 additions and 319 deletions

View File

@ -3,9 +3,11 @@
in vec3 startPosition; in vec3 startPosition;
in vec3 direction; in vec3 direction;
in vec3 cameraSpacePos; 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 voxelModel;
flat in int blockType; flat in int textureIndex;
flat in uvec3 lower; flat in uvec3 lower;
flat in uvec3 upper; flat in uvec3 upper;
@ -16,6 +18,13 @@ uniform mat4 projectionMatrix;
uniform float sizeScale; uniform float sizeScale;
uniform int time; 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]( const float[6] normalVariations = float[6](
1.0, 1.0,
0.80, 0.80,
@ -25,191 +34,71 @@ const float[6] normalVariations = float[6](
0.85 0.85
); );
// blockDrops ------------------------------------------------------------------------------------------------------------------------ layout(std430, binding = 1) buffer _animatedTexture
{
float animatedTexture[];
};
const vec3[6] normals = vec3[6]( // block drops -------------------------------------------------------------------------------------------------------------------------
vec3(0, 0, 1),
vec3(0, 0, -1), float lightVariation(vec3 normal) {
vec3(1, 0, 0), const vec3 directionalPart = vec3(0, contrast/2, contrast);
vec3(-1, 0, 0), const float baseLighting = 1 - contrast;
vec3(0, 1, 0), return baseLighting + dot(normal, directionalPart);
vec3(0, -1, 0) }
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 bool passDitherTest(float alpha) {
struct VoxelModel { ivec2 screenPos = ivec2(gl_FragCoord.xy);
ivec4 minimum; return alpha > ditherThresholds[screenPos.x*4 + screenPos.y];
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;
} }
void mainBlockDrop() { void mainBlockDrop() {
RayMarchResult result; float animatedTextureIndex = animatedTexture[textureIndex];
float variance = perpendicularFwidth(direction); float normalVariation = lightVariation(faceNormal);
if(variance <= 4.0) { vec3 textureCoords = vec3(uv, animatedTextureIndex);
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);
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 ------------------------------------------------------------------------------------------------------------------------- // itemDrops -------------------------------------------------------------------------------------------------------------------------
layout(std430, binding = 2) buffer _itemVoxelModels layout(std430, binding = 2) buffer _modelInfo
{ {
uint itemVoxelModels[]; uint modelInfo[];
}; };
uint getVoxel(uvec3 pos) { uint getVoxel(uvec3 pos) {
uint index = (pos.x | pos.y*upper.x)*upper.z | pos.z; uint index = (pos.x | pos.y*upper.x)*upper.z | pos.z;
return itemVoxelModels[voxelModel + index]; return modelInfo[voxelModel + index];
} }
vec4 decodeColor(uint block) { vec4 decodeColor(uint block) {
@ -229,7 +118,7 @@ void mainItemDrop() {
if(direction.z == 0) tMax.z = 1.0/0.0; if(direction.z == 0) tMax.z = 1.0/0.0;
uvec3 voxelPosition = uvec3(floor(startPosition)); uvec3 voxelPosition = uvec3(floor(startPosition));
int lastNormal = faceNormal; int lastNormal = faceNormalIndex;
uint block = getVoxel(voxelPosition); uint block = getVoxel(voxelPosition);
float total_tMax = 0; float total_tMax = 0;
@ -286,7 +175,7 @@ void mainItemDrop() {
} }
void main() { void main() {
if(blockType != 0) { if(textureIndex >= 0) {
mainBlockDrop(); mainBlockDrop();
} else { } else {
mainItemDrop(); mainItemDrop();

View File

@ -1,13 +1,13 @@
#version 430 #version 430
layout (location=0) in int positionAndNormals;
out vec3 startPosition; out vec3 startPosition;
out vec3 direction; out vec3 direction;
out vec3 cameraSpacePos; 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 voxelModel;
flat out int blockType; flat out int textureIndex;
flat out uvec3 lower; flat out uvec3 lower;
flat out uvec3 upper; flat out uvec3 upper;
@ -18,47 +18,95 @@ uniform int modelIndex;
uniform int block; uniform int block;
uniform float sizeScale; uniform float sizeScale;
layout(std430, binding = 2) buffer _itemVoxelModels layout(std430, binding = 2) buffer _modelInfo
{ {
uint itemVoxelModels[]; uint modelInfo[];
}; };
#define modelSize 16 struct QuadInfo {
struct VoxelModel { vec3 normal;
ivec4 minimum; vec3 corners[4];
ivec4 maximum; vec2 cornerUV[4];
uint bitPackedData[modelSize*modelSize*modelSize/8]; 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() { void main() {
ivec3 pos = ivec3 ( int faceID = gl_VertexID >> 2;
positionAndNormals >> 2 & 1, int vertexID = gl_VertexID & 3;
positionAndNormals >> 1 & 1,
positionAndNormals >> 0 & 1
);
faceNormal = positionAndNormals >> 3;
int voxelModelIndex = modelIndex; int voxelModelIndex = modelIndex;
bool isBlock = block != 0; bool isBlock = block != 0;
vec3 pos;
if(isBlock) { if(isBlock) {
lower = uvec3(blockVoxelModels[voxelModelIndex].minimum.xyz); uint modelAndTexture = modelInfo[voxelModelIndex + faceID*2];
upper = uvec3(blockVoxelModels[voxelModelIndex].maximum.xyz); 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 { } else {
upper.x = itemVoxelModels[voxelModelIndex++]; int position = positions[gl_VertexID];
upper.y = itemVoxelModels[voxelModelIndex++]; pos = vec3 (
upper.z = itemVoxelModels[voxelModelIndex++]; 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); lower = uvec3(0);
startPosition = lower + vec3(upper - lower)*0.999*pos;
pos = pos*(upper - lower)*sizeScale + sizeScale/2;
textureIndex = -1;
} }
voxelModel = voxelModelIndex; 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; direction = (transpose(mat3(modelMatrix))*worldSpace.xyz).xyz;
vec4 cameraSpace = viewMatrix*worldSpace; vec4 cameraSpace = viewMatrix*worldSpace;

View File

@ -134,6 +134,16 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
return _data; 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 { fn storeSingle(self: *ItemDropManager, allocator: NeverFailingAllocator, i: u16) JsonElement {
main.utils.assertLocked(&self.mutex); main.utils.assertLocked(&self.mutex);
const obj = JsonElement.initObject(allocator); const obj = JsonElement.initObject(allocator);
@ -182,7 +192,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
pickupCooldown[i] -= 1; pickupCooldown[i] -= 1;
despawnTime[i] -= 1; despawnTime[i] -= 1;
if(despawnTime[i] < 0) { if(despawnTime[i] < 0) {
self.remove(i); self.removeLocked(i);
} else { } else {
ii += 1; ii += 1;
} }
@ -272,9 +282,8 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
self.size += 1; self.size += 1;
} }
pub fn remove(self: *ItemDropManager, i: u16) void { fn removeLocked(self: *ItemDropManager, i: u16) void {
self.mutex.lock(); main.utils.assertLocked(&self.mutex);
defer self.mutex.unlock();
self.size -= 1; self.size -= 1;
const ii = self.list.items(.reverseIndex)[i]; const ii = self.list.items(.reverseIndex)[i];
self.indices[ii] = self.indices[self.size]; 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 { fn updateEnt(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {
main.utils.assertLocked(&self.mutex); main.utils.assertLocked(&self.mutex);
const startedInABlock = self.checkBlocks(chunk, pos); const startedInABlock = self.checkBlocks(chunk, pos);
@ -506,58 +521,84 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer
time: c_int, time: c_int,
texture_sampler: c_int, texture_sampler: c_int,
emissionSampler: c_int, emissionSampler: c_int,
reflectivityAndAbsorptionSampler: c_int,
reflectionMap: c_int,
reflectionMapSize: c_int,
contrast: c_int,
} = undefined; } = undefined;
var itemModelSSBO: graphics.SSBO = undefined; var itemModelSSBO: graphics.SSBO = undefined;
var itemVAO: c_uint = undefined;
var itemVBOs: [2]c_uint = undefined;
var modelData: main.List(u32) = undefined; var modelData: main.List(u32) = undefined;
var freeSlots: main.List(*ItemVoxelModel) = undefined; var freeSlots: main.List(*ItemVoxelModel) = undefined;
const ItemVoxelModel = struct { const ItemVoxelModel = struct {
index: u31 = undefined, index: u31 = undefined,
size: Vec3i = undefined, len: u31 = undefined,
item: items.Item, 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 { fn init(template: ItemVoxelModel) *ItemVoxelModel {
const self = main.globalAllocator.create(ItemVoxelModel); const self = main.globalAllocator.create(ItemVoxelModel);
self.* = ItemVoxelModel{ self.* = ItemVoxelModel{
.item = template.item, .item = template.item,
}; };
// Find sizes and free index: if(self.item == .baseItem and self.item.baseItem.block != null and self.item.baseItem.image.imageData.ptr == graphics.Image.defaultImage.imageData.ptr) {
const img = self.item.getImage(); // Find sizes and free index:
self.size = Vec3i{img.width, 1, img.height}; const block = blocks.Block{.typ = self.item.baseItem.block.?, .data = 0}; // TODO: Natural standard
var freeSlot: ?*ItemVoxelModel = null; const modelIndex = blocks.meshes.model(block);
for(freeSlots.items, 0..) |potentialSlot, i| { const model = &main.models.models.items[modelIndex];
if(std.meta.eql(self.size, potentialSlot.size)) { var data = main.List(u32).init(main.stackAllocator);
freeSlot = potentialSlot; defer data.deinit();
_ = freeSlots.swapRemove(i); for(model.internalQuads) |quad| {
break; const textureIndex = blocks.meshes.textureIndex(block, main.models.quads.items[quad].textureSlot);
data.append(@as(u32, quad) << 16 | textureIndex); // modelAndTexture
data.append(0); // offsetByNormal
} }
} for(model.neighborFacingQuads) |list| {
const modelDataSize: u32 = @intCast(3 + @reduce(.Mul, self.size)); for(list) |quad| {
var dataSection: []u32 = undefined; const textureIndex = blocks.meshes.textureIndex(block, main.models.quads.items[quad].textureSlot);
if(freeSlot) |_freeSlot| { data.append(@as(u32, quad) << 16 | textureIndex); // modelAndTexture
main.globalAllocator.destroy(_freeSlot); data.append(1); // offsetByNormal
self.index = _freeSlot.index; }
}
self.len = @intCast(data.items.len);
self.index = getSlot(self.len);
@memcpy(modelData.items[self.index..][0..self.len], data.items);
} else { } else {
self.index = @intCast(modelData.items.len); // Find sizes and free index:
modelData.resize(self.index + modelDataSize); const img = self.item.getImage();
} const size = Vec3i{img.width, 1, img.height};
dataSection = modelData.items[self.index..][0..modelDataSize]; self.len = @intCast(3 + @reduce(.Mul, size));
dataSection[0] = @intCast(self.size[0]); self.index = getSlot(self.len);
dataSection[1] = @intCast(self.size[1]); var dataSection: []u32 = undefined;
dataSection[2] = @intCast(self.size[2]); dataSection = modelData.items[self.index..][0..self.len];
var i: u32 = 3; dataSection[0] = @intCast(size[0]);
var z: u32 = 0; dataSection[1] = @intCast(size[1]);
while(z < 1) : (z += 1) { dataSection[2] = @intCast(size[2]);
var x: u32 = 0; var i: u32 = 3;
while(x < img.width) : (x += 1) { var z: u32 = 0;
var y: u32 = 0; while(z < 1) : (z += 1) {
while(y < img.height) : (y += 1) { var x: u32 = 0;
dataSection[i] = img.getRGB(x, y).toARBG(); while(x < img.width) : (x += 1) {
i += 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.bufferData(i32, &[3]i32{1, 1, 1});
itemModelSSBO.bind(2); 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); modelData = main.List(u32).init(main.globalAllocator);
freeSlots = main.List(*ItemVoxelModel).init(main.globalAllocator); freeSlots = main.List(*ItemVoxelModel).init(main.globalAllocator);
} }
@ -656,8 +633,6 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer
pub fn deinit() void { pub fn deinit() void {
itemShader.deinit(); itemShader.deinit();
itemModelSSBO.deinit(); itemModelSSBO.deinit();
c.glDeleteVertexArrays(1, &itemVAO);
c.glDeleteBuffers(2, &itemVBOs);
modelData.deinit(); modelData.deinit();
voxelModels.clear(); voxelModels.clear();
for(freeSlots.items) |freeSlot| { for(freeSlots.items) |freeSlot| {
@ -668,9 +643,9 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer
var voxelModels: utils.Cache(ItemVoxelModel, 32, 32, ItemVoxelModel.deinit) = .{}; 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}; 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 { pub fn renderItemDrops(projMatrix: Mat4f, ambientLight: Vec3f, playerPos: Vec3d, time: u32) void {
@ -678,11 +653,15 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer
itemShader.bind(); itemShader.bind();
c.glUniform1i(itemUniforms.texture_sampler, 0); c.glUniform1i(itemUniforms.texture_sampler, 0);
c.glUniform1i(itemUniforms.emissionSampler, 1); 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.glUniform1i(itemUniforms.time, @as(u31, @truncate(time)));
c.glUniformMatrix4fv(itemUniforms.projectionMatrix, 1, c.GL_TRUE, @ptrCast(&projMatrix)); c.glUniformMatrix4fv(itemUniforms.projectionMatrix, 1, c.GL_TRUE, @ptrCast(&projMatrix));
c.glUniform3fv(itemUniforms.ambientLight, 1, @ptrCast(&ambientLight)); c.glUniform3fv(itemUniforms.ambientLight, 1, @ptrCast(&ambientLight));
c.glUniformMatrix4fv(itemUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&game.camera.viewMatrix)); c.glUniformMatrix4fv(itemUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&game.camera.viewMatrix));
c.glUniform1f(itemUniforms.sizeScale, @floatCast(ItemDropManager.diameter/4.0)); c.glUniform1f(itemUniforms.sizeScale, @floatCast(ItemDropManager.diameter/4.0));
c.glUniform1f(itemUniforms.contrast, 0.12);
const itemDrops = &game.world.?.itemDrops.super; const itemDrops = &game.world.?.itemDrops.super;
itemDrops.mutex.lock(); itemDrops.mutex.lock();
defer itemDrops.mutex.unlock(); defer itemDrops.mutex.unlock();
@ -702,18 +681,19 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer
modelMatrix = modelMatrix.mul(Mat4f.rotationZ(-rot[2])); modelMatrix = modelMatrix.mul(Mat4f.rotationZ(-rot[2]));
c.glUniformMatrix4fv(itemUniforms.modelMatrix, 1, c.GL_TRUE, @ptrCast(&modelMatrix)); 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) { 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 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); c.glUniform1i(itemUniforms.block, blockType);
vertices = model.len/2*6;
} else { } else {
const index = getModelIndex(item);
c.glUniform1i(itemUniforms.modelIndex, index);
c.glUniform1i(itemUniforms.block, 0); c.glUniform1i(itemUniforms.block, 0);
} }
c.glBindVertexArray(itemVAO); c.glBindVertexArray(main.renderer.chunk_meshing.vao);
c.glDrawElements(c.GL_TRIANGLES, 36, c.GL_UNSIGNED_INT, null); c.glDrawElements(c.GL_TRIANGLES, vertices, c.GL_UNSIGNED_INT, null);
} }
} }
} }

View File

@ -62,7 +62,7 @@ pub var occlusionTestUniforms: struct {
playerPositionInteger: c_int, playerPositionInteger: c_int,
playerPositionFraction: c_int, playerPositionFraction: c_int,
} = undefined; } = undefined;
var vao: c_uint = undefined; pub var vao: c_uint = undefined;
var vbo: c_uint = undefined; var vbo: c_uint = undefined;
pub var faceBuffer: graphics.LargeBuffer(FaceData) = undefined; pub var faceBuffer: graphics.LargeBuffer(FaceData) = undefined;
pub var lightBuffer: graphics.LargeBuffer(u32) = undefined; pub var lightBuffer: graphics.LargeBuffer(u32) = undefined;

View File

@ -252,14 +252,7 @@ fn deinit() void {
command.deinit(); command.deinit();
} }
fn update() void { // MARK: update() fn sendEntityUpdates(comptime getInitialList: bool, allocator: utils.NeverFailingAllocator) if(getInitialList) []const u8 else void {
world.?.update();
mutex.lock();
for(users.items) |user| {
user.update();
}
mutex.unlock();
// Send the entity updates: // Send the entity updates:
const updateList = main.JsonElement.initArray(main.stackAllocator); const updateList = main.JsonElement.initArray(main.stackAllocator);
defer updateList.free(main.stackAllocator); defer updateList.free(main.stackAllocator);
@ -276,13 +269,37 @@ fn update() void { // MARK: update()
world.?.itemDropManager.lastUpdates.free(alloc); world.?.itemDropManager.lastUpdates.free(alloc);
world.?.itemDropManager.lastUpdates = main.JsonElement.initArray(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(); world.?.itemDropManager.mutex.unlock();
mutex.lock(); mutex.lock();
for(users.items) |user| { for(users.items) |user| {
main.network.Protocols.entity.send(user.conn, updateData); main.network.Protocols.entity.send(user.conn, updateData);
} }
mutex.unlock(); 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: // 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); 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; const message = std.fmt.allocPrint(main.stackAllocator.allocator, "{s} #ffff00joined", .{user.name}) catch unreachable;
defer main.stackAllocator.free(message); defer main.stackAllocator.free(message);
mutex.lock(); mutex.lock();