From 0368e3d6547a5c7da2095d893ee70857945a1e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9?= Date: Tue, 18 Feb 2025 07:34:16 +0600 Subject: [PATCH] - --- Src/Client/Abstract.hpp | 2 +- Src/Client/ServerSession.cpp | 11 +- Src/Client/Vulkan/VulkanRenderSession.cpp | 116 +++++++++-- assets/shaders/chunk/voxel.geom | 190 ++++++++++-------- assets/shaders/chunk/voxel.geom.bin | Bin 16300 -> 17132 bytes assets/shaders/chunk/voxel_opaque.frag | 24 ++- assets/shaders/chunk/voxel_opaque.frag.bin | Bin 6268 -> 7188 bytes assets/shaders/chunk/voxel_transparent.frag | 1 + .../shaders/chunk/voxel_transparent.frag.bin | Bin 1264 -> 1288 bytes assets/{ => textures}/grass.png | Bin assets/textures/tropical_rainforest_wood.png | Bin 0 -> 2089 bytes assets/textures/willow_wood.png | Bin 0 -> 1453 bytes assets/textures/xnether_blue_wood.png | Bin 0 -> 5940 bytes assets/textures/xnether_purple_wood.png | Bin 0 -> 6101 bytes 14 files changed, 238 insertions(+), 106 deletions(-) rename assets/{ => textures}/grass.png (100%) create mode 100644 assets/textures/tropical_rainforest_wood.png create mode 100644 assets/textures/willow_wood.png create mode 100644 assets/textures/xnether_blue_wood.png create mode 100644 assets/textures/xnether_purple_wood.png diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index 185bd59..429b202 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -32,7 +32,7 @@ struct GlobalTime { struct VoxelCube { DefVoxelId_c VoxelId; - Pos::Local256_u Left, Right; + Pos::Local256_u Left, Size; }; struct Node { diff --git a/Src/Client/ServerSession.cpp b/Src/Client/ServerSession.cpp index e415b5d..dc49660 100644 --- a/Src/Client/ServerSession.cpp +++ b/Src/Client/ServerSession.cpp @@ -157,7 +157,8 @@ void ServerSession::onResize(uint32_t width, uint32_t height) { } void ServerSession::onChangeFocusState(bool isFocused) { - + if(!isFocused) + CursorMode = EnumCursorMoveMode::Default; } void ServerSession::onCursorPosChange(int32_t width, int32_t height) { @@ -273,7 +274,7 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) { float deltaTime = 1-std::min(gTime-PYR_At, 1/PYR_TIME_DELTA)*PYR_TIME_DELTA; glm::quat quat = - glm::angleAxis(PYR.x-deltaTime*PYR_Offset.x, glm::vec3(-1.f, 0.f, 0.f)) + glm::angleAxis(PYR.x-deltaTime*PYR_Offset.x, glm::vec3(1.f, 0.f, 0.f)) * glm::angleAxis(PYR.y-deltaTime*PYR_Offset.y, glm::vec3(0.f, -1.f, 0.f)); RS->setCameraPos(0, Pos, quat); @@ -465,9 +466,9 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) { cube.Left.X = co_await sock.read(); cube.Left.Y = co_await sock.read(); cube.Left.Z = co_await sock.read(); - cube.Right.X = co_await sock.read(); - cube.Right.Y = co_await sock.read(); - cube.Right.Z = co_await sock.read(); + cube.Size.X = co_await sock.read(); + cube.Size.Y = co_await sock.read(); + cube.Size.Z = co_await sock.read(); } PP_Content_ChunkVoxels *packet = new PP_Content_ChunkVoxels( diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index 6b723c1..194edf7 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -3,6 +3,7 @@ #include "Client/Vulkan/Vulkan.hpp" #include "Common/Abstract.hpp" #include "assets.hpp" +#include "glm/trigonometric.hpp" #include #include #include @@ -194,9 +195,17 @@ void VulkanRenderSession::init(Vulkan *instance) { int width, height; bool hasAlpha; - ByteBuffer image = VK::loadPNG(std::ifstream("/home/mr_s/Workspace/Alpha/LuaVox/assets/grass.png"), width, height, hasAlpha); - uint16_t texId = VKCTX->MainTest.atlasAddTexture(width, height); - VKCTX->MainTest.atlasChangeTextureData(texId, (const uint32_t*) image.data()); + for(const char *path : { + "grass.png", + "tropical_rainforest_wood.png", + "willow_wood.png", + "xnether_blue_wood.png", + "xnether_purple_wood.png" + }) { + ByteBuffer image = VK::loadPNG(getResource(std::string("textures/") + path)->makeStream().Stream, width, height, hasAlpha); + uint16_t texId = VKCTX->MainTest.atlasAddTexture(width, height); + VKCTX->MainTest.atlasChangeTextureData(texId, (const uint32_t*) image.data()); + } /* x left -1 ~ right 1 @@ -221,15 +230,22 @@ void VulkanRenderSession::init(Vulkan *instance) { { std::vector cubes; - cubes.emplace_back(0, Pos::Local256_u{0, 0, 0}, Pos::Local256_u{1, 1, 1}); + cubes.emplace_back(0, Pos::Local256_u{0, 0, 0}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(1, Pos::Local256_u{255, 0, 0}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(1, Pos::Local256_u{0, 255, 0}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(1, Pos::Local256_u{0, 0, 255}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(2, Pos::Local256_u{255, 255, 0}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(2, Pos::Local256_u{0, 255, 255}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(2, Pos::Local256_u{255, 0, 255}, Pos::Local256_u{0, 0, 0}); + cubes.emplace_back(3, Pos::Local256_u{255, 255, 255}, Pos::Local256_u{0, 0, 0}); + + cubes.emplace_back(4, Pos::Local256_u{64, 64, 64}, Pos::Local256_u{127, 127, 127}); std::vector vertexs = generateMeshForVoxelChunks(cubes); if(!vertexs.empty()) { VKCTX->TestVoxel.emplace(VkInst, vertexs.size()*sizeof(VoxelVertexPoint)); - VoxelVertexPoint *result = (VoxelVertexPoint*) VKCTX->TestVoxel->mapMemory(); - std::copy(vertexs.data(), vertexs.data()+vertexs.size(), result); - TOS::Logger("Test").debug() << result[0].FX << " " << result[0].FY << " " << result[0].FZ; + std::copy(vertexs.data(), vertexs.data()+vertexs.size(), (VoxelVertexPoint*) VKCTX->TestVoxel->mapMemory()); VKCTX->TestVoxel->unMapMemory(); } } @@ -655,11 +671,19 @@ void VulkanRenderSession::beforeDraw() { } void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd) { - glm::mat4 proj = glm::perspective(75, float(VkInst->Screen.Width)/float(VkInst->Screen.Height), 0.5, std::pow(2, 17)); - // Сместить в координаты игрока, повернуть относительно взгляда, ещё поворот на 180 и проецировать на экран + glm::mat4 proj = glm::perspective(glm::radians(75.f), float(VkInst->Screen.Width)/float(VkInst->Screen.Height), 0.5, std::pow(2, 17)); + + for(int i = 0; i < 4; i++) { + proj[1][i] *= -1; + proj[2][i] *= -1; + } + + + // Сместить в координаты игрока, повернуть относительно взгляда проецировать на экран + // Изначально взгляд в z-1 PCO.ProjView = glm::mat4(1); PCO.ProjView = glm::translate(PCO.ProjView, -glm::vec3(Pos)/float(Pos::Object_t::BS)); - PCO.ProjView = proj*glm::mat4(Quat)*glm::rotate(glm::mat4(1), glm::pi(), glm::vec3(0, 1, 0))*PCO.ProjView; + PCO.ProjView = proj*glm::mat4(Quat)*PCO.ProjView; PCO.Model = glm::mat4(1); vkCmdBindPipeline(drawCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, NodeStaticOpaquePipeline); @@ -692,6 +716,7 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff if(VKCTX->TestVoxel) { vkBuffer = *VKCTX->TestVoxel; + vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets); vkCmdDraw(drawCmd, VKCTX->TestVoxel->getSize() / sizeof(VoxelVertexPoint), 1, 0, 0); } } @@ -706,9 +731,74 @@ std::vector VulkanRenderSession::generateMeshForVoxelChunks(co cube.Left.Y, cube.Left.Z, 0, - 0, - cube.Right.X-cube.Left.X, - cube.Right.Z-cube.Left.Z, + 0, 0, + cube.Size.X, + cube.Size.Z, + cube.VoxelId, + 0, 0, + 0 + ); + + out.emplace_back( + cube.Left.X, + cube.Left.Y, + cube.Left.Z, + 1, + 0, 0, + cube.Size.X, + cube.Size.Y, + cube.VoxelId, + 0, 0, + 0 + ); + + out.emplace_back( + cube.Left.X, + cube.Left.Y, + cube.Left.Z, + 2, + 0, 0, + cube.Size.Z, + cube.Size.Y, + cube.VoxelId, + 0, 0, + 0 + ); + + out.emplace_back( + cube.Left.X, + cube.Left.Y+cube.Size.Y+1, + cube.Left.Z, + 3, + 0, 0, + cube.Size.X, + cube.Size.Z, + cube.VoxelId, + 0, 0, + 0 + ); + + out.emplace_back( + cube.Left.X, + cube.Left.Y, + cube.Left.Z+cube.Size.Z+1, + 4, + 0, 0, + cube.Size.X, + cube.Size.Y, + cube.VoxelId, + 0, 0, + 0 + ); + + out.emplace_back( + cube.Left.X+cube.Size.X+1, + cube.Left.Y, + cube.Left.Z, + 5, + 0, 0, + cube.Size.Z, + cube.Size.Y, cube.VoxelId, 0, 0, 0 diff --git a/assets/shaders/chunk/voxel.geom b/assets/shaders/chunk/voxel.geom index 1afc36e..c0e5317 100644 --- a/assets/shaders/chunk/voxel.geom +++ b/assets/shaders/chunk/voxel.geom @@ -5,11 +5,12 @@ layout (triangle_strip, max_vertices = 4) out; layout(location = 0) in highp uvec3 Geometry[]; -layout(location = 0) out Fragment { +layout(location = 0) out FragmentObj { vec3 GeoPos; // Реальная позиция в мире - uint VoxMTL; // Материал вокселя + flat uint VoxMTL; // Материал вокселя vec2 LUV; -} fragment; + flat uint Place; +} Fragment; layout(push_constant) uniform UniformBufferObject { mat4 projview; @@ -43,195 +44,214 @@ void main() { uint voxMTL = ((Geometry[0].y >> 16) & 0xffff); vec2 luv = vec2(float(Geometry[0].z & 0x3fff)+0.5f, float((Geometry[0].z >> 14) & 0x3fff)+0.5f); + int place = int(Geometry[0].x >> 27) & 0x7; // Стартовая вершина vec4 tempVec = baseVec; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv; + Fragment.GeoPos = vec3(tempVec); + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv; + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); - int place = int(Geometry[0].x >> 27) & 0x3; switch(place) { case 0: // xz tempVec = baseVec; - tempVec.x += size.x; + tempVec.z += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, 0); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(0, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.z += size.y; + tempVec.x += size.x / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(0, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, 0); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.x += size.x; - tempVec.z += size.y; + tempVec.x += size.x / 16.f; + tempVec.z += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); break; case 1: // xy tempVec = baseVec; - tempVec.x += size.x; + tempVec.x += size.x / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, 0); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, 0); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.y += size.y; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(0, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(0, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.x += size.x; - tempVec.y += size.y; + tempVec.x += size.x / 16.f; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); break; case 2: // zy tempVec = baseVec; - tempVec.z += size.x; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, 0); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(0, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.y += size.y; + tempVec.z += size.x / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(0, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, 0); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.z += size.x; - tempVec.y += size.y; + tempVec.z += size.x / 16.f; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); break; case 3: // xz inv tempVec = baseVec; - tempVec.z += size.y; + tempVec.x += size.x / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, 0); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, 0); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.x += size.x; + tempVec.z += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(0, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(0, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.x += size.x; - tempVec.z += size.y; + tempVec.x += size.x / 16.f; + tempVec.z += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); break; case 4: // xy inv tempVec = baseVec; - tempVec.y += size.y; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, 0); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(0, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.x += size.x; + tempVec.x += size.x / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(0, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, 0); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.x += size.x; - tempVec.y += size.y; + tempVec.x += size.x / 16.f; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); break; case 5: // zy inv tempVec = baseVec; - tempVec.y += size.y; + tempVec.z += size.x / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, 0); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, 0); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.z += size.x; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(0, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(0, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); tempVec = baseVec; - tempVec.z += size.x; - tempVec.y += size.y; + tempVec.z += size.x / 16.f; + tempVec.y += size.y / 16.f; tempVec = ubo.model*tempVec; - fragment.GeoPos = vec3(tempVec); - fragment.VoxMTL = voxMTL; - fragment.LUV = luv+vec2(size.x, size.y); + Fragment.GeoPos = tempVec.xyz; + Fragment.VoxMTL = voxMTL; + Fragment.LUV = luv+vec2(size.x, size.y); + Fragment.Place = place; gl_Position = ubo.projview*tempVec; EmitVertex(); diff --git a/assets/shaders/chunk/voxel.geom.bin b/assets/shaders/chunk/voxel.geom.bin index 1aa3a6e8b8b32803dbccd3294b4812491f1c1c45..a6472dc0e4c47cd311a2f20985486bf6ae26ab5d 100644 GIT binary patch literal 17132 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 H{L8|BQoglB delta 730 zcmY*WO-lk%6umk#4rxw-i-JfhA!rx0DWV_*Z82g*xoI_lSfP%XMXiSV2W9KFt;7G* zw(L8rY15)}o}{K$p1X+4O@6YLY_%WZX3OXxx} zQ+FywcmrR%d8Q@2HV{v?=x(@&A`vRUAy~mZ$!*!>bj5|i+1mw`&GM*LsuZgYT*2w` z3}185BET>Iu%X7W_e*|vJ=-^M{cj{xWa=eQouZn_a|{-0Gs*n zEZ!|f+`5irG;a#pJ$MZkgDnS`FF`Jeh4`;`U=i35j5&|+tVNAE#9W9R_1ECeJnA>_ zd}^L#une>b75oiy7{;v_OzcbZE;{R(xbn^DDMjJ=X2h$gLv0SWhB?{u4aParuoc9! t|2vF)9$B3KBjCvMaAwwGU203%l>ee5GA1Lqun9#5@yB$eb!nZ){{S=WZHxc_ diff --git a/assets/shaders/chunk/voxel_transparent.frag b/assets/shaders/chunk/voxel_transparent.frag index b1a6436..d5aa336 100644 --- a/assets/shaders/chunk/voxel_transparent.frag +++ b/assets/shaders/chunk/voxel_transparent.frag @@ -4,6 +4,7 @@ layout(location = 0) in Fragment { vec3 GeoPos; // Реальная позиция в мире uint VoxMTL; // Материал вокселя vec2 LUV; + uint Place; } fragment; layout(location = 0) out vec4 Frame; diff --git a/assets/shaders/chunk/voxel_transparent.frag.bin b/assets/shaders/chunk/voxel_transparent.frag.bin index 61a69b16435d25d76d3031cc5e3fbc36c6d43d59..bb402063dbd959962970d407676654e7d79887f3 100644 GIT binary patch delta 57 zcmeys*}=8Jf>D@_ft7)ufq{V;hy!vGlT#TOHk&ifX97xqgn59N7l`>l^ya6`+>8JV Cv83BI)1|9$a diff --git a/assets/grass.png b/assets/textures/grass.png similarity index 100% rename from assets/grass.png rename to assets/textures/grass.png diff --git a/assets/textures/tropical_rainforest_wood.png b/assets/textures/tropical_rainforest_wood.png new file mode 100644 index 0000000000000000000000000000000000000000..6107044abdf71dcb7dd08e93001b800a04b1cddc GIT binary patch literal 2089 zcmV+^2-f$BP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bvw&N%a{bv=u1SBzt5ldK!h^Fr+lj?|33LTPOjgybCe_vsIgSQ+mYkb7aH@XF*@BtXCh5>J6_WR670qXM4{L(1Z~00Q!!8@yyE5&({JpBvvq8e`e>RHJ4A z2rmIkO94;@Rt|*?{E1G%q3p#w?|tymt4}@$2`=~$LJYn5T9U6s;Q~w#!VXP zL<=o8ZK>srHc)AEo8Q6~H{H^fcTjDY-R*u4d)#$Tdp=PkGhuzXKSzxY)OaA(2gVaM zd>Z3nf_gde9Wx-tj(~XV2!PPsF|$g}vFXrt%xprL6VLF{cW@eY#DJjNi2Y6{c3;Rn z;bxrsBi#5v&UEPh26CoDcZ1w3Zf{U)eYdGr%s{9w!=6+tSbq3iGi%-j-#8xazQ0Wg z`t^qMlp7w%OUic3Y`U7XYx?GMCtDtdu(qb1B1~o20j{IZpybX$rxdu{TP1>E`xwpt zKb5&E>M)X2uQA0oMrfev3AV-26Q)b%(UmZ}Htd&YZfZWwWTxP<&vjE zcuY!WocQ8mX}x%F>|I!QvifOMtG4MvcCc@5COBo7URll4Pmg*t*OGO*>c6MBjWU9R z4i3Xpd9KlOmyor5i_l}4$*atG8O%3*z{jY+D>5sg#)gS8Hh2zh@-8QfEq=VEX>4Tx0C=2zkv&MmKpe$i(@I4u3U&~6$WWauh>AFB6^c+H)C#RSm|XfHG-*gu zTpR`0f`cE6RR=bb;{*sk16O*>U#SDrpQP7X zTI>ku*#<7ITbi;5T;Y5-i%B}Z<9Duprtz_jda zt(%q&kOjw~#Ia4{P-do7re%}*)3pd?K)>DOX7-XDctMC^S{Q(#L2J9VmdpPzI3M=- ziz216*8+&ECoiij52{LezW~^)uWFRG$#~-7?wA;+wXrMO=-4exMiq~B%H|;dtWD$# z2>|--X2~2W#iJh(t8&6fDW?8{PzH!W$KmdMJvc-A;sY@C7u-JkobEdaVGzoILB~P6 z7rMNg=OhjqE7FFp7k;B$MvNz3cI&3 literal 0 HcmV?d00001 diff --git a/assets/textures/willow_wood.png b/assets/textures/willow_wood.png new file mode 100644 index 0000000000000000000000000000000000000000..af57e116b29c54ac1866ab4041091b68d8dcec6b GIT binary patch literal 1453 zcmV;e1ycHnP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00k9EL_t(Y$4ypSjx0+Jj0n4W z<^V#v3t*RQg{`nA{*VA&&UB?C_;Ae;_0`HQS7ye`=HLJJ*H>L6DRkF)ABoqil_5#u zzK;#I0LCHkzP|{)uIrq)gCKE8h)iToKdAcncqN{h*a5@_WSFAJfC0KI_SZdo3j#zESAZmd_Kze0fFBo;ovI-?#pqH<9alB}M|2B$6}7K}k+X5|I!n z5#k_rYybwBBryO0qyjkVtB4q}#N-6u2xk%s>Fz9VNe}@n5%~UMK!HT)c+SB}o*_h{ z|MAb?_w@u4i07dg2ZUCT9v~FNUOoUUnMvRTA(fZ_RC#X9{?m)csS=X98o|oFkWk+> z1lk?|AgV;dW08^)lLQEaA*KKP_g%`2dyjMVD#zMGg-F6jg-J*ZsJ`Ghb2}tSP2w}~ zbkzh1kO8Jjy#OWs`uJEV?R=xNWL7*`tU<&c;{kmD7y&?V$-vf!j<443kVUacFbSio z1q1+iamgef-=YvFAPW={APyuF2r%akwy2$4g|QuX5{dD89isk^yx^DRsy0a|1+bl< z_FY00yA8$$f!H>JF17DBgsyU;0F+~ZRXS%V#d%-@D1l`B>h@m3D=;SzX)+EIus{NA zKGMu}2`rU}24M%h1fyhI!aXdo#d87%9v~%-olxAwMo6Lpf~us)~NcHov@{4-mr{vM4)?(10TCoc`@cQzQk1`|FAI1%^&U1}G7rL!c8gAhRk+ zwmMrv^ch1%swd!BM3V6VP!eJQR7nIdWD*Z0oikpgWqVYrw0%g+5c9+!SVViKM8_gt zt?#5z0x|-yIwUC+Qy0ec7(~@0*^rs4Uyx=a1K{hi_qJhxL zr#ur3fnv^gM_RSoPeVn}fBq~yJPpYz0g1;+$u>f$x64K3Qwgl$fk;AfpILxKRf(j* zndyO$2|3Q3$xVDyEzWkG9Bf-%8^!6?Zbk|?8>tCY0=%&cvAY`QC#9Klb$`C3D%*)k z&73FXvq8^s1e*Lhv5nl-rDtRl65h6F9S3lXMt>Nnt7hyN25gFiyRUdWCxF3LwIBhi zotbtjwS64Kud8iKrBa~S6naca_e^HTkOQE*OZ0sUNifNrv5`fbo-aJ9(#P%S| z;E<>yfo@TXx>Azp83HPLOfm+mI}v-w+r$97x?6T;=ALM4ZQDD&Rq?*lg|;*S$#d>Y zbv%h_Fi0$^SzzMBXGYSF0)VbpmpvYGhgbr5-|r0@P`C3xEV62Em3akY00000NkvXX Hu0mjf;RJOC literal 0 HcmV?d00001 diff --git a/assets/textures/xnether_blue_wood.png b/assets/textures/xnether_blue_wood.png new file mode 100644 index 0000000000000000000000000000000000000000..6a989b8d2aa94ca8c23e4cd1fc43a1f832f68271 GIT binary patch literal 5940 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 literal 0 HcmV?d00001 diff --git a/assets/textures/xnether_purple_wood.png b/assets/textures/xnether_purple_wood.png new file mode 100644 index 0000000000000000000000000000000000000000..cd668004c66ad57fc03cd7baf18c1c5847bd27ae GIT binary patch literal 6101 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