mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-08 03:29:48 -04:00
Implement block drop rendering and fix a couple synchronization issues.
This commit is contained in:
parent
44bb49ee5b
commit
3a6f55b8e7
@ -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();
|
||||
|
@ -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;
|
||||
|
204
src/itemdrop.zig
204
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user