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 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();

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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();