summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaG1924 <12997935+LaG1924@users.noreply.github.com>2022-12-15 16:41:06 +0100
committerGitHub <noreply@github.com>2022-12-15 16:41:06 +0100
commitd2b2f223cc62a1cc6e9d41d32020ef94d229a581 (patch)
treede0685c59a55557893d8d6d64bad01e9c98d206a
parentMerge pull request #82 from LaG1924/fix/sdl-wayland-build (diff)
parentAdded liquid rendering pass (diff)
downloadAltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.tar
AltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.tar.gz
AltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.tar.bz2
AltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.tar.lz
AltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.tar.xz
AltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.tar.zst
AltCraft-d2b2f223cc62a1cc6e9d41d32020ef94d229a581.zip
-rw-r--r--.gitignore6
-rw-r--r--CMakeLists.txt2
-rw-r--r--cwd/assets/altcraft/scripts/blocks.lua10
-rw-r--r--cwd/assets/altcraft/shaders/frag/fwd_liquid_face.fs38
-rw-r--r--cwd/assets/altcraft/shaders/frag/liquid_face.fs22
-rw-r--r--cwd/assets/altcraft/shaders/vert/liquid_face.vs38
-rw-r--r--cwd/assets/minecraft/blockstates/lava.json5
-rw-r--r--cwd/assets/minecraft/blockstates/water.json5
-rw-r--r--cwd/assets/minecraft/models/block/lava.json6
-rw-r--r--cwd/assets/minecraft/models/block/water.json6
-rw-r--r--src/AssetManager.cpp47
-rw-r--r--src/AssetManager.hpp9
-rw-r--r--src/Block.cpp32
-rw-r--r--src/Block.hpp9
-rw-r--r--src/Plugin.cpp8
-rw-r--r--src/RendererSection.cpp54
-rw-r--r--src/RendererSection.hpp25
-rw-r--r--src/RendererSectionData.cpp255
-rw-r--r--src/RendererSectionData.hpp3
-rw-r--r--src/RendererWorld.cpp69
-rw-r--r--src/RendererWorld.hpp6
21 files changed, 566 insertions, 89 deletions
diff --git a/.gitignore b/.gitignore
index 41e9362..819c522 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
cwd/assets/minecraft
cwd/assets/altcraft/fonts/
+cwd/myeasylog.log
+cwd/settings.json
build/
#CLion
@@ -10,6 +12,10 @@ cmake-build-release/
#Visual Studio
.vs/
CMakeSettings.json
+Folder.DotSettings.user
+
+#Visual Studio Code
+.vscode/
#Qt Creator
CMakeLists.txt.user
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f70a096..240d899 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -217,4 +217,4 @@ if(MSVC AND CMAKE_BUILD_TYPE MATCHES Release)
set_target_properties(AltCraft PROPERTIES WIN32_EXECUTABLE ON)
endif()
-file(DOWNLOAD https://github.com/google/fonts/raw/main/apache/opensans/OpenSans%5Bwdth%2Cwght%5D.ttf ${CMAKE_SOURCE_DIR}/cwd/assets/altcraft/fonts/OpenSans-Regular.ttf)
+file(DOWNLOAD https://github.com/google/fonts/raw/main/ofl/opensans/OpenSans%5Bwdth%2Cwght%5D.ttf ${CMAKE_SOURCE_DIR}/cwd/assets/altcraft/fonts/OpenSans-Regular.ttf)
diff --git a/cwd/assets/altcraft/scripts/blocks.lua b/cwd/assets/altcraft/scripts/blocks.lua
index 5678677..dde4b57 100644
--- a/cwd/assets/altcraft/scripts/blocks.lua
+++ b/cwd/assets/altcraft/scripts/blocks.lua
@@ -33,13 +33,11 @@ local function RegisterBlocks()
AC.RegisterBlock(BlockId.new(7,0), true, "bedrock", "normal")
- AC.RegisterBlock(BlockId.new(8,0), true, "water", "normal")
+ AC.RegisterLiquid(BlockId.new(8,0), "blocks/water_flow", "blocks/water_still")
+ AC.RegisterLiquid(BlockId.new(9,0), "blocks/water_flow", "blocks/water_still")
- AC.RegisterBlock(BlockId.new(9,0), true, "water", "normal")
-
- AC.RegisterBlock(BlockId.new(10,0), true, "lava", "normal")
-
- AC.RegisterBlock(BlockId.new(11,0), true, "lava", "normal")
+ AC.RegisterLiquid(BlockId.new(10,0), "blocks/lava_flow", "blocks/lava_still")
+ AC.RegisterLiquid(BlockId.new(11,0), "blocks/lava_flow", "blocks/lava_still")
AC.RegisterBlock(BlockId.new(12,0), true, "sand", "normal")
AC.RegisterBlock(BlockId.new(12,1), true, "red_sand", "normal")
diff --git a/cwd/assets/altcraft/shaders/frag/fwd_liquid_face.fs b/cwd/assets/altcraft/shaders/frag/fwd_liquid_face.fs
new file mode 100644
index 0000000..f8d9376
--- /dev/null
+++ b/cwd/assets/altcraft/shaders/frag/fwd_liquid_face.fs
@@ -0,0 +1,38 @@
+#version 330 core
+
+in vec4 faceWorldPos;
+in vec3 faceTextureUv;
+in vec3 faceAddColor;
+in vec3 faceNormal;
+in vec2 faceLight;
+
+out vec4 fragColor;
+
+uniform sampler2DArray textureAtlas;
+
+layout (std140) uniform Globals {
+ mat4 projView;
+ mat4 proj;
+ mat4 invProj;
+ mat4 view;
+ uvec2 viewportSize;
+ vec4 ssaoKernels[64];
+ float globalTime;
+ float dayTime;
+ float gamma;
+};
+
+void main() {
+ vec4 col = texture(textureAtlas, faceTextureUv);
+
+ float localLight = faceLight.r / 15.0f;
+ float skyLight = faceLight.g / 15.0f;
+ float lightLevel = clamp(localLight + skyLight * dayTime, 0.01f, 1.0f);
+ lightLevel = pow(lightLevel, 3);
+ lightLevel = clamp(lightLevel, 0.005f, 1.0f);
+
+ fragColor = vec4(col.rgb * faceAddColor.rgb * lightLevel, 1.0f);
+
+ fragColor.rgb = pow(fragColor.rgb, vec3(1.0f / gamma));
+ fragColor.a = col.a;
+}
diff --git a/cwd/assets/altcraft/shaders/frag/liquid_face.fs b/cwd/assets/altcraft/shaders/frag/liquid_face.fs
new file mode 100644
index 0000000..3e5c0d4
--- /dev/null
+++ b/cwd/assets/altcraft/shaders/frag/liquid_face.fs
@@ -0,0 +1,22 @@
+#version 330 core
+
+in vec3 faceTextureUv;
+in vec3 faceAddColor;
+in vec3 faceNormal;
+in vec2 faceLight;
+in float faceAmbientOcclusion;
+
+layout (location = 0) out vec4 color;
+layout (location = 1) out vec4 normal;
+layout (location = 2) out vec4 light;
+
+uniform sampler2DArray textureAtlas;
+
+void main() {
+ vec4 col = texture(textureAtlas, faceTextureUv);
+
+ color = vec4(col.rgb * faceAddColor.rgb, 1.0f);
+ normal = vec4(faceNormal, 1.0f);
+ light = vec4(faceLight / 15.0f, faceAmbientOcclusion, 1.0f);
+ color.a = col.a;
+}
diff --git a/cwd/assets/altcraft/shaders/vert/liquid_face.vs b/cwd/assets/altcraft/shaders/vert/liquid_face.vs
new file mode 100644
index 0000000..101e4d0
--- /dev/null
+++ b/cwd/assets/altcraft/shaders/vert/liquid_face.vs
@@ -0,0 +1,38 @@
+#version 330 core
+
+in vec3 pos[4];
+in vec2 uv[4];
+in vec2 light[4];
+in vec3 normal;
+in vec3 color;
+in vec3 layerAnimationAo;
+
+out vec3 faceTextureUv;
+out vec3 faceNormal;
+out vec3 faceAddColor;
+out vec2 faceLight;
+out float faceAmbientOcclusion;
+
+layout (std140) uniform Globals {
+ mat4 projView;
+ mat4 proj;
+ mat4 invProj;
+ mat4 view;
+ uvec2 viewportSize;
+ vec4 ssaoKernels[64];
+ float globalTime;
+ float dayTime;
+ float gamma;
+};
+
+void main() {
+ gl_Position = projView * vec4(pos[gl_VertexID], 1.0f);
+
+ faceTextureUv = vec3(uv[gl_VertexID], layerAnimationAo.r);
+ faceTextureUv.y -= (uv[2].y - uv[0].y) * trunc(mod(globalTime * 4.0f, layerAnimationAo.g));
+
+ faceNormal = (view * vec4(normal, 0.0f)).xyz;
+ faceAddColor = color;
+ faceLight = light[gl_VertexID];
+ faceAmbientOcclusion = layerAnimationAo.b;
+}
diff --git a/cwd/assets/minecraft/blockstates/lava.json b/cwd/assets/minecraft/blockstates/lava.json
deleted file mode 100644
index 97b01d3..0000000
--- a/cwd/assets/minecraft/blockstates/lava.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "variants": {
- "normal": { "model": "lava" }
- }
-}
diff --git a/cwd/assets/minecraft/blockstates/water.json b/cwd/assets/minecraft/blockstates/water.json
deleted file mode 100644
index 683334a..0000000
--- a/cwd/assets/minecraft/blockstates/water.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "variants": {
- "normal": { "model": "water" }
- }
-}
diff --git a/cwd/assets/minecraft/models/block/lava.json b/cwd/assets/minecraft/models/block/lava.json
deleted file mode 100644
index 714d0b2..0000000
--- a/cwd/assets/minecraft/models/block/lava.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "parent": "block/cube_all",
- "textures": {
- "all": "blocks/lava_flow"
- }
-}
diff --git a/cwd/assets/minecraft/models/block/water.json b/cwd/assets/minecraft/models/block/water.json
deleted file mode 100644
index 860815a..0000000
--- a/cwd/assets/minecraft/models/block/water.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "parent": "block/cube_all",
- "textures": {
- "all": "blocks/water_flow"
- }
-}
diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp
index 3e3f677..09f5209 100644
--- a/src/AssetManager.cpp
+++ b/src/AssetManager.cpp
@@ -573,6 +573,52 @@ BlockFaces &AssetManager::GetBlockModelByBlockId(BlockId block) {
return it->second;
BlockInfo *blockInfo = GetBlockInfo(block);
+ if (blockInfo->blockstate == "@liquid") {
+ BlockFaces blockFaces;
+ blockFaces.isBlock = false;
+ blockFaces.isLiquid = true;
+ blockFaces.transform = glm::mat4(1.0f);
+ blockFaces.ambientOcclusion = false;
+ for (size_t i = 0; i < FaceDirection::none; i++) {
+ blockFaces.faceDirectionVector[i] = FaceDirectionVector[i];
+ }
+
+ const auto& liquidInfo = GetBlockLiquidInfo(BlockId{ block.id, 0 });
+
+ {
+ AssetTexture* assetTexture = AssetManager::GetAsset<AssetTexture>("minecraft/textures/" + liquidInfo.flowTexture);
+ if (!assetTexture)
+ return errorFaces;
+ TextureCoord texture = atlas->GetTexture(assetTexture->id);
+ float textureFrames = assetTexture->frames;
+ blockFaces.faces.emplace_back(ParsedFace{
+ FaceDirection::none,
+ glm::translate(glm::mat4(1.0f), glm::vec3{0.0f, 1.0f, 0.0f}),
+ glm::vec4{ texture.x,texture.y,texture.w,texture.h },
+ static_cast<float>(texture.layer),
+ static_cast<float>(assetTexture->frames),
+ glm::vec3(1.0f),
+ });
+ }
+
+ {
+ AssetTexture* assetTexture = AssetManager::GetAsset<AssetTexture>("minecraft/textures/" + liquidInfo.stillTexture);
+ if (!assetTexture)
+ return errorFaces;
+ TextureCoord texture = atlas->GetTexture(assetTexture->id);
+ float textureFrames = assetTexture->frames;
+ blockFaces.faces.emplace_back(ParsedFace{
+ FaceDirection::none,
+ glm::translate(glm::mat4(1.0f), glm::vec3{0.0f, 1.0f, 0.0f}),
+ glm::vec4{ texture.x,texture.y,texture.w,texture.h },
+ static_cast<float>(texture.layer),
+ static_cast<float>(assetTexture->frames),
+ glm::vec3(1.0f),
+ });
+ }
+
+ return blockIdToBlockFaces.insert(std::make_pair(block, blockFaces)).first->second;
+ }
AssetBlockState *asset = GetAsset<AssetBlockState>("/minecraft/blockstates/" + blockInfo->blockstate);
if (!asset)
return errorFaces;
@@ -595,6 +641,7 @@ BlockFaces &AssetManager::GetBlockModelByBlockId(BlockId block) {
blockFaces.faces = assetModel->blockModel.parsedFaces;
blockFaces.isBlock = assetModel->blockModel.IsBlock;
blockFaces.ambientOcclusion = assetModel->blockModel.AmbientOcclusion;
+ blockFaces.isLiquid = false;
glm::mat4 transform = glm::mat4(1.0);
if (model.y != 0) {
diff --git a/src/AssetManager.hpp b/src/AssetManager.hpp
index 59fc851..250524e 100644
--- a/src/AssetManager.hpp
+++ b/src/AssetManager.hpp
@@ -22,6 +22,10 @@ enum FaceDirection {
south,
west,
east,
+ northWest,
+ northEast,
+ southWest,
+ southEast,
none,
};
@@ -32,6 +36,10 @@ static const Vector FaceDirectionVector[] = {
Vector(0,0,1),
Vector(-1,0,0),
Vector(1,0,0),
+ Vector(-1,0,-1),
+ Vector(1,0,-1),
+ Vector(-1,0,1),
+ Vector(1,0,1),
Vector(0,0,0)
};
@@ -49,6 +57,7 @@ struct BlockFaces {
std::vector<ParsedFace> faces;
bool isBlock;
bool ambientOcclusion;
+ bool isLiquid; //if true, then faces contains only two elements with valid texture data
Vector faceDirectionVector[FaceDirection::none];
};
diff --git a/src/Block.cpp b/src/Block.cpp
index 85870f6..8af5a4b 100644
--- a/src/Block.cpp
+++ b/src/Block.cpp
@@ -1,25 +1,29 @@
#include "Block.hpp"
#include <map>
-#include <vector>
-#include "Plugin.hpp"
+static std::map<BlockId, BlockInfo> blocks;
+static std::map<BlockId, LiquidInfo> liquids;
-static std::vector<BlockInfo> blocks;
-static std::map<BlockId, size_t> staticBlockInfo;
-
-BlockInfo WTFBlock{ true, "", "" };
+static BlockInfo UnknownBlock{ true, "", "" };
+static LiquidInfo UnknownLiquid{ "", "" };
void RegisterStaticBlockInfo(BlockId blockId, BlockInfo blockInfo) {
- //NOTE: It can be made thread-safe by using atomic incrementer
- staticBlockInfo[blockId] = blocks.size();
- blocks.push_back(blockInfo);
+ blocks.emplace(blockId, blockInfo);
+}
+
+void RegisterStaticLiquidInfo(BlockId blockId, LiquidInfo liquidInfo) {
+ liquids[blockId] = liquidInfo;
+ for (uint8_t i = 0; i < 16; i++)
+ blocks.emplace(BlockId{ blockId.id, i }, BlockInfo{ true, "@liquid", liquidInfo.stillTexture });
}
BlockInfo* GetBlockInfo(BlockId blockId) {
- auto it = staticBlockInfo.find(blockId);
- if (it != staticBlockInfo.end())
- return &blocks.data()[it->second];
- else
- return &WTFBlock;
+ auto it = blocks.find(blockId);
+ return it != blocks.end() ? &it->second : &UnknownBlock;
+}
+
+const LiquidInfo& GetBlockLiquidInfo(BlockId blockId) {
+ auto it = liquids.find(blockId);
+ return it != liquids.end() ? it->second : UnknownLiquid;
}
diff --git a/src/Block.hpp b/src/Block.hpp
index 0fd0e89..535ae68 100644
--- a/src/Block.hpp
+++ b/src/Block.hpp
@@ -47,6 +47,15 @@ struct BlockInfo {
std::string variant;
};
+struct LiquidInfo {
+ std::string flowTexture;
+ std::string stillTexture;
+};
+
void RegisterStaticBlockInfo(BlockId blockId, BlockInfo blockInfo);
+void RegisterStaticLiquidInfo(BlockId blockId, LiquidInfo liquidInfo);
+
BlockInfo* GetBlockInfo(BlockId blockId);
+
+const LiquidInfo& GetBlockLiquidInfo(BlockId blockId);
diff --git a/src/Plugin.cpp b/src/Plugin.cpp
index 3e06b0c..7a3b716 100644
--- a/src/Plugin.cpp
+++ b/src/Plugin.cpp
@@ -78,6 +78,13 @@ namespace PluginApi {
});
}
+ void RegisterLiquid(BlockId blockId, std::string flowTexture, std::string stillTexture) {
+ RegisterStaticLiquidInfo(blockId, LiquidInfo{
+ flowTexture,
+ stillTexture
+ });
+ }
+
void RegisterDimension(int dimId, Dimension dim) {
RegisterNewDimension(dimId, dim);
}
@@ -286,6 +293,7 @@ void PluginSystem::Init() {
apiTable["LogError"] = PluginApi::LogError;
apiTable["GetGameState"] = PluginApi::GetGameState;
apiTable["RegisterBlock"] = PluginApi::RegisterBlock;
+ apiTable["RegisterLiquid"] = PluginApi::RegisterLiquid;
apiTable["RegisterDimension"] = PluginApi::RegisterDimension;
apiTable["ConnectToServer"] = PluginApi::ConnectToServer;
apiTable["Exit"] = PluginApi::Exit;
diff --git a/src/RendererSection.cpp b/src/RendererSection.cpp
index 429a8bd..7ea74df 100644
--- a/src/RendererSection.cpp
+++ b/src/RendererSection.cpp
@@ -9,16 +9,26 @@
#include "RendererSectionData.hpp"
-RendererSection::RendererSection(const RendererSectionData& data, std::shared_ptr<Gal::Pipeline> pipeline, std::shared_ptr<Gal::BufferBinding> bufferBinding) {
+RendererSection::RendererSection(const RendererSectionData& data,
+ std::shared_ptr<Gal::Pipeline> solidPipeline,
+ std::shared_ptr<Gal::BufferBinding> solidBufferBinding,
+ std::shared_ptr<Gal::Pipeline> liquidPipeline,
+ std::shared_ptr<Gal::BufferBinding> liquidBufferBinding) {
OPTICK_EVENT();
auto gal = Gal::GetImplementation();
- buffer = gal->CreateBuffer();
- pipelineInstance = pipeline->CreateInstance({
- {bufferBinding, buffer}
+ solidBuffer = gal->CreateBuffer();
+ solidPipelineInstance = solidPipeline->CreateInstance({
+ {solidBufferBinding, solidBuffer}
});
- pipelineInstance->SetInstancesCount(4);
+ solidPipelineInstance->SetInstancesCount(4);
+
+ liquidBuffer = gal->CreateBuffer();
+ liquidPipelineInstance = liquidPipeline->CreateInstance({
+ {liquidBufferBinding, liquidBuffer}
+ });
+ liquidPipelineInstance->SetInstancesCount(4);
UpdateData(data);
}
@@ -32,18 +42,27 @@ RendererSection::~RendererSection() {
}
-void swap(RendererSection & lhs, RendererSection & rhs) {
- std::swap(lhs.pipelineInstance, rhs.pipelineInstance);
- std::swap(lhs.buffer, rhs.buffer);
- std::swap(lhs.hash, rhs.hash);
- std::swap(lhs.numOfFaces, rhs.numOfFaces);
- std::swap(lhs.sectionPos, rhs.sectionPos);
+void RendererSection::RenderSolid() {
+ OPTICK_EVENT();
+ solidPipelineInstance->Activate();
+ solidPipelineInstance->Render(0, solidFacesCount);
}
-void RendererSection::Render() {
+void RendererSection::RenderLiquid() {
OPTICK_EVENT();
- pipelineInstance->Activate();
- pipelineInstance->Render(0, numOfFaces);
+ liquidPipelineInstance->Activate();
+ liquidPipelineInstance->Render(0, liquidFacesCount);
+}
+
+void swap(RendererSection & lhs, RendererSection & rhs) {
+ std::swap(lhs.solidPipelineInstance, rhs.solidPipelineInstance);
+ std::swap(lhs.solidBuffer, rhs.solidBuffer);
+ std::swap(lhs.liquidPipelineInstance, rhs.liquidPipelineInstance);
+ std::swap(lhs.liquidBuffer, rhs.liquidBuffer);
+ std::swap(lhs.hash, rhs.hash);
+ std::swap(lhs.solidFacesCount, rhs.solidFacesCount);
+ std::swap(lhs.liquidFacesCount, rhs.liquidFacesCount);
+ std::swap(lhs.sectionPos, rhs.sectionPos);
}
Vector RendererSection::GetPosition() {
@@ -57,9 +76,12 @@ size_t RendererSection::GetHash() {
void RendererSection::UpdateData(const RendererSectionData & data) {
OPTICK_EVENT();
- buffer->SetData({ reinterpret_cast<const std::byte*>(data.vertices.data()), reinterpret_cast<const std::byte*>(data.vertices.data() + data.vertices.size())});
+ solidBuffer->SetData({ reinterpret_cast<const std::byte*>(data.solidVertices.data()), reinterpret_cast<const std::byte*>(data.solidVertices.data() + data.solidVertices.size())});
+ solidFacesCount = data.solidVertices.size();
+
+ liquidBuffer->SetData({ reinterpret_cast<const std::byte*>(data.liquidVertices.data()), reinterpret_cast<const std::byte*>(data.liquidVertices.data() + data.liquidVertices.size()) });
+ liquidFacesCount = data.liquidVertices.size();
- numOfFaces = data.vertices.size();
sectionPos = data.sectionPos;
hash = data.hash;
}
diff --git a/src/RendererSection.hpp b/src/RendererSection.hpp
index 0a03f44..8125e4e 100644
--- a/src/RendererSection.hpp
+++ b/src/RendererSection.hpp
@@ -7,26 +7,39 @@ class RenderState;
class RendererSectionData;
class RendererSection {
- std::shared_ptr<Gal::PipelineInstance> pipelineInstance;
- std::shared_ptr<Gal::Buffer> buffer;
- size_t hash;
+ std::shared_ptr<Gal::PipelineInstance> solidPipelineInstance;
+ std::shared_ptr<Gal::Buffer> solidBuffer;
+ std::shared_ptr<Gal::PipelineInstance> liquidPipelineInstance;
+ std::shared_ptr<Gal::Buffer> liquidBuffer;
Vector sectionPos;
+ size_t hash = 0;
+ size_t solidFacesCount = 0;
+ size_t liquidFacesCount = 0;
RendererSection(const RendererSection &other) = delete;
public:
- RendererSection(const RendererSectionData& data, std::shared_ptr<Gal::Pipeline> pipeline, std::shared_ptr<Gal::BufferBinding> bufferBinding);
+ RendererSection(
+ const RendererSectionData& data,
+ std::shared_ptr<Gal::Pipeline> solidPipeline,
+ std::shared_ptr<Gal::BufferBinding> solidBufferBinding,
+ std::shared_ptr<Gal::Pipeline> liquidPipeline,
+ std::shared_ptr<Gal::BufferBinding> liquidBufferBinding);
RendererSection(RendererSection &&other);
~RendererSection();
- void Render();
+ void RenderSolid();
+
+ void RenderLiquid();
Vector GetPosition();
size_t GetHash();
- size_t numOfFaces;
+ inline size_t GetSolidFacesCount() { return solidFacesCount; }
+
+ inline size_t GetLiquidFacesCount() { return liquidFacesCount; }
friend void swap(RendererSection &lhs, RendererSection &rhs);
diff --git a/src/RendererSectionData.cpp b/src/RendererSectionData.cpp
index 761dd14..fdd961d 100644
--- a/src/RendererSectionData.cpp
+++ b/src/RendererSectionData.cpp
@@ -79,8 +79,8 @@ void AddFacesByBlockModel(RendererSectionData& data, const BlockFaces& model, co
continue;
}
- data.vertices.emplace_back();
- VertexData& vertexData = data.vertices.back();
+ data.solidVertices.emplace_back();
+ VertexData& vertexData = data.solidVertices.back();
glm::mat4 transformed = transform * model.transform * face.transform;
vertexData.positions[0] = transformed * glm::vec4(0, 0, 0, 1);
@@ -131,6 +131,248 @@ void AddFacesByBlockModel(RendererSectionData& data, const BlockFaces& model, co
}
}
+void AddLiquidFacesByBlockModel(RendererSectionData& data, const BlockId& blockId, const BlockFaces& model, const glm::mat4& transform, bool visibility[FaceDirection::none], const Vector& pos, const SectionsData& sections, bool smoothLighting) {
+ const ParsedFace& flowData = model.faces[0];
+ const ParsedFace& stillData = model.faces[1];
+ size_t addedFaces = 0;
+
+ constexpr float highLevel = 0.9f;
+ constexpr float lowLevel = 0.05f;
+
+ constexpr float neighborLevels[] = {
+ lowLevel + ((highLevel - lowLevel) / 7) * 7.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 6.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 5.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 4.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 3.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 2.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 1.0f,
+ lowLevel + ((highLevel - lowLevel) / 7) * 0.0f,
+ };
+
+ uint8_t neighborsLiquids[FaceDirection::none + 1] = { 0 };
+ for (size_t i = 0; i < FaceDirection::none; i++) {
+ const BlockId bid = sections.GetBlockId(pos + FaceDirectionVector[i]);
+ neighborsLiquids[i] = bid.id == blockId.id ? bid.state & 0b00000111 : 0;
+ }
+ neighborsLiquids[FaceDirection::none] = blockId.state & 0b00000111;
+
+ const bool liquidFalling = blockId.state & 0x8;
+ if (liquidFalling) {
+ if (!neighborsLiquids[FaceDirection::down]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 0, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(1, 0, 0, 1);
+ vertex.positions[2] = transform * glm::vec4(1, 0, 1, 1);
+ vertex.positions[3] = transform * glm::vec4(0, 0, 1, 1);
+ }
+
+ if (!neighborsLiquids[FaceDirection::up]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 1, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(0, 1, 1, 1);
+ vertex.positions[2] = transform * glm::vec4(1, 1, 1, 1);
+ vertex.positions[3] = transform * glm::vec4(1, 1, 0, 1);
+ }
+
+ if (!neighborsLiquids[FaceDirection::north]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(1, 0, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(0, 0, 0, 1);
+ vertex.positions[2] = transform * glm::vec4(0, 1, 0, 1);
+ vertex.positions[3] = transform * glm::vec4(1, 1, 0, 1);
+ }
+
+ if (!neighborsLiquids[FaceDirection::south]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 0, 1, 1);
+ vertex.positions[1] = transform * glm::vec4(1, 0, 1, 1);
+ vertex.positions[2] = transform * glm::vec4(1, 1, 1, 1);
+ vertex.positions[3] = transform * glm::vec4(0, 1, 1, 1);
+ }
+
+ if (!neighborsLiquids[FaceDirection::west]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 0, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(0, 0, 1, 1);
+ vertex.positions[2] = transform * glm::vec4(0, 1, 1, 1);
+ vertex.positions[3] = transform * glm::vec4(0, 1, 0, 1);
+ }
+
+ if (!neighborsLiquids[FaceDirection::east]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(1, 0, 1, 1);
+ vertex.positions[1] = transform * glm::vec4(1, 0, 0, 1);
+ vertex.positions[2] = transform * glm::vec4(1, 1, 0, 1);
+ vertex.positions[3] = transform * glm::vec4(1, 1, 1, 1);
+ }
+ }
+ else {
+ const float bLevel = neighborLevels[neighborsLiquids[FaceDirection::none]];
+ const float nLevel = neighborLevels[neighborsLiquids[FaceDirection::north]];
+ const float eLevel = neighborLevels[neighborsLiquids[FaceDirection::east]];
+ const float sLevel = neighborLevels[neighborsLiquids[FaceDirection::south]];
+ const float wLevel = neighborLevels[neighborsLiquids[FaceDirection::west]];
+ const float nwLevel = neighborLevels[neighborsLiquids[FaceDirection::northWest]];
+ const float neLevel = neighborLevels[neighborsLiquids[FaceDirection::northEast]];
+ const float swLevel = neighborLevels[neighborsLiquids[FaceDirection::southWest]];
+ const float seLevel = neighborLevels[neighborsLiquids[FaceDirection::southEast]];
+
+ const glm::vec4 nwCorner = glm::vec4(0, _min(nLevel, wLevel, nwLevel, bLevel), 0, 1);
+ const glm::vec4 neCorner = glm::vec4(1, _min(nLevel, eLevel, neLevel, bLevel), 0, 1);
+ const glm::vec4 swCorner = glm::vec4(0, _min(sLevel, wLevel, swLevel, bLevel), 1, 1);
+ const glm::vec4 seCorner = glm::vec4(1, _min(sLevel, eLevel, seLevel, bLevel), 1, 1);
+
+ if (!neighborsLiquids[FaceDirection::down]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 0, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(1, 0, 0, 1);
+ vertex.positions[2] = transform * glm::vec4(1, 0, 1, 1);
+ vertex.positions[3] = transform * glm::vec4(0, 0, 1, 1);
+ }
+
+ if (!neighborsLiquids[FaceDirection::up]) {
+ addedFaces++;
+
+ FaceDirection flowDirection = FaceDirection::north;
+ if (nwCorner.y + swCorner.y > neCorner.y + seCorner.y)
+ flowDirection = FaceDirection::east;
+ else if (neCorner.y + seCorner.y > nwCorner.y + swCorner.y)
+ flowDirection = FaceDirection::west;
+ else if (nwCorner.y + neCorner.y > swCorner.y + seCorner.y)
+ flowDirection = FaceDirection::south;
+ else
+ flowDirection = FaceDirection::north;
+
+ glm::mat4 flowMat = glm::mat4(1.0f);
+
+ switch (flowDirection)
+ {
+ case FaceDirection::east:
+ break;
+ case FaceDirection::west:
+ break;
+ case FaceDirection::south:
+ break;
+ case FaceDirection::north:
+ break;
+ default:
+ break;
+ }
+
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * flowMat * nwCorner;
+ vertex.positions[1] = transform * flowMat * swCorner;
+ vertex.positions[2] = transform * flowMat * seCorner;
+ vertex.positions[3] = transform * flowMat * neCorner;
+
+ const ParsedFace &texData =
+ _max(nwCorner.y, swCorner.y, seCorner.y, neCorner.y) ==
+ _min(nwCorner.y, swCorner.y, seCorner.y, neCorner.y) ?
+ stillData : flowData;
+
+ vertex.uvs[0] = TransformTextureCoord(texData.texture, glm::vec2(0, 0), texData.frames);
+ vertex.uvs[1] = TransformTextureCoord(texData.texture, glm::vec2(1, 0), texData.frames);
+ vertex.uvs[2] = TransformTextureCoord(texData.texture, glm::vec2(1, 1), texData.frames);
+ vertex.uvs[3] = TransformTextureCoord(texData.texture, glm::vec2(0, 1), texData.frames);
+
+ vertex.layerAnimationAo.r = texData.layer;
+ vertex.layerAnimationAo.g = texData.frames;
+
+ glm::vec3 normal = glm::cross(vertex.positions[1] - vertex.positions[0], vertex.positions[3] - vertex.positions[0]);
+ vertex.normal = glm::normalize(normal);
+ }
+
+ if (!neighborsLiquids[FaceDirection::north]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(1, 0, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(0, 0, 0, 1);
+ vertex.positions[2] = transform * nwCorner;
+ vertex.positions[3] = transform * neCorner;
+ }
+
+ if (!neighborsLiquids[FaceDirection::south]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 0, 1, 1);
+ vertex.positions[1] = transform * glm::vec4(1, 0, 1, 1);
+ vertex.positions[2] = transform * seCorner;
+ vertex.positions[3] = transform * swCorner;
+ }
+
+ if (!neighborsLiquids[FaceDirection::west]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(0, 0, 0, 1);
+ vertex.positions[1] = transform * glm::vec4(0, 0, 1, 1);
+ vertex.positions[2] = transform * swCorner;
+ vertex.positions[3] = transform * nwCorner;
+ }
+
+ if (!neighborsLiquids[FaceDirection::east]) {
+ addedFaces++;
+ VertexData& vertex = data.liquidVertices.emplace_back();
+ vertex.positions[0] = transform * glm::vec4(1, 0, 1, 1);
+ vertex.positions[1] = transform * glm::vec4(1, 0, 0, 1);
+ vertex.positions[2] = transform * neCorner;
+ vertex.positions[3] = transform * seCorner;
+ }
+ }
+
+
+ glm::vec3 absPos = (sections.data[1][1][1].GetPosition() * 16).glm();
+ BlockLightness light = sections.GetLight(pos);
+ BlockLightness skyLight = sections.GetSkyLight(pos);
+ glm::vec2 lightness;
+ lightness.x = light.self;
+ lightness.y = skyLight.self;
+ for (size_t i = data.liquidVertices.size() - addedFaces; i < data.liquidVertices.size(); i++) {
+ VertexData& vertex = data.liquidVertices[i];
+
+ if (glm::length(vertex.normal) < 0.5f) {
+ vertex.uvs[0] = TransformTextureCoord(flowData.texture, glm::vec2(0, 0), flowData.frames);
+ vertex.uvs[1] = TransformTextureCoord(flowData.texture, glm::vec2(1, 0), flowData.frames);
+ vertex.uvs[2] = TransformTextureCoord(flowData.texture, glm::vec2(1, 1), flowData.frames);
+ vertex.uvs[3] = TransformTextureCoord(flowData.texture, glm::vec2(0, 1), flowData.frames);
+
+ glm::vec3 normal = glm::cross(vertex.positions[1] - vertex.positions[0], vertex.positions[3] - vertex.positions[0]);
+ vertex.normal = glm::normalize(normal);
+
+ vertex.layerAnimationAo.r = flowData.layer;
+ vertex.layerAnimationAo.g = flowData.frames;
+ }
+
+ vertex.layerAnimationAo.b = 0.0f;
+ vertex.colors = glm::vec3(1.0f);
+
+ if (smoothLighting) {
+ for (size_t i = 0; i < 4; i++) {
+ glm::vec3 baseLightPos = vertex.positions[i] - absPos;
+ glm::vec3 lightPos = baseLightPos + vertex.normal * 0.5f;
+ glm::ivec3 basePos = glm::trunc(lightPos);
+ BlockLightness light = sections.GetLight(Vector(basePos.x, basePos.y, basePos.z));
+ BlockLightness skyLight = sections.GetSkyLight(Vector(basePos.x, basePos.y, basePos.z));
+ vertex.lights[i].x = InterpolateBlockLightness(light, lightPos - glm::vec3(basePos));
+ vertex.lights[i].y = InterpolateBlockLightness(skyLight, lightPos - glm::vec3(basePos));
+ }
+ }
+ else {
+ vertex.lights[0] = lightness;
+ vertex.lights[1] = lightness;
+ vertex.lights[2] = lightness;
+ vertex.lights[3] = lightness;
+ }
+ }
+}
+
BlockFaces *GetInternalBlockModel(const BlockId& id, std::vector<std::pair<BlockId, BlockFaces*>> &idModels) {
for (const auto& it : idModels) {
if (it.first == id)
@@ -213,11 +455,16 @@ RendererSectionData ParseSection(const SectionsData &sections, bool smoothLighti
transform = glm::translate(baseOffset, vec.glm());
BlockFaces *model = GetInternalBlockModel(block, idModels);
- AddFacesByBlockModel(data, *model, transform, blockVisibility[y * 256 + z * 16 + x], vec, sections, smoothLighting);
+ if (model->isLiquid)
+ AddLiquidFacesByBlockModel(data, block, *model, transform, blockVisibility[y * 256 + z * 16 + x], vec, sections, smoothLighting);
+ else
+ AddFacesByBlockModel(data, *model, transform, blockVisibility[y * 256 + z * 16 + x], vec, sections, smoothLighting);
}
}
}
- data.vertices.shrink_to_fit();
+
+ data.solidVertices.shrink_to_fit();
+ data.liquidVertices.shrink_to_fit();
return data;
}
diff --git a/src/RendererSectionData.hpp b/src/RendererSectionData.hpp
index 0f9ade6..ac69bff 100644
--- a/src/RendererSectionData.hpp
+++ b/src/RendererSectionData.hpp
@@ -68,7 +68,8 @@ struct VertexData {
};
struct RendererSectionData {
- std::vector<VertexData> vertices;
+ std::vector<VertexData> solidVertices;
+ std::vector<VertexData> liquidVertices;
size_t hash = 0;
Vector sectionPos;
bool forced = false;
diff --git a/src/RendererWorld.cpp b/src/RendererWorld.cpp
index af177d7..26c1f69 100644
--- a/src/RendererWorld.cpp
+++ b/src/RendererWorld.cpp
@@ -189,7 +189,7 @@ RendererWorld::RendererWorld(std::shared_ptr<Gal::Framebuffer> target, bool deff
}
it->second.UpdateData(parsing[id].renderer);
} else
- sections.emplace(std::make_pair(parsing[id].renderer.sectionPos, RendererSection(parsing[id].renderer, sectionsPipeline, sectionsBufferBinding)));
+ sections.emplace(std::make_pair(parsing[id].renderer.sectionPos, RendererSection(parsing[id].renderer, solidSectionsPipeline, solidSectionsBufferBinding, liquidSectionsPipeline, liquidSectionsBufferBinding)));
parsing[id] = RendererWorld::SectionParsing();
});
@@ -267,7 +267,8 @@ RendererWorld::RendererWorld(std::shared_ptr<Gal::Framebuffer> target, bool deff
RendererWorld::~RendererWorld() {
size_t faces = 0;
for (auto& it : sections) {
- faces += it.second.numOfFaces;
+ faces += it.second.GetSolidFacesCount();
+ faces += it.second.GetLiquidFacesCount();
}
LOG(INFO) << "Total faces to render: " << faces;
isRunning = false;
@@ -342,7 +343,6 @@ void RendererWorld::Render(float screenRatio) {
auto rawGlobalTime = (std::chrono::high_resolution_clock::now() - globalTimeStart);
float globalTime = rawGlobalTime.count() / 1000000000.0f;
globalSpb->Get<GlobalShaderParameters>()->globalTime = globalTime;
- sectionsPipeline->Activate();
Frustum frustum(projView);
renderList.clear();
@@ -362,14 +362,20 @@ void RendererWorld::Render(float screenRatio) {
continue;
}
renderList.push_back(section.first);
- renderedFaces += section.second.numOfFaces;
+ renderedFaces += section.second.GetSolidFacesCount();
+ renderedFaces += section.second.GetLiquidFacesCount();
}
glm::vec3 playerChunk(GetGameState()->GetPlayer()->pos / 16);
std::sort(renderList.begin(), renderList.end(), [playerChunk](const Vector& lhs, const Vector& rhs) {
return glm::distance2(lhs.glm(), playerChunk) < glm::distance2(rhs.glm(), playerChunk);
});
+ solidSectionsPipeline->Activate();
for (const auto& renderPos : renderList) {
- sections.at(renderPos).Render();
+ sections.at(renderPos).RenderSolid();
+ }
+ liquidSectionsPipeline->Activate();
+ for (const auto& renderPos : renderList) {
+ sections.at(renderPos).RenderLiquid();
}
DebugInfo::culledSections = culledSections;
DebugInfo::renderFaces = renderedFaces;
@@ -418,14 +424,24 @@ void RendererWorld::Render(float screenRatio) {
}
void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target, bool defferedShading) {
- std::string sectionVertexSource, sectionPixelSource;
+ std::string solidSectionVertexSource, solidSectionPixelSource;
{
auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/face");
- sectionVertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
+ solidSectionVertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
auto pixelAsset = defferedShading ? AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/face") :
AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/fwd_face");
- sectionPixelSource = std::string((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size());
+ solidSectionPixelSource = std::string((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size());
+ }
+
+ std::string liquidSectionVertexSource, liquidSectionPixelSource;
+ {
+ auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/liquid_face");
+ liquidSectionVertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
+
+ auto pixelAsset = defferedShading ? AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/liquid_face") :
+ AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/fwd_liquid_face");
+ liquidSectionPixelSource = std::string((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size());
}
std::string entitiesVertexSource, entitiesPixelSource;
@@ -450,13 +466,13 @@ void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target, bool
auto gal = Gal::GetImplementation();
{
- auto sectionsPLC = gal->CreatePipelineConfig();
- sectionsPLC->SetTarget(target);
- sectionsPLC->AddStaticTexture("textureAtlas", AssetManager::GetTextureAtlas());
- sectionsPLC->SetVertexShader(gal->LoadVertexShader(sectionVertexSource));
- sectionsPLC->SetPixelShader(gal->LoadPixelShader(sectionPixelSource));
- sectionsPLC->SetPrimitive(Gal::Primitive::TriangleFan);
- sectionsBufferBinding = sectionsPLC->BindVertexBuffer({
+ auto solidSectionPLC = gal->CreatePipelineConfig();
+ solidSectionPLC->SetTarget(target);
+ solidSectionPLC->AddStaticTexture("textureAtlas", AssetManager::GetTextureAtlas());
+ solidSectionPLC->SetVertexShader(gal->LoadVertexShader(solidSectionVertexSource));
+ solidSectionPLC->SetPixelShader(gal->LoadPixelShader(solidSectionPixelSource));
+ solidSectionPLC->SetPrimitive(Gal::Primitive::TriangleFan);
+ solidSectionsBufferBinding = solidSectionPLC->BindVertexBuffer({
{"pos", Gal::Type::Vec3, 4, 1},
{"uv", Gal::Type::Vec2, 4, 1},
{"light", Gal::Type::Vec2, 4, 1},
@@ -464,9 +480,28 @@ void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target, bool
{"color", Gal::Type::Vec3, 1, 1},
{"layerAnimationAo", Gal::Type::Vec3, 1, 1},
});
- sectionsPipeline = gal->BuildPipeline(sectionsPLC);
+ solidSectionsPipeline = gal->BuildPipeline(solidSectionPLC);
}
-
+
+ {
+ auto liquidSectionPLC = gal->CreatePipelineConfig();
+ liquidSectionPLC->SetTarget(target);
+ liquidSectionPLC->AddStaticTexture("textureAtlas", AssetManager::GetTextureAtlas());
+ liquidSectionPLC->SetVertexShader(gal->LoadVertexShader(liquidSectionVertexSource));
+ liquidSectionPLC->SetPixelShader(gal->LoadPixelShader(liquidSectionPixelSource));
+ liquidSectionPLC->SetPrimitive(Gal::Primitive::TriangleFan);
+ liquidSectionPLC->SetBlending(Gal::Blending::Additive);
+ liquidSectionsBufferBinding = liquidSectionPLC->BindVertexBuffer({
+ {"pos", Gal::Type::Vec3, 4, 1},
+ {"uv", Gal::Type::Vec2, 4, 1},
+ {"light", Gal::Type::Vec2, 4, 1},
+ {"normal", Gal::Type::Vec3, 1, 1},
+ {"color", Gal::Type::Vec3, 1, 1},
+ {"layerAnimationAo", Gal::Type::Vec3, 1, 1},
+ });
+ liquidSectionsPipeline = gal->BuildPipeline(liquidSectionPLC);
+ }
+
{
auto entitiesPLC = gal->CreatePipelineConfig();
entitiesPLC->SetTarget(target);
diff --git a/src/RendererWorld.hpp b/src/RendererWorld.hpp
index 438c022..13d9739 100644
--- a/src/RendererWorld.hpp
+++ b/src/RendererWorld.hpp
@@ -43,8 +43,10 @@ class RendererWorld {
std::map<Vector, RendererSection> sections;
void UpdateAllSections(VectorF playerPos);
std::chrono::time_point<std::chrono::high_resolution_clock> globalTimeStart;
- std::shared_ptr<Gal::Pipeline> sectionsPipeline;
- std::shared_ptr<Gal::BufferBinding> sectionsBufferBinding;
+ std::shared_ptr<Gal::Pipeline> solidSectionsPipeline;
+ std::shared_ptr<Gal::BufferBinding> solidSectionsBufferBinding;
+ std::shared_ptr<Gal::Pipeline> liquidSectionsPipeline;
+ std::shared_ptr<Gal::BufferBinding> liquidSectionsBufferBinding;
//Entities
std::vector<RendererEntity> entities;
std::shared_ptr<Gal::Pipeline> entitiesPipeline;