summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaG1924 <12997935+LaG1924@users.noreply.github.com>2021-12-25 07:50:14 +0100
committerGitHub <noreply@github.com>2021-12-25 07:50:14 +0100
commit7ebc8e1bd33b6658b50153a26945814a87fba5f4 (patch)
tree51d377a4560a7e12b3b404b0b043d9f64981caf3 /src
parentMerge pull request #77 from LaG1924/ftr/graphics-abstraction-layer (diff)
parentAdded smooth lighting settings parameter (diff)
downloadAltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.tar
AltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.tar.gz
AltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.tar.bz2
AltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.tar.lz
AltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.tar.xz
AltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.tar.zst
AltCraft-7ebc8e1bd33b6658b50153a26945814a87fba5f4.zip
Diffstat (limited to 'src')
-rw-r--r--src/AssetManager.cpp3
-rw-r--r--src/AssetManager.hpp1
-rw-r--r--src/Gal.hpp58
-rw-r--r--src/GalOgl.cpp339
-rw-r--r--src/Render.cpp188
-rw-r--r--src/Render.hpp15
-rw-r--r--src/RenderConfigs.cpp287
-rw-r--r--src/RenderConfigs.hpp137
-rw-r--r--src/RendererEntity.cpp2
-rw-r--r--src/RendererSectionData.cpp243
-rw-r--r--src/RendererSectionData.hpp63
-rw-r--r--src/RendererWorld.cpp163
-rw-r--r--src/RendererWorld.hpp5
-rw-r--r--src/Rml.cpp13
-rw-r--r--src/TextureAtlas.cpp1
15 files changed, 1093 insertions, 425 deletions
diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp
index 0976e30..3e3f677 100644
--- a/src/AssetManager.cpp
+++ b/src/AssetManager.cpp
@@ -557,7 +557,7 @@ void ParseBlockModels() {
if (face.second.tintIndex)
parsedFace.color = glm::vec3(0.486, 0.745, 0.423);
else
- parsedFace.color = glm::vec3(0, 0, 0);
+ parsedFace.color = glm::vec3(1.0f);
model.parsedFaces.push_back(parsedFace);
}
@@ -594,6 +594,7 @@ BlockFaces &AssetManager::GetBlockModelByBlockId(BlockId block) {
blockFaces.transform = glm::mat4(1.0);
blockFaces.faces = assetModel->blockModel.parsedFaces;
blockFaces.isBlock = assetModel->blockModel.IsBlock;
+ blockFaces.ambientOcclusion = assetModel->blockModel.AmbientOcclusion;
glm::mat4 transform = glm::mat4(1.0);
if (model.y != 0) {
diff --git a/src/AssetManager.hpp b/src/AssetManager.hpp
index 2bee47c..59fc851 100644
--- a/src/AssetManager.hpp
+++ b/src/AssetManager.hpp
@@ -48,6 +48,7 @@ struct BlockFaces {
glm::mat4 transform;
std::vector<ParsedFace> faces;
bool isBlock;
+ bool ambientOcclusion;
Vector faceDirectionVector[FaceDirection::none];
};
diff --git a/src/Gal.hpp b/src/Gal.hpp
index f448c89..ed0b559 100644
--- a/src/Gal.hpp
+++ b/src/Gal.hpp
@@ -20,7 +20,7 @@ namespace Gal {
struct PipelineInstance;
struct FramebufferConfig;
struct Framebuffer;
- struct ShaderParameters;
+ struct ShaderParametersBuffer;
struct Shader;
@@ -61,8 +61,12 @@ namespace Gal {
enum class Format {
D24S8,
+ R8,
+ R8G8,
R8G8B8,
+ R8G8B8SN,
R8G8B8A8,
+ R32G32B32A32F,
};
enum class Filtering {
@@ -85,6 +89,11 @@ namespace Gal {
TriangleFan,
};
+ enum class Blending {
+ Opaque,
+ Additive,
+ };
+
struct VertexAttribute {
std::string name;
Type type;
@@ -106,6 +115,8 @@ namespace Gal {
virtual void SetScissor(bool enabled) = 0;
+ virtual void SetWireframe(bool enabled) = 0;
+
virtual std::shared_ptr<Buffer> CreateBuffer() = 0;
@@ -129,7 +140,7 @@ namespace Gal {
virtual std::shared_ptr<Framebuffer> GetDefaultFramebuffer() = 0;
- virtual std::shared_ptr<ShaderParameters> GetGlobalShaderParameters() = 0;
+ virtual std::shared_ptr<ShaderParametersBuffer> GetGlobalShaderParameters() = 0;
virtual std::shared_ptr<Shader> LoadVertexShader(std::string_view code) = 0;
@@ -156,11 +167,15 @@ namespace Gal {
virtual void SetWrapping(Wrapping wrapping) = 0;
+ virtual void SetLinear(bool isLinear) = 0;
+
};
struct Texture {
virtual ~Texture() = default;
+ virtual std::tuple<size_t, size_t, size_t> GetSize() = 0;
+
virtual void SetData(std::vector<std::byte>&& data, size_t mipLevel = 0) = 0;
virtual void SetSubData(size_t x, size_t y, size_t z, size_t width, size_t height, size_t depth, std::vector<std::byte> &&data, size_t mipLevel = 0) = 0;
@@ -181,6 +196,8 @@ namespace Gal {
virtual void SetPrimitive(Primitive primitive) = 0;
+ virtual void SetBlending(Blending blendingMode) = 0;
+
virtual std::shared_ptr<BufferBinding> BindVertexBuffer(std::vector<VertexAttribute> &&bufferLayout) = 0;
virtual std::shared_ptr<BufferBinding> BindIndexBuffer() = 0;
@@ -248,34 +265,23 @@ namespace Gal {
virtual void SetTexture(size_t location, std::shared_ptr<Texture> texture) = 0;
};
- struct ShaderParameters {
- virtual ~ShaderParameters() = default;
-
- virtual void AddGlobalShaderParameter(std::string_view name, Type type) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, float value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, double value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, int8_t value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, int16_t value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, int32_t value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, uint8_t value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, uint16_t value) = 0;
-
- virtual void SetGlobalShaderParameter(std::string_view name, uint32_t value) = 0;
+ struct ShaderParametersBuffer {
+ virtual ~ShaderParametersBuffer() = default;
- virtual void SetGlobalShaderParameter(std::string_view name, glm::vec2 value) = 0;
+ template<typename T>
+ T* Get() {
+ return reinterpret_cast<T*>(GetDataPtr());
+ }
- virtual void SetGlobalShaderParameter(std::string_view name, glm::vec3 value) = 0;
+ template<typename T>
+ void Resize() {
+ Resize(sizeof(T));
+ *Get<T>() = T{};
+ }
- virtual void SetGlobalShaderParameter(std::string_view name, glm::vec4 value) = 0;
+ virtual std::byte* GetDataPtr() = 0;
- virtual void SetGlobalShaderParameter(std::string_view name, glm::mat4 value) = 0;
+ virtual void Resize(size_t newSize) = 0;
};
struct Shader {
diff --git a/src/GalOgl.cpp b/src/GalOgl.cpp
index 052c68a..b046d4b 100644
--- a/src/GalOgl.cpp
+++ b/src/GalOgl.cpp
@@ -7,76 +7,13 @@
#include "Utility.hpp"
-enum class GlResourceType {
- Vbo,
- Vao,
- Texture,
- Fbo,
- Program,
- None,
-};
-
-class GlResource {
- GlResourceType type = GlResourceType::None;
- GLuint res = 0;
-public:
- GlResource() = default;
-
- GlResource(GLuint resource, GlResourceType resType) noexcept : res(resource), type(resType) {}
-
- GlResource(const GlResource&) = delete;
-
- GlResource(GlResource&& rhs) noexcept {
- std::swap(this->res, rhs.res);
- std::swap(this->type, rhs.type);
- }
-
- GlResource& operator=(const GlResource&) = delete;
-
- GlResource& operator=(GlResource&& rhs) noexcept {
- std::swap(this->res, rhs.res);
- std::swap(this->type, rhs.type);
- return *this;
- }
-
- ~GlResource() {
- switch (type) {
- case GlResourceType::Vbo:
- glDeleteBuffers(1, &res);
- break;
- case GlResourceType::Vao:
- glDeleteVertexArrays(1, &res);
- break;
- case GlResourceType::Texture:
- glDeleteTextures(1, &res);
- break;
- case GlResourceType::Fbo:
- glDeleteFramebuffers(1, &res);
- break;
- case GlResourceType::Program:
- glDeleteProgram(res);
- break;
- case GlResourceType::None:
- default:
- break;
- }
- }
-
- operator GLuint() const noexcept {
- return res;
- }
-
- GLuint Get() const noexcept {
- return res;
- }
-};
-
using namespace Gal;
-class ImplOgl;
-class ShaderOgl;
-class FramebufferOgl;
+struct ImplOgl;
+struct ShaderOgl;
+struct FramebufferOgl;
+struct ShaderParametersBufferOgl;
class OglState {
GLuint activeFbo = 0;
@@ -88,6 +25,7 @@ class OglState {
GLuint activeTextureUnit = 0;
GLint vpX = 0, vpY = 0;
GLsizei vpW = 0, vpH = 0;
+ bool blending = false;
public:
@@ -137,6 +75,7 @@ public:
if (activeTexture[textureUnit] != texture) {
SetTextureUnit(textureUnit);
glBindTexture(type, texture);
+ activeTexture[textureUnit] = texture;
}
glCheckError();
}
@@ -160,10 +99,119 @@ public:
glCheckError();
}
+ void EnableBlending(bool enable) {
+ if (enable != blending) {
+ blending = enable;
+ if (blending)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+ }
+ }
+
+ void ReleaseFbo(GLuint vao) {
+ if (activeVao == vao)
+ activeVao = 0;
+ }
+
+ void ReleaseVao(GLuint fbo) {
+ if (activeFbo == fbo)
+ activeEbo = 0;
+ }
+
+ void ReleaseVbo(GLuint vbo) {
+ if (activeVbo == vbo)
+ activeVbo = 0;
+ if (activeEbo == vbo)
+ activeEbo = 0;
+ }
+
+ void ReleaseProgram(GLuint program) {
+ if (activeProgram == program)
+ activeProgram = 0;
+ }
+
+ void ReleaseTexture(GLuint texture) {
+ for (auto& activeTex : activeTexture) {
+ if (activeTex == texture)
+ activeTex = 0;
+ }
+ }
+
} oglState;
+enum class GlResourceType {
+ Vbo,
+ Vao,
+ Texture,
+ Fbo,
+ Program,
+ None,
+};
+
+class GlResource {
+ GlResourceType type = GlResourceType::None;
+ GLuint res = 0;
+public:
+ GlResource() = default;
+
+ GlResource(GLuint resource, GlResourceType resType) noexcept : res(resource), type(resType) {}
+
+ GlResource(const GlResource&) = delete;
+
+ GlResource(GlResource&& rhs) noexcept {
+ std::swap(this->res, rhs.res);
+ std::swap(this->type, rhs.type);
+ }
+
+ GlResource& operator=(const GlResource&) = delete;
+
+ GlResource& operator=(GlResource&& rhs) noexcept {
+ std::swap(this->res, rhs.res);
+ std::swap(this->type, rhs.type);
+ return *this;
+ }
+
+ ~GlResource() {
+ switch (type) {
+ case GlResourceType::Vbo:
+ oglState.ReleaseVbo(res);
+ glDeleteBuffers(1, &res);
+ break;
+ case GlResourceType::Vao:
+ oglState.ReleaseVao(res);
+ glDeleteVertexArrays(1, &res);
+ break;
+ case GlResourceType::Texture:
+ oglState.ReleaseTexture(res);
+ glDeleteTextures(1, &res);
+ break;
+ case GlResourceType::Fbo:
+ oglState.ReleaseFbo(res);
+ glDeleteFramebuffers(1, &res);
+ break;
+ case GlResourceType::Program:
+ oglState.ReleaseProgram(res);
+ glDeleteProgram(res);
+ break;
+ case GlResourceType::None:
+ default:
+ break;
+ }
+ }
+
+ operator GLuint() const noexcept {
+ return res;
+ }
+
+ GLuint Get() const noexcept {
+ return res;
+ }
+};
+
std::unique_ptr<ImplOgl> impl;
std::shared_ptr<FramebufferOgl> fbDefault;
+std::shared_ptr<ShaderParametersBufferOgl> spbDefault;
size_t GalTypeGetComponents(Gal::Type type) {
switch (type) {
@@ -308,24 +356,64 @@ GLenum GalTypeGetComponentGlType(Gal::Type type) {
size_t GalFormatGetSize(Format format) {
switch (format) {
+ case Format::D24S8:
+ return 4;
+ case Format::R8:
+ return 1;
+ case Format::R8G8:
+ return 2;
case Format::R8G8B8:
return 3;
+ case Format::R8G8B8SN:
+ return 3;
case Format::R8G8B8A8:
return 4;
+ case Format::R32G32B32A32F:
+ return 16;
default:
return 0;
}
return 0;
}
-GLenum GalFormatGetGlInternalFormat(Format format) {
+GLenum GalFormatGetGlLinearInternalFormat(Format format) {
switch (format) {
case Format::D24S8:
return GL_DEPTH24_STENCIL8;
+ case Format::R8:
+ return GL_R8;
+ case Format::R8G8:
+ return GL_RG8;
case Format::R8G8B8:
return GL_RGB8;
+ case Format::R8G8B8SN:
+ return GL_RGB8_SNORM;
case Format::R8G8B8A8:
return GL_RGBA8;
+ case Format::R32G32B32A32F:
+ return GL_RGBA32F;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+GLenum GalFormatGetGlInternalFormat(Format format) {
+ switch (format) {
+ case Format::D24S8:
+ return 0;
+ case Format::R8:
+ return 0;
+ case Format::R8G8:
+ return 0;
+ case Format::R8G8B8:
+ return GL_SRGB;
+ case Format::R8G8B8SN:
+ return 0;
+ case Format::R8G8B8A8:
+ return GL_SRGB_ALPHA;
+ case Format::R32G32B32A32F:
+ return 0;
default:
return 0;
}
@@ -336,10 +424,18 @@ GLenum GalFormatGetGlFormat(Format format) {
switch (format) {
case Format::D24S8:
return GL_DEPTH_STENCIL;
+ case Format::R8:
+ return GL_RED;
+ case Format::R8G8:
+ return GL_RG;
case Format::R8G8B8:
return GL_RGB;
+ case Format::R8G8B8SN:
+ return GL_RGB;
case Format::R8G8B8A8:
return GL_RGBA;
+ case Format::R32G32B32A32F:
+ return GL_RGBA;
default:
return 0;
}
@@ -350,10 +446,18 @@ GLenum GalFormatGetGlType(Format format) {
switch (format) {
case Format::D24S8:
return GL_UNSIGNED_INT_24_8;
+ case Format::R8:
+ return GL_UNSIGNED_BYTE;
+ case Format::R8G8:
+ return GL_UNSIGNED_BYTE;
case Format::R8G8B8:
return GL_UNSIGNED_BYTE;
+ case Format::R8G8B8SN:
+ return GL_BYTE;
case Format::R8G8B8A8:
return GL_UNSIGNED_BYTE;
+ case Format::R32G32B32A32F:
+ return GL_FLOAT;
default:
return 0;
}
@@ -577,6 +681,7 @@ struct TextureConfigOgl : public TextureConfig {
Format format;
size_t width = 1, height = 1, depth = 1;
bool interpolateLayers = false;
+ bool linear = true;
GLenum type;
Filtering min = Filtering::Nearest, max = Filtering::Nearest;
@@ -594,6 +699,10 @@ struct TextureConfigOgl : public TextureConfig {
wrap = wrapping;
}
+ virtual void SetLinear(bool isLinear) override {
+ linear = isLinear;
+ }
+
};
struct TextureOgl : public Texture {
@@ -602,12 +711,19 @@ struct TextureOgl : public Texture {
GlResource texture;
Format format;
size_t width, height, depth;
+ bool linear;
+
+ virtual std::tuple<size_t, size_t, size_t> GetSize() override {
+ return { width, height, depth };
+ }
virtual void SetData(std::vector<std::byte>&& data, size_t mipLevel = 0) override {
size_t expectedSize = width * height * depth * GalFormatGetSize(format);
if (data.size() != expectedSize && !data.empty())
throw std::logic_error("Size of data is not valid for this texture");
+ GLenum internalFormat = linear ? GalFormatGetGlLinearInternalFormat(format) : GalFormatGetGlInternalFormat(format);
+
oglState.BindTexture(type, texture);
switch (type) {
@@ -627,13 +743,13 @@ struct TextureOgl : public Texture {
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
case GL_PROXY_TEXTURE_CUBE_MAP:
- glTexImage2D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
+ glTexImage2D(type, mipLevel, internalFormat, width, height, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
break;
case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
case GL_PROXY_TEXTURE_2D_ARRAY:
- glTexImage3D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, depth, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
+ glTexImage3D(type, mipLevel, internalFormat, width, height, depth, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
break;
default:
throw std::runtime_error("Unknown texture type");
@@ -690,6 +806,7 @@ struct FramebufferOgl : public Framebuffer {
size_t vpX = 0, vpY = 0, vpW = 1, vpH = 1;
std::shared_ptr<TextureOgl> depthStencil;
std::vector<std::shared_ptr<TextureOgl>> colors;
+ std::vector<GLenum> attachments;
GlResource fbo;
@@ -729,6 +846,22 @@ struct FramebufferConfigOgl : public FramebufferConfig {
}
};
+struct ShaderParametersBufferOgl : public ShaderParametersBuffer {
+ std::shared_ptr<BufferOgl> buffer;
+ bool dirty = true;
+ std::vector<std::byte> data;
+
+ virtual std::byte* GetDataPtr() override {
+ dirty = true;
+ return data.data();
+ }
+
+ virtual void Resize(size_t newSize) override {
+ dirty = true;
+ data.resize(newSize);
+ }
+};
+
struct PipelineConfigOgl : public PipelineConfig {
std::shared_ptr<ShaderOgl> vertexShader, pixelShader;
@@ -737,6 +870,7 @@ struct PipelineConfigOgl : public PipelineConfig {
std::shared_ptr<FramebufferOgl> targetFb;
std::vector<std::vector<VertexAttribute>> vertexBuffers;
Primitive vertexPrimitive = Primitive::Triangle;
+ Blending blending = Blending::Opaque;
virtual void SetVertexShader(std::shared_ptr<Shader> shader) override {
vertexShader = std::static_pointer_cast<ShaderOgl,Shader>(shader);
@@ -764,6 +898,10 @@ struct PipelineConfigOgl : public PipelineConfig {
vertexPrimitive = primitive;
}
+ virtual void SetBlending(Blending blendingMode) override {
+ blending = blendingMode;
+ }
+
virtual std::shared_ptr<BufferBinding> BindVertexBuffer(std::vector<VertexAttribute> &&bufferLayout) override {
auto binding = std::make_shared<BufferBindingOgl>(vertexBuffers.size());
vertexBuffers.push_back(bufferLayout);
@@ -832,7 +970,7 @@ struct PipelineInstanceOgl : public PipelineInstance {
};
struct PipelineOgl : public Pipeline {
-
+ std::vector<std::shared_ptr<ShaderParametersBufferOgl>> spbs;
std::map<std::string, size_t> shaderParameters;
std::vector<std::shared_ptr<TextureOgl>> staticTextures;
GlResource program;
@@ -847,16 +985,27 @@ struct PipelineOgl : public Pipeline {
};
std::vector<VertexBindingCommand> vertexBindCmds;
Primitive primitive;
+ Blending blending;
std::shared_ptr<FramebufferOgl> target;
virtual void Activate() override {
oglState.UseProgram(program);
oglState.BindFbo(target->fbo);
oglState.SetViewport(target->vpX, target->vpY, target->vpW, target->vpH);
+ oglState.EnableBlending(blending == Blending::Additive);
+ if (target->fbo)
+ glDrawBuffers(target->attachments.size(), target->attachments.data());
for (size_t i = 0; i < staticTextures.size(); i++) {
oglState.BindTexture(staticTextures[i]->type, staticTextures[i]->texture, i);
}
+
+ for (auto& spb : spbs) {
+ if (spb->dirty) {
+ spb->buffer->SetData(std::vector<std::byte>(spb->data));
+ spb->dirty = false;
+ }
+ }
}
virtual void SetDynamicTexture(std::string_view name, std::shared_ptr<Texture> texture) override {
@@ -1013,13 +1162,15 @@ struct ImplOgl : public Impl {
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
- glEnable(GL_BLEND);
+ oglState.EnableBlending(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glCheckError();
if (glActiveTexture == nullptr) {
throw std::runtime_error("GLEW initialization failed with unknown reason");
}
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
@@ -1055,6 +1206,10 @@ struct ImplOgl : public Impl {
glCheckError();
}
+ virtual void SetWireframe(bool enabled) override {
+ glPolygonMode(GL_FRONT_AND_BACK, enabled ? GL_LINE : GL_FILL);
+ }
+
virtual std::shared_ptr<Buffer> CreateBuffer() override {
auto buff = std::make_shared<BufferOgl>();
@@ -1101,6 +1256,7 @@ struct ImplOgl : public Impl {
texture->width = texConfig->width;
texture->height = texConfig->height;
texture->depth = texConfig->depth;
+ texture->linear = texConfig->linear;
GLuint newTex;
glGenTextures(1, &newTex);
@@ -1131,6 +1287,7 @@ struct ImplOgl : public Impl {
auto config = std::static_pointer_cast<PipelineConfigOgl, PipelineConfig>(pipelineConfig);
pipeline->primitive = config->vertexPrimitive;
+ pipeline->blending = config->blending;
pipeline->target = config->targetFb;
if (!pipeline->target)
@@ -1198,6 +1355,23 @@ struct ImplOgl : public Impl {
/*
+ * Shader parameters buffers
+ */
+ constexpr auto spbGlobalsName = "Globals";
+ size_t spbGlobalsBind = 0;
+ size_t spbIndex = glGetUniformBlockIndex(program, spbGlobalsName);
+ if (spbIndex != GL_INVALID_VALUE) {
+ glUniformBlockBinding(program, spbIndex, spbGlobalsBind);
+ auto spbGlobals = std::static_pointer_cast<ShaderParametersBufferOgl, ShaderParametersBuffer>(GetGlobalShaderParameters());
+ glBindBufferBase(GL_UNIFORM_BUFFER, spbGlobalsBind, spbGlobals->buffer->vbo);
+ pipeline->spbs.emplace_back(spbGlobals);
+ }
+ else
+ LOG(ERROR) << "Cannot bind Globals UBO to shader. Maybe uniform block Globals missing?";
+ glCheckError();
+
+
+ /*
* Shader parameters
*/
for (auto&& [name, type] : config->shaderParameters) {
@@ -1222,6 +1396,7 @@ struct ImplOgl : public Impl {
glUniform1i(location, usedTextureBlocks);
pipeline->staticTextures.push_back(texture);
+ usedTextureBlocks++;
}
glCheckError();
@@ -1247,6 +1422,11 @@ struct ImplOgl : public Impl {
size_t attribSize = GalTypeGetSize(type);
for (size_t i = 0; i < count; i++) {
+ if (location < 0) {
+ vertexSize += attribSize;
+ continue;
+ }
+
pipeline->vertexBindCmds.push_back({
bufferId,
static_cast<size_t>(location + i),
@@ -1295,6 +1475,7 @@ struct ImplOgl : public Impl {
for (auto&& [location, texture] : conf->colors) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + location, texture->type, texture->texture, 0);
fb->colors.emplace_back(std::move(texture));
+ fb->attachments.push_back(GL_COLOR_ATTACHMENT0 + location);
}
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
@@ -1308,15 +1489,21 @@ struct ImplOgl : public Impl {
}
virtual std::shared_ptr<Framebuffer> GetDefaultFramebuffer() override {
- if (!fbDefault)
+ if (!fbDefault) {
fbDefault = std::make_shared<FramebufferOgl>();
- fbDefault->fbo = GlResource(0, GlResourceType::None);
+ fbDefault->fbo = GlResource(0, GlResourceType::None);
+ fbDefault->attachments.push_back(GL_COLOR_ATTACHMENT0);
+ }
return std::static_pointer_cast<Framebuffer, FramebufferOgl>(fbDefault);
}
- virtual std::shared_ptr<ShaderParameters> GetGlobalShaderParameters() override {
- return nullptr;
+ virtual std::shared_ptr<ShaderParametersBuffer> GetGlobalShaderParameters() override {
+ if (!spbDefault) {
+ spbDefault = std::make_shared<ShaderParametersBufferOgl>();
+ spbDefault->buffer = std::static_pointer_cast<BufferOgl, Buffer>(GetImplementation()->CreateBuffer());
+ }
+ return spbDefault;
}
virtual std::shared_ptr<Shader> LoadVertexShader(std::string_view code) override {
diff --git a/src/Render.cpp b/src/Render.cpp
index 6301ff5..fe9dc04 100644
--- a/src/Render.cpp
+++ b/src/Render.cpp
@@ -1,5 +1,7 @@
#include "Render.hpp"
+#include <random>
+
#include <easylogging++.h>
#include <optick.h>
#include <RmlUi/Core.h>
@@ -17,6 +19,7 @@
#include "Plugin.hpp"
#include "Rml.hpp"
#include "Gal.hpp"
+#include "RenderConfigs.hpp"
const std::map<SDL_Keycode, Rml::Input::KeyIdentifier> keyMapping = {
{SDLK_BACKSPACE, Rml::Input::KI_BACK},
@@ -77,9 +80,8 @@ Render::~Render() {
rmlRender.reset();
rmlSystem.reset();
- PluginSystem::Init();
+ PluginSystem::Init();
- framebuffer.reset();
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
@@ -123,6 +125,7 @@ void Render::InitSdl(unsigned int WinWidth, unsigned int WinHeight, std::string
void Render::InitGlew() {
auto gal = Gal::GetImplementation();
gal->Init();
+ gal->GetGlobalShaderParameters()->Resize<GlobalShaderParameters>();
int width, height;
SDL_GL_GetDrawableSize(window, &width, &height);
@@ -139,64 +142,79 @@ void Render::PrepareToRendering() {
auto gal = Gal::GetImplementation();
gal->GetDefaultFramebuffer()->SetViewport(0, 0, width, height);
+ gal->GetGlobalShaderParameters()->Get<GlobalShaderParameters>()->gamma = Settings::ReadDouble("gamma", 2.2);
+
+ gbuffer.reset();
+ resizeTextureCopy.reset();
+ fbTextureCopy.reset();
+ fbTextureColor.reset();
+ fbTextureDepthStencil.reset();
+ fbTarget.reset();
+
+ bool useDeffered = Settings::ReadBool("deffered", false);
+ bool useResize = scaledW != width;
+
+ if (useDeffered) {
+ std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
+ std::uniform_real_distribution<float> dis(-1.0f, 1.0f);
+ auto& ssaoKernels = gal->GetGlobalShaderParameters()->Get<GlobalShaderParameters>()->ssaoKernels;
+ for (auto& vec : ssaoKernels) {
+ vec.x = dis(rng);
+ vec.y = dis(rng);
+ vec.z = (dis(rng) + 1.0f) / 2.0f;
+ vec.w = 0.0f;
+ vec = glm::normalize(vec);
+ }
+ for (size_t i = 0; i < sizeof(ssaoKernels) / sizeof(*ssaoKernels); i++) {
+ float scale = i / 64.0f;
+ scale = glm::mix(0.1f, 1.0f, scale * scale);
+ ssaoKernels[i] *= scale;
+ }
-
- auto dsTexConf = gal->CreateTexture2DConfig(scaledW, scaledH, Gal::Format::D24S8);
- dsTexConf->SetMinFilter(Gal::Filtering::Nearest);
- dsTexConf->SetMaxFilter(Gal::Filtering::Nearest);
- fbDepthStencil = gal->BuildTexture(dsTexConf);
-
- auto texConf = gal->CreateTexture2DConfig(scaledW, scaledH, Gal::Format::R8G8B8A8);
- texConf->SetMinFilter(Gal::Filtering::Nearest);
- texConf->SetMaxFilter(Gal::Filtering::Nearest);
- fbColor = gal->BuildTexture(texConf);
-
- auto fbConf = gal->CreateFramebufferConfig();
- fbConf->SetTexture(0, fbColor);
- fbConf->SetDepthStencil(fbDepthStencil);
-
- framebuffer = gal->BuildFramebuffer(fbConf);
- framebuffer->SetViewport(0, 0, scaledW, scaledH);
- framebuffer->Clear();
-
- std::string vertexSource, pixelSource;
- {
- auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/fbo");
- vertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
-
- auto pixelAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/fbo");
- pixelSource = std::string((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size());
+ int ssaoSamples = Settings::ReadDouble("ssaoSamples", 0);
+ float ssaoScale = Settings::ReadDouble("ssaoScale", 0.5f);
+ size_t ssaoW = scaledW * ssaoScale, ssaoH = scaledH * ssaoScale;
+
+ gbuffer = std::make_unique<Gbuffer>(scaledW, scaledH, scaledW, scaledH, ssaoSamples, ssaoW, ssaoH);
+ gbuffer->SetRenderBuff(renderBuff);
+ fbTarget = gbuffer->GetGeometryTarget();
+ if (useResize) {
+ auto fbTextureColorConf = gal->CreateTexture2DConfig(scaledW, scaledH, Gal::Format::R8G8B8);
+ fbTextureColorConf->SetMinFilter(Gal::Filtering::Bilinear);
+ fbTextureColorConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ fbTextureColor = gal->BuildTexture(fbTextureColorConf);
+
+ resizeTextureCopy = std::make_unique<TextureFbCopy>(gbuffer->GetFinalTexture(), fbTextureColor);
+ fbTextureCopy = std::make_unique<TextureFbCopy>(fbTextureColor, gal->GetDefaultFramebuffer());
+ } else {
+ fbTextureCopy = std::make_unique<TextureFbCopy>(gbuffer->GetFinalTexture(), gal->GetDefaultFramebuffer());
+ }
+ } else {
+ if (useResize) {
+ auto fbTextureColorConf = gal->CreateTexture2DConfig(scaledW, scaledH, Gal::Format::R8G8B8);
+ fbTextureColorConf->SetMinFilter(Gal::Filtering::Bilinear);
+ fbTextureColorConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ fbTextureColor = gal->BuildTexture(fbTextureColorConf);
+
+ auto fbTextureDepthStencilConf = gal->CreateTexture2DConfig(scaledW, scaledH, Gal::Format::D24S8);
+ fbTextureDepthStencilConf->SetMinFilter(Gal::Filtering::Bilinear);
+ fbTextureDepthStencilConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ fbTextureDepthStencil = gal->BuildTexture(fbTextureDepthStencilConf);
+
+ auto fbTargetConf = gal->CreateFramebufferConfig();
+ fbTargetConf->SetTexture(0, fbTextureColor);
+ fbTargetConf->SetDepthStencil(fbTextureDepthStencil);
+ fbTarget = gal->BuildFramebuffer(fbTargetConf);
+ fbTarget->SetViewport(0, 0, scaledW, scaledH);
+
+ fbTextureCopy = std::make_unique<TextureFbCopy>(fbTextureColor, gal->GetDefaultFramebuffer());
+ } else {
+ fbTarget = gal->GetDefaultFramebuffer();
+ }
}
- constexpr float quadVertices[] = {
- // positions // texCoords
- -1.0f, 1.0f, 0.0f, 1.0f,
- -1.0f, -1.0f, 0.0f, 0.0f,
- 1.0f, -1.0f, 1.0f, 0.0f,
-
- -1.0f, 1.0f, 0.0f, 1.0f,
- 1.0f, -1.0f, 1.0f, 0.0f,
- 1.0f, 1.0f, 1.0f, 1.0f
- };
- fbBuffer = gal->CreateBuffer();
- fbBuffer->SetData({ reinterpret_cast<const std::byte*>(quadVertices), reinterpret_cast<const std::byte*>(quadVertices) + sizeof(quadVertices) });
- auto fbPPC = gal->CreatePipelineConfig();
- fbPPC->SetTarget(gal->GetDefaultFramebuffer());
- fbPPC->SetVertexShader(gal->LoadVertexShader(vertexSource));
- fbPPC->SetPixelShader(gal->LoadPixelShader(pixelSource));
- fbPPC->AddStaticTexture("inputTexture", fbColor);
- auto fbColorBB = fbPPC->BindVertexBuffer({
- {"Pos", Gal::Type::Vec2},
- {"TextureCoords", Gal::Type::Vec2}
- });
-
- fbPipeline = gal->BuildPipeline(fbPPC);
- fbPipelineInstance = fbPipeline->CreateInstance({
- {fbColorBB, fbBuffer}
- });
-
if (world)
- world->PrepareRender(framebuffer);
+ world->PrepareRender(fbTarget, useDeffered);
}
void Render::UpdateKeyboard() {
@@ -221,18 +239,29 @@ void Render::RenderFrame() {
OPTICK_EVENT();
Gal::GetImplementation()->GetDefaultFramebuffer()->Clear();
- framebuffer->Clear();
-
- //if (isWireframe)
- //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- if (renderWorld)
+ if (gbuffer)
+ gbuffer->Clear();
+ if (fbTarget)
+ fbTarget->Clear();
+ if (resizeTextureCopy)
+ resizeTextureCopy->Clear();
+ if (fbTextureCopy)
+ fbTextureCopy->Clear();
+
+ if (isWireframe)
+ Gal::GetImplementation()->SetWireframe(true);
+ if (renderWorld) {
world->Render(static_cast<float>(windowWidth) / static_cast<float>(windowHeight));
- //if (isWireframe)
- //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ if (isWireframe)
+ Gal::GetImplementation()->SetWireframe(false);
- fbPipeline->Activate();
- fbPipelineInstance->Activate();
- fbPipelineInstance->Render(0, 6);
+ if (gbuffer)
+ gbuffer->Render();
+ if (resizeTextureCopy)
+ resizeTextureCopy->Copy();
+ if (fbTextureCopy)
+ fbTextureCopy->Copy();
RenderGui();
@@ -266,6 +295,7 @@ void Render::HandleEvents() {
windowHeight = height;
rmlRender->Update(width, height);
rmlContext->SetDimensions(Rml::Vector2i(width, height));
+ Gal::GetImplementation()->GetGlobalShaderParameters()->Get<GlobalShaderParameters>()->viewportSize = glm::uvec2(width, height);
PrepareToRendering();
break;
}
@@ -347,6 +377,23 @@ void Render::HandleEvents() {
break;
}
+ case SDL_SCANCODE_F9: {
+ if (sdlKeyMods & KMOD_CTRL) {
+ renderBuff = 0;
+ } else if (sdlKeyMods & KMOD_SHIFT) {
+ renderBuff--;
+ if (renderBuff < 0)
+ renderBuff = 0;
+ } else {
+ renderBuff++;
+ if (renderBuff > gbuffer->GetMaxRenderBuffers())
+ renderBuff = 0;
+ }
+ if (gbuffer)
+ gbuffer->SetRenderBuff(renderBuff);
+ break;
+ }
+
default:
break;
}
@@ -487,7 +534,7 @@ void Render::InitEvents() {
listener.RegisterHandler("PlayerConnected", [this](const Event&) {
stateString = "Loading terrain...";
- world = std::make_unique<RendererWorld>(framebuffer);
+ world = std::make_unique<RendererWorld>(fbTarget, Settings::ReadBool("deffered", false), Settings::ReadBool("smoothlight", false));
world->MaxRenderingDistance = Settings::ReadDouble("renderDistance", 2.0f);
PUSH_EVENT("UpdateSectionsRender", 0);
});
@@ -497,7 +544,6 @@ void Render::InitEvents() {
renderWorld = true;
SetState(State::Playing);
GetGameState()->GetPlayer()->isFlying = Settings::ReadBool("flight", false);
- PUSH_EVENT("SetMinLightLevel", (float)Settings::ReadDouble("brightness", 0.2f));
});
listener.RegisterHandler("ConnectionFailed", [this](const Event& eventData) {
@@ -560,6 +606,7 @@ void Render::InitEvents() {
listener.RegisterHandler("SettingsUpdate", [this](const Event& eventData) {
if (world) {
+ world->smoothLighting = Settings::ReadBool("smoothlight", false);
float renderDistance = Settings::ReadDouble("renderDistance", 2.0f);
if (renderDistance != world->MaxRenderingDistance) {
world->MaxRenderingDistance = renderDistance;
@@ -591,8 +638,8 @@ void Render::InitEvents() {
else
SDL_GL_SetSwapInterval(0);
- float brightness = Settings::ReadDouble("brightness", 0.2f);
- PUSH_EVENT("SetMinLightLevel", brightness);
+
+ Gal::GetImplementation()->GetGlobalShaderParameters()->Get<GlobalShaderParameters>()->gamma = Settings::ReadDouble("gamma", 2.2);
PrepareToRendering();
});
@@ -607,6 +654,7 @@ void Render::InitRml() {
rmlRender = std::make_unique<RmlRenderInterface>();
Rml::SetRenderInterface(rmlRender.get());
rmlRender->Update(windowWidth, windowHeight);
+ Gal::GetImplementation()->GetGlobalShaderParameters()->Get<GlobalShaderParameters>()->viewportSize = glm::uvec2(windowWidth, windowHeight);
rmlFile = std::make_unique<RmlFileInterface>();
Rml::SetFileInterface(rmlFile.get());
diff --git a/src/Render.hpp b/src/Render.hpp
index 87494fa..3ac76e3 100644
--- a/src/Render.hpp
+++ b/src/Render.hpp
@@ -11,6 +11,8 @@
#include "Event.hpp"
#include "Gal.hpp"
+class Gbuffer;
+class TextureFbCopy;
class RendererWorld;
class RmlRenderInterface;
class RmlSystemInterface;
@@ -35,12 +37,12 @@ class Render {
bool HasFocus=true;
float sensetivity = 0.1f;
bool isWireframe = false;
- std::shared_ptr<Gal::Framebuffer> framebuffer;
- std::shared_ptr<Gal::Texture> fbDepthStencil;
- std::shared_ptr<Gal::Texture> fbColor;
- std::shared_ptr<Gal::Pipeline> fbPipeline;
- std::shared_ptr<Gal::PipelineInstance> fbPipelineInstance;
- std::shared_ptr<Gal::Buffer> fbBuffer;
+ std::unique_ptr<TextureFbCopy> resizeTextureCopy;
+ std::unique_ptr<TextureFbCopy> fbTextureCopy;
+ std::shared_ptr<Gal::Texture> fbTextureColor;
+ std::shared_ptr<Gal::Texture> fbTextureDepthStencil;
+ std::shared_ptr<Gal::Framebuffer> fbTarget;
+ std::unique_ptr<Gbuffer> gbuffer;
EventListener listener;
std::string stateString;
std::unique_ptr<RmlRenderInterface> rmlRender;
@@ -49,6 +51,7 @@ class Render {
Rml::Context* rmlContext;
unsigned short sdlKeyMods = 0;
bool hideRml = false;
+ size_t renderBuff = 0;
void SetMouseCapture(bool IsCaptured);
diff --git a/src/RenderConfigs.cpp b/src/RenderConfigs.cpp
new file mode 100644
index 0000000..78b442d
--- /dev/null
+++ b/src/RenderConfigs.cpp
@@ -0,0 +1,287 @@
+#include "RenderConfigs.hpp"
+
+#include <chrono>
+#include <random>
+
+#include "AssetManager.hpp"
+
+std::string LoadShaderCode(std::string_view assetPath) {
+ auto gal = Gal::GetImplementation();
+ auto codeAsset = AssetManager::GetAssetByAssetName(std::string(assetPath));
+ auto codePtr = reinterpret_cast<const char*>(codeAsset->data.data());
+ return std::string(codePtr, codePtr + codeAsset->data.size());
+}
+
+std::shared_ptr<Gal::Shader> LoadVertexShader(std::string_view assetPath) {
+ auto gal = Gal::GetImplementation();
+ return gal->LoadVertexShader(LoadShaderCode(assetPath));
+}
+
+std::shared_ptr<Gal::Shader> LoadPixelShader(std::string_view assetPath) {
+ auto gal = Gal::GetImplementation();
+ return gal->LoadPixelShader(LoadShaderCode(assetPath));
+}
+
+TextureFbCopy::TextureFbCopy(
+ std::shared_ptr<Gal::Texture> inputTexture,
+ std::shared_ptr<Gal::Texture> outputTexture,
+ std::shared_ptr<Gal::Shader> copyShader) {
+
+ auto gal = Gal::GetImplementation();
+
+ auto fbConf = gal->CreateFramebufferConfig();
+ fbConf->SetTexture(0, outputTexture);
+
+ auto [outputW, outputH, outputD] = outputTexture->GetSize();
+
+ framebuffer = gal->BuildFramebuffer(fbConf);
+ framebuffer->SetViewport(0, 0, outputW, outputH);
+
+ auto fbPPC = gal->CreatePipelineConfig();
+ fbPPC->SetTarget(framebuffer);
+
+ fbPPC->AddStaticTexture("inputTexture", inputTexture);
+
+ fbPPC->SetVertexShader(LoadVertexShader("/altcraft/shaders/vert/quad"));
+ fbPPC->SetPixelShader(copyShader ? copyShader : LoadPixelShader("/altcraft/shaders/frag/copy"));
+ auto fbBufferBB = fbPPC->BindVertexBuffer({
+ {"pos", Gal::Type::Vec2},
+ {"uvPos", Gal::Type::Vec2}
+ });
+
+ pipeline = gal->BuildPipeline(fbPPC);
+
+ fbBuffer = gal->CreateBuffer();
+ constexpr float quadVertices[] = {
+ // pos // uv
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+ auto quadPtr = reinterpret_cast<const std::byte*>(quadVertices);
+ fbBuffer->SetData({ quadPtr, quadPtr + sizeof(quadVertices) });
+
+ pipelineInstance = pipeline->CreateInstance({
+ {fbBufferBB, fbBuffer}
+ });
+}
+
+TextureFbCopy::TextureFbCopy(
+ std::shared_ptr<Gal::Texture> inputTexture,
+ std::shared_ptr<Gal::Framebuffer> outputFb,
+ std::shared_ptr<Gal::Shader> copyShader) {
+
+ auto gal = Gal::GetImplementation();
+
+ framebuffer = outputFb;
+
+ auto fbPPC = gal->CreatePipelineConfig();
+ fbPPC->SetTarget(framebuffer);
+
+ fbPPC->AddStaticTexture("inputTexture", inputTexture);
+
+ fbPPC->SetVertexShader(LoadVertexShader("/altcraft/shaders/vert/quad"));
+ fbPPC->SetPixelShader(copyShader ? copyShader : LoadPixelShader("/altcraft/shaders/frag/copy"));
+ auto fbBufferBB = fbPPC->BindVertexBuffer({
+ {"pos", Gal::Type::Vec2},
+ {"uvPos", Gal::Type::Vec2}
+ });
+
+ pipeline = gal->BuildPipeline(fbPPC);
+
+ fbBuffer = gal->CreateBuffer();
+ constexpr float quadVertices[] = {
+ // pos // uv
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+ auto quadPtr = reinterpret_cast<const std::byte*>(quadVertices);
+ fbBuffer->SetData({ quadPtr, quadPtr + sizeof(quadVertices) });
+
+ pipelineInstance = pipeline->CreateInstance({
+ {fbBufferBB, fbBuffer}
+ });
+}
+
+PostProcess::PostProcess(
+ std::shared_ptr<Gal::Shader> pixelShader,
+ std::vector<std::pair<std::string_view, std::shared_ptr<Gal::Texture>>> inputTextures,
+ std::vector<std::pair<std::string_view, Gal::Type>> inputParameters,
+ size_t width,
+ size_t height,
+ Gal::Format format,
+ Gal::Filtering filtering) {
+ auto gal = Gal::GetImplementation();
+
+ auto texConf = gal->CreateTexture2DConfig(width, height, format);
+ texConf->SetMinFilter(filtering);
+ texConf->SetMaxFilter(filtering);
+
+ result = gal->BuildTexture(texConf);
+
+ auto fbConf = gal->CreateFramebufferConfig();
+ fbConf->SetTexture(0, result);
+
+ framebuffer = gal->BuildFramebuffer(fbConf);
+ framebuffer->SetViewport(0, 0, width, height);
+
+ auto fbPPC = gal->CreatePipelineConfig();
+ fbPPC->SetTarget(framebuffer);
+ for (auto&& [name, texture] : inputTextures) {
+ fbPPC->AddStaticTexture(name, texture);
+ }
+ for (auto&& [name, type] : inputParameters) {
+ fbPPC->AddShaderParameter(name, type);
+ }
+ fbPPC->SetVertexShader(LoadVertexShader("/altcraft/shaders/vert/quad"));
+ fbPPC->SetPixelShader(pixelShader);
+ auto fbBufferBB = fbPPC->BindVertexBuffer({
+ {"pos", Gal::Type::Vec2},
+ {"uvPos", Gal::Type::Vec2}
+ });
+
+ pipeline = gal->BuildPipeline(fbPPC);
+
+ fbBuffer = gal->CreateBuffer();
+ constexpr float quadVertices[] = {
+ // pos // uv
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+ auto quadPtr = reinterpret_cast<const std::byte*>(quadVertices);
+ fbBuffer->SetData({ quadPtr, quadPtr + sizeof(quadVertices) });
+
+ pipelineInstance = pipeline->CreateInstance({
+ {fbBufferBB, fbBuffer}
+ });
+}
+
+Gbuffer::Gbuffer(size_t geomW, size_t geomH, size_t lightW, size_t lightH, int ssaoSamples, size_t ssaoW, size_t ssaoH) {
+ auto gal = Gal::GetImplementation();
+
+ auto colorConf = gal->CreateTexture2DConfig(geomW, geomH, Gal::Format::R8G8B8);
+ colorConf->SetMinFilter(Gal::Filtering::Bilinear);
+ colorConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ color = gal->BuildTexture(colorConf);
+
+ auto normalConf = gal->CreateTexture2DConfig(geomW, geomH, Gal::Format::R8G8B8SN);
+ normalConf->SetMinFilter(Gal::Filtering::Bilinear);
+ normalConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ normal = gal->BuildTexture(normalConf);
+
+ auto lightConf = gal->CreateTexture2DConfig(geomW, geomH, Gal::Format::R8G8B8);
+ lightConf->SetMinFilter(Gal::Filtering::Bilinear);
+ lightConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ light = gal->BuildTexture(lightConf);
+
+ auto dsConf = gal->CreateTexture2DConfig(geomW, geomH, Gal::Format::D24S8);
+ dsConf->SetMinFilter(Gal::Filtering::Bilinear);
+ dsConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ depthStencil = gal->BuildTexture(dsConf);
+
+ auto geomFbConf = gal->CreateFramebufferConfig();
+ geomFbConf->SetDepthStencil(depthStencil);
+ geomFbConf->SetTexture(0, color);
+ geomFbConf->SetTexture(1, normal);
+ geomFbConf->SetTexture(2, light);
+
+ geomFramebuffer = gal->BuildFramebuffer(geomFbConf);
+ geomFramebuffer->SetViewport(0, 0, geomW, geomH);
+
+ if (ssaoSamples > 0) {
+ auto noiseConf = gal->CreateTexture2DConfig(4, 4, Gal::Format::R8G8B8SN);
+ noiseConf->SetWrapping(Gal::Wrapping::Repeat);
+ noiseConf->SetMinFilter(Gal::Filtering::Bilinear);
+ noiseConf->SetMaxFilter(Gal::Filtering::Bilinear);
+ ssaoNoise = gal->BuildTexture(noiseConf);
+
+ std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
+ std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+ std::vector<glm::i8vec3> noiseTexData(16);
+ for (auto& vec : noiseTexData) {
+ vec.x = static_cast<int8_t>(dis(rng) * 128.0f);
+ vec.y = static_cast<int8_t>(dis(rng) * 128.0f);
+ vec.z = 0.0f;
+ }
+ ssaoNoise->SetData({ reinterpret_cast<std::byte*>(noiseTexData.data()), reinterpret_cast<std::byte*>(noiseTexData.data() + noiseTexData.size()) });
+
+ std::vector<std::pair<std::string_view, std::shared_ptr<Gal::Texture>>> ssaoTextures = {
+ {"normal", normal},
+ {"light", light},
+ {"depthStencil", depthStencil},
+ {"ssaoNoise", ssaoNoise},
+ };
+
+ std::vector<std::pair<std::string_view, Gal::Type>> ssaoParameters = {
+ {"ssaoSamples", Gal::Type::Int32},
+ };
+
+ ssaoPass = std::make_unique<PostProcess>(LoadPixelShader("/altcraft/shaders/frag/ssao"),
+ ssaoTextures,
+ ssaoParameters,
+ ssaoW,
+ ssaoH,
+ Gal::Format::R8,
+ Gal::Filtering::Bilinear);
+
+ ssaoPass->SetShaderParameter("ssaoSamples", ssaoSamples);
+
+ std::vector<std::pair<std::string_view, std::shared_ptr<Gal::Texture>>> ssaoBlurTextures = {
+ {"blurInput", ssaoPass->GetResultTexture()},
+ };
+
+ std::vector<std::pair<std::string_view, Gal::Type>> ssaoBlurParameters = {
+ {"blurScale", Gal::Type::Int32},
+ };
+
+ ssaoBlurPass = std::make_unique<PostProcess>(LoadPixelShader("/altcraft/shaders/frag/blur"),
+ ssaoBlurTextures,
+ ssaoBlurParameters,
+ ssaoW,
+ ssaoH,
+ Gal::Format::R8,
+ Gal::Filtering::Bilinear);
+
+ ssaoBlurPass->SetShaderParameter("blurScale", 2);
+ }
+
+ std::vector<std::pair<std::string_view, Gal::Type>> lightingParameters = {
+ {"renderBuff", Gal::Type::Int32},
+ {"applySsao", Gal::Type::Int32},
+ };
+
+ std::vector<std::pair<std::string_view, std::shared_ptr<Gal::Texture>>> lightingTextures = {
+ {"depthStencil", depthStencil},
+ {"color", color},
+ {"normal", normal},
+ {"light", light},
+ };
+
+ if (ssaoSamples > 0)
+ lightingTextures.emplace_back("ssao", ssaoBlurPass->GetResultTexture());
+
+ lightingPass = std::make_unique<PostProcess>(LoadPixelShader("/altcraft/shaders/frag/light"),
+ lightingTextures,
+ lightingParameters,
+ lightW,
+ lightH,
+ Gal::Format::R8G8B8,
+ Gal::Filtering::Bilinear);
+
+ lightingPass->SetShaderParameter("applySsao", ssaoSamples);
+}
+
diff --git a/src/RenderConfigs.hpp b/src/RenderConfigs.hpp
new file mode 100644
index 0000000..9d1ffcd
--- /dev/null
+++ b/src/RenderConfigs.hpp
@@ -0,0 +1,137 @@
+#pragma once
+
+#include "Gal.hpp"
+
+struct GlobalShaderParameters {
+ glm::mat4 projView;
+ glm::mat4 proj;
+ glm::mat4 invProj;
+ glm::mat4 view;
+ glm::uvec2 viewportSize;
+ glm::uint32 paddingFA = 0xFAAFFAFA;
+ glm::uint32 paddingFB = 0xFBFBFBFB;
+ glm::vec4 ssaoKernels[64];
+ glm::float32 globalTime;
+ glm::float32 dayTime;
+ glm::float32 gamma;
+ glm::uint32 paddingF0 = 0xF0F0F0F0;
+ glm::uint32 paddingF1 = 0xF1F1F1F1;
+ glm::uint32 paddingF2 = 0xF2F2F2F2;
+};
+
+std::shared_ptr<Gal::Shader> LoadVertexShader(std::string_view assetPath);
+
+std::shared_ptr<Gal::Shader> LoadPixelShader(std::string_view assetPath);
+
+class TextureFbCopy {
+ std::shared_ptr<Gal::Framebuffer> framebuffer;
+ std::shared_ptr<Gal::Buffer> fbBuffer;
+ std::shared_ptr<Gal::Pipeline> pipeline;
+ std::shared_ptr<Gal::PipelineInstance> pipelineInstance;
+public:
+
+ TextureFbCopy(
+ std::shared_ptr<Gal::Texture> inputTexture,
+ std::shared_ptr<Gal::Texture> outputTexture,
+ std::shared_ptr<Gal::Shader> copyShader = nullptr);
+
+ TextureFbCopy(
+ std::shared_ptr<Gal::Texture> inputTexture,
+ std::shared_ptr<Gal::Framebuffer> outputFb,
+ std::shared_ptr<Gal::Shader> copyShader = nullptr);
+
+ void Clear() {
+ framebuffer->Clear();
+ }
+
+ void Copy() {
+ pipeline->Activate();
+ pipelineInstance->Activate();
+ pipelineInstance->Render(0, 6);
+ }
+};
+
+class PostProcess {
+ std::shared_ptr<Gal::Framebuffer> framebuffer;
+ std::shared_ptr<Gal::Buffer> fbBuffer;
+ std::shared_ptr<Gal::Pipeline> pipeline;
+ std::shared_ptr<Gal::PipelineInstance> pipelineInstance;
+ std::shared_ptr<Gal::Texture> result;
+public:
+
+ PostProcess(
+ std::shared_ptr<Gal::Shader> pixelShader,
+ std::vector<std::pair<std::string_view, std::shared_ptr<Gal::Texture>>> inputTextures,
+ std::vector<std::pair<std::string_view, Gal::Type>> inputParameters,
+ size_t width,
+ size_t height,
+ Gal::Format format,
+ Gal::Filtering filtering);
+
+ void Clear() {
+ framebuffer->Clear();
+ }
+
+ void Render() {
+ pipeline->Activate();
+ pipelineInstance->Activate();
+ pipelineInstance->Render(0, 6);
+ }
+
+ template<typename T>
+ void SetShaderParameter(std::string_view name, T value) {
+ pipeline->SetShaderParameter(name, value);
+ }
+
+ std::shared_ptr<Gal::Texture> GetResultTexture() {
+ return result;
+ }
+};
+
+class Gbuffer {
+ std::shared_ptr<Gal::Texture> ssaoNoise;
+ std::unique_ptr<PostProcess> ssaoPass;
+ std::unique_ptr<PostProcess> ssaoBlurPass;
+ std::unique_ptr<PostProcess> lightingPass;
+ std::shared_ptr<Gal::Texture> depthStencil;
+ std::shared_ptr<Gal::Texture> color; //RGB - color
+ std::shared_ptr<Gal::Texture> normal; //RGB - normal
+ std::shared_ptr<Gal::Texture> light; //R - faceLight, G - skyLight, B - ssaoDepthMask
+ std::shared_ptr<Gal::Framebuffer> geomFramebuffer;
+
+public:
+ Gbuffer(size_t geomW, size_t geomH, size_t lightW, size_t lightH, int ssaoSamples, size_t ssaoW, size_t ssaoH);
+
+ std::shared_ptr<Gal::Framebuffer> GetGeometryTarget() {
+ return geomFramebuffer;
+ }
+
+ std::shared_ptr<Gal::Texture> GetFinalTexture() {
+ return lightingPass->GetResultTexture();
+ }
+
+ void Render() {
+ if (ssaoPass) {
+ ssaoPass->Render();
+ ssaoBlurPass->Render();
+ }
+ lightingPass->Render();
+ }
+
+ void Clear() {
+ geomFramebuffer->Clear();
+ if (ssaoPass) {
+ ssaoPass->Clear();
+ ssaoBlurPass->Clear();
+ }
+ lightingPass->Clear();
+ }
+
+ int GetMaxRenderBuffers() {
+ return 7;
+ }
+
+ void SetRenderBuff(int renderBuff) {
+ lightingPass->SetShaderParameter("renderBuff", renderBuff);
+ }
+};
diff --git a/src/RendererEntity.cpp b/src/RendererEntity.cpp
index 02a5f54..d014bdb 100644
--- a/src/RendererEntity.cpp
+++ b/src/RendererEntity.cpp
@@ -18,5 +18,5 @@ void RendererEntity::Render(std::shared_ptr<Gal::Pipeline> pipeline, const World
model = glm::scale(model, glm::vec3(entity.width, entity.height, entity.width));
pipeline->SetShaderParameter("model", model);
- pipeline->SetShaderParameter("color", entity.renderColor);
+ pipeline->SetShaderParameter("entityColor", entity.renderColor);
}
diff --git a/src/RendererSectionData.cpp b/src/RendererSectionData.cpp
index 2588fd6..761dd14 100644
--- a/src/RendererSectionData.cpp
+++ b/src/RendererSectionData.cpp
@@ -3,6 +3,7 @@
#include <array>
#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/matrix_inverse.hpp>
#include <optick.h>
#include "World.hpp"
@@ -24,12 +25,44 @@ glm::vec2 TransformTextureCoord(glm::vec4 TextureAtlasCoords, glm::vec2 UvCoords
return transformed;
}
-void AddFacesByBlockModel(RendererSectionData &data, const BlockFaces &model, const glm::mat4 &transform, bool visibility[FaceDirection::none], BlockLightness light, BlockLightness skyLight) {
- for (const auto &face : model.faces) {
- glm::vec2 lightness;
- lightness.x = _max(light.face[0], light.face[1], light.face[2], light.face[3], light.face[4], light.face[5]);
- lightness.y = _max(skyLight.face[0], skyLight.face[1], skyLight.face[2], skyLight.face[3], skyLight.face[4], skyLight.face[5]);
- if (face.visibility != FaceDirection::none) {
+//Maps [0.0, 0.5] range to [0.0, 1.0]
+float MapNeg(float x) {
+ float y = x * 2.0f;
+ return glm::clamp(y, 0.0f, 1.0f);
+}
+
+//Maps [0.5, 1.0] range to [0.0, 1.0]
+float MapPos(float x) {
+ float y = (x * 2.0f) - 1.0f;
+ return glm::clamp(y, 0.0f, 1.0f);
+}
+
+float InterpolateBlockLightness(const BlockLightness& light, const glm::vec3 &point) {
+ float xNeg = MapNeg(point.x);
+ float xPos = MapPos(point.x);
+ float xNegLight = glm::mix(light.face[FaceDirection::east], light.self, xNeg);
+ float xPosLight = glm::mix(light.self, light.face[FaceDirection::west], xPos);
+ float xLight = (glm::max)(xNegLight, xPosLight);
+
+ float yNeg = MapNeg(point.y);
+ float yPos = MapPos(point.y);
+ float yNegLight = glm::mix(light.face[FaceDirection::down], light.self, yNeg);
+ float yPosLight = glm::mix(light.self, light.face[FaceDirection::up], yPos);
+ float yLight = (glm::max)(yNegLight, yPosLight);
+
+ float zNeg = MapNeg(point.z);
+ float zPos = MapPos(point.z);
+ float zNegLight = glm::mix(light.face[FaceDirection::south], light.self, zNeg);
+ float zPosLight = glm::mix(light.self, light.face[FaceDirection::north], zPos);
+ float zLight = (glm::max)(zNegLight, zPosLight);
+
+ return (glm::max)(xLight, (glm::max)(yLight, zLight));
+}
+
+void AddFacesByBlockModel(RendererSectionData& data, const BlockFaces& model, const glm::mat4& transform, bool visibility[FaceDirection::none], const Vector &pos, const SectionsData &sections, bool smoothLighting) {
+ glm::vec3 absPos = (sections.data[1][1][1].GetPosition() * 16).glm();
+ for (const auto& face : model.faces) {
+ if (face.visibility != FaceDirection::none) {
FaceDirection direction = face.visibility;
Vector directionVec = model.faceDirectionVector[direction];
FaceDirection faceDirection = FaceDirection::none;
@@ -44,7 +77,6 @@ void AddFacesByBlockModel(RendererSectionData &data, const BlockFaces &model, co
if (visibility[faceDirection])
continue;
- lightness = glm::vec2(light.face[faceDirection], skyLight.face[faceDirection]);
}
data.vertices.emplace_back();
@@ -56,16 +88,47 @@ void AddFacesByBlockModel(RendererSectionData &data, const BlockFaces &model, co
vertexData.positions[2] = transformed * glm::vec4(1, 0, 1, 1);
vertexData.positions[3] = transformed * glm::vec4(1, 0, 0, 1);
+ glm::vec3 normal = glm::cross(vertexData.positions[1] - vertexData.positions[0], vertexData.positions[3] - vertexData.positions[0]);
+ vertexData.normal = glm::normalize(normal);
+
vertexData.uvs[0] = TransformTextureCoord(face.texture, glm::vec2(0, 0), face.frames);
vertexData.uvs[1] = TransformTextureCoord(face.texture, glm::vec2(1, 0), face.frames);
vertexData.uvs[2] = TransformTextureCoord(face.texture, glm::vec2(1, 1), face.frames);
vertexData.uvs[3] = TransformTextureCoord(face.texture, glm::vec2(0, 1), face.frames);
- vertexData.uvLayers = face.layer;
- vertexData.animations = face.frames;
+ vertexData.layerAnimationAo.r = face.layer;
+ vertexData.layerAnimationAo.g = face.frames;
vertexData.colors = face.color;
- vertexData.lights = lightness;
- }
+
+ if (smoothLighting) {
+ for (size_t i = 0; i < 4; i++) {
+ glm::vec3 baseLightPos = vertexData.positions[i] - absPos;
+ glm::vec3 lightPos = baseLightPos + 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));
+ vertexData.lights[i].x = InterpolateBlockLightness(light, lightPos - glm::vec3(basePos));
+ vertexData.lights[i].y = InterpolateBlockLightness(skyLight, lightPos - glm::vec3(basePos));
+ }
+ } else {
+ BlockLightness light = sections.GetLight(pos);
+ BlockLightness skyLight = sections.GetSkyLight(pos);
+ glm::vec2 lightness;
+
+ lightness.x = face.visibility != FaceDirection::none ? light.face[face.visibility] : light.self;
+ lightness.x = (glm::max)(lightness.x, static_cast<float>(light.self));
+
+ lightness.y = face.visibility != FaceDirection::none ? skyLight.face[face.visibility] : skyLight.self;
+ lightness.y = (glm::max)(lightness.y, static_cast<float>(skyLight.self));
+
+ vertexData.lights[0] = lightness;
+ vertexData.lights[1] = lightness;
+ vertexData.lights[2] = lightness;
+ vertexData.lights[3] = lightness;
+ }
+
+ vertexData.layerAnimationAo.b = model.ambientOcclusion ? 1.0f : 0.0f;
+ }
}
BlockFaces *GetInternalBlockModel(const BlockId& id, std::vector<std::pair<BlockId, BlockFaces*>> &idModels) {
@@ -117,14 +180,14 @@ std::array<BlockId, 4096> SetBlockIdData(const SectionsData &sections) {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
- blockIdData[y * 256 + z * 16 + x] = sections.section.GetBlockId(Vector(x, y, z));
+ blockIdData[y * 256 + z * 16 + x] = sections.data[1][1][1].GetBlockId(Vector(x, y, z));
}
}
}
return blockIdData;
}
-RendererSectionData ParseSection(const SectionsData &sections) {
+RendererSectionData ParseSection(const SectionsData &sections, bool smoothLighting) {
OPTICK_EVENT();
RendererSectionData data;
@@ -133,10 +196,10 @@ RendererSectionData ParseSection(const SectionsData &sections) {
std::array<bool[FaceDirection::none], 4096> blockVisibility = GetBlockVisibilityData(sections, blockIdData, idModels);
std::string textureName;
- data.hash = sections.section.GetHash();
- data.sectionPos = sections.section.GetPosition();
+ data.hash = sections.data[1][1][1].GetHash();
+ data.sectionPos = sections.data[1][1][1].GetPosition();
- glm::mat4 baseOffset = glm::translate(glm::mat4(1.0), (sections.section.GetPosition() * 16).glm()), transform;
+ glm::mat4 baseOffset = glm::translate(glm::mat4(1.0), (sections.data[1][1][1].GetPosition() * 16).glm()), transform;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
@@ -149,11 +212,8 @@ RendererSectionData ParseSection(const SectionsData &sections) {
transform = glm::translate(baseOffset, vec.glm());
- BlockLightness light = sections.GetLight(vec);
- BlockLightness skyLight = sections.GetSkyLight(vec);
-
BlockFaces *model = GetInternalBlockModel(block, idModels);
- AddFacesByBlockModel(data, *model, transform, blockVisibility[y * 256 + z * 16 + x], light, skyLight);
+ AddFacesByBlockModel(data, *model, transform, blockVisibility[y * 256 + z * 16 + x], vec, sections, smoothLighting);
}
}
}
@@ -163,127 +223,34 @@ RendererSectionData ParseSection(const SectionsData &sections) {
}
BlockId SectionsData::GetBlockId(const Vector &pos) const {
- if (pos.x < 0)
- return east.GetBlockId(Vector(15, pos.y, pos.z));
-
- if (pos.x > 15)
- return west.GetBlockId(Vector(0, pos.y, pos.z));
-
- if (pos.y < 0)
- return bottom.GetBlockId(Vector(pos.x, 15, pos.z));
-
- if (pos.y > 15)
- return top.GetBlockId(Vector(pos.x, 0, pos.z));
-
- if (pos.z < 0)
- return south.GetBlockId(Vector(pos.x, pos.y, 15));
-
- if (pos.z > 15)
- return north.GetBlockId(Vector(pos.x, pos.y, 0));
-
- return section.GetBlockId(pos);
+ Vector sectionPos = pos;
+ return GetSection(sectionPos).GetBlockId(sectionPos);
}
-BlockLightness SectionsData::GetLight(const Vector &pos) const {
- BlockLightness lightness;
- static const Vector directions[] = {
- Vector(1,0,0),
- Vector(-1,0,0),
- Vector(0,1,0),
- Vector(0,-1,0),
- Vector(0,0,1),
- Vector(0,0,-1),
- };
-
- unsigned char self = section.GetBlockLight(pos);
-
- for (const Vector &dir : directions) {
- Vector vec = pos + dir;
- unsigned char dirValue = 0;
-
- if (vec.x < 0 || vec.x > 15 || vec.y < 0 || vec.y > 15 || vec.z < 0 || vec.z > 15) {
- if (vec.x < 0)
- dirValue = east.GetBlockLight(Vector(15, vec.y, vec.z));
- if (vec.x > 15)
- dirValue = west.GetBlockLight(Vector(0, vec.y, vec.z));
- if (vec.y < 0)
- dirValue = bottom.GetBlockLight(Vector(vec.x, 15, vec.z));
- if (vec.y > 15)
- dirValue = top.GetBlockLight(Vector(vec.x, 0, vec.z));
- if (vec.z < 0)
- dirValue = south.GetBlockLight(Vector(vec.x, vec.y, 15));
- if (vec.z > 15)
- dirValue = north.GetBlockLight(Vector(vec.x, vec.y, 0));
- }
- else
- dirValue = section.GetBlockLight(vec);
-
- dirValue = _max(self, dirValue);
-
- if (dir == directions[0])
- lightness.face[FaceDirection::east] = dirValue;
- if (dir == directions[1])
- lightness.face[FaceDirection::west] = dirValue;
- if (dir == directions[2])
- lightness.face[FaceDirection::up] = dirValue;
- if (dir == directions[3])
- lightness.face[FaceDirection::down] = dirValue;
- if (dir == directions[4])
- lightness.face[FaceDirection::south] = dirValue;
- if (dir == directions[5])
- lightness.face[FaceDirection::north] = dirValue;
- }
- return lightness;
+BlockLightness SectionsData::GetLight(const Vector& pos) const {
+ BlockLightness lightness;
+ for (size_t i = 0; i <= FaceDirection::none; i++) {
+ Vector vec = pos + FaceDirectionVector[i];
+ uint8_t dirValue = GetSection(vec).GetBlockLight(vec);
+
+ if (i == FaceDirection::none)
+ lightness.self = dirValue;
+ else
+ lightness.face[i] = dirValue;
+ }
+ return lightness;
}
BlockLightness SectionsData::GetSkyLight(const Vector &pos) const {
- BlockLightness lightness;
- static const Vector directions[] = {
- Vector(1,0,0),
- Vector(-1,0,0),
- Vector(0,1,0),
- Vector(0,-1,0),
- Vector(0,0,1),
- Vector(0,0,-1),
- };
-
- unsigned char self = section.GetBlockSkyLight(pos);
-
- for (const Vector &dir : directions) {
- Vector vec = pos + dir;
- unsigned char dirValue = 0;
-
- if (vec.x < 0 || vec.x > 15 || vec.y < 0 || vec.y > 15 || vec.z < 0 || vec.z > 15) {
- if (vec.x < 0)
- dirValue = east.GetBlockSkyLight(Vector(15, vec.y, vec.z));
- if (vec.x > 15)
- dirValue = west.GetBlockSkyLight(Vector(0, vec.y, vec.z));
- if (vec.y < 0)
- dirValue = bottom.GetBlockSkyLight(Vector(vec.x, 15, vec.z));
- if (vec.y > 15)
- dirValue = top.GetBlockSkyLight(Vector(vec.x, 0, vec.z));
- if (vec.z < 0)
- dirValue = south.GetBlockSkyLight(Vector(vec.x, vec.y, 15));
- if (vec.z > 15)
- dirValue = north.GetBlockSkyLight(Vector(vec.x, vec.y, 0));
- }
- else
- dirValue = section.GetBlockSkyLight(vec);
-
- dirValue = _max(self, dirValue);
-
- if (dir == directions[0])
- lightness.face[FaceDirection::east] = dirValue;
- if (dir == directions[1])
- lightness.face[FaceDirection::west] = dirValue;
- if (dir == directions[2])
- lightness.face[FaceDirection::up] = dirValue;
- if (dir == directions[3])
- lightness.face[FaceDirection::down] = dirValue;
- if (dir == directions[4])
- lightness.face[FaceDirection::south] = dirValue;
- if (dir == directions[5])
- lightness.face[FaceDirection::north] = dirValue;
- }
- return lightness;
+ BlockLightness lightness;
+ for (size_t i = 0; i <= FaceDirection::none; i++) {
+ Vector vec = pos + FaceDirectionVector[i];
+ uint8_t dirValue = GetSection(vec).GetBlockSkyLight(vec);
+
+ if (i == FaceDirection::none)
+ lightness.self = dirValue;
+ else
+ lightness.face[i] = dirValue;
+ }
+ return lightness;
}
diff --git a/src/RendererSectionData.hpp b/src/RendererSectionData.hpp
index edd2992..0f9ade6 100644
--- a/src/RendererSectionData.hpp
+++ b/src/RendererSectionData.hpp
@@ -11,17 +11,45 @@
class World;
struct BlockLightness {
- unsigned char face[FaceDirection::none] = { 0,0,0,0,0,0 };
+ uint8_t face[FaceDirection::none + 1] = { 0,0,0,0,0,0 };
+ uint8_t self = 0;
};
struct SectionsData {
- Section section;
- Section west;
- Section east;
- Section top;
- Section bottom;
- Section north;
- Section south;
+ Section data[3][3][3];
+
+ const Section& GetSection(Vector& pos) const {
+ size_t x = 1, y = 1, z = 1;
+ while (true) {
+ if (pos.x < 0) {
+ x--;
+ pos.x += 16;
+ }
+ else if (pos.x > 15) {
+ x++;
+ pos.x -= 16;
+ }
+ else if (pos.y < 0) {
+ y--;
+ pos.y += 16;
+ }
+ else if (pos.y > 15) {
+ y++;
+ pos.y -= 16;
+ }
+ else if (pos.z < 0) {
+ z--;
+ pos.z += 16;
+ }
+ else if (pos.z > 15) {
+ z++;
+ pos.z -= 16;
+ }
+ else
+ break;
+ }
+ return data[x][y][z];
+ }
BlockId GetBlockId(const Vector &pos) const;
@@ -31,20 +59,19 @@ struct SectionsData {
};
struct VertexData {
- glm::vec3 positions[4];
- glm::vec2 uvs[4];
- float uvLayers;
- float animations;
- glm::vec3 colors;
- glm::vec2 lights;
- uint8_t padding[20];
+ glm::vec3 positions[4];
+ glm::vec2 uvs[4];
+ glm::vec2 lights[4];
+ glm::vec3 normal;
+ glm::vec3 colors;
+ glm::vec3 layerAnimationAo; //R - uvLayer, G - animation, B - ambientOcclusion
};
struct RendererSectionData {
- std::vector<VertexData> vertices;
+ std::vector<VertexData> vertices;
size_t hash = 0;
Vector sectionPos;
- bool forced = false;
+ bool forced = false;
};
-RendererSectionData ParseSection(const SectionsData &sections); \ No newline at end of file
+RendererSectionData ParseSection(const SectionsData &sections, bool smoothLighting);
diff --git a/src/RendererWorld.cpp b/src/RendererWorld.cpp
index cb4551f..af177d7 100644
--- a/src/RendererWorld.cpp
+++ b/src/RendererWorld.cpp
@@ -2,6 +2,7 @@
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/norm.hpp>
#include <optick.h>
#include "DebugInfo.hpp"
@@ -12,6 +13,7 @@
#include "Section.hpp"
#include "RendererSectionData.hpp"
#include "Game.hpp"
+#include "RenderConfigs.hpp"
void RendererWorld::WorkerFunction(size_t workerId) {
OPTICK_THREAD("Worker");
@@ -24,7 +26,7 @@ void RendererWorld::WorkerFunction(size_t workerId) {
return;
size_t id = std::get<1>(data);
bool forced = std::get<2>(data);
- parsing[id].renderer = ParseSection(parsing[id].data);
+ parsing[id].renderer = ParseSection(parsing[id].data, smoothLighting);
parsing[id].renderer.forced = forced;
PUSH_EVENT("SectionParsed", id);
});
@@ -55,13 +57,13 @@ void RendererWorld::ParseQueueUpdate() {
vec.y -= 4500;
}
- parsing[id].data.section = GetGameState()->GetWorld().GetSection(vec);
- parsing[id].data.north = GetGameState()->GetWorld().GetSection(vec + Vector(0, 0, 1));
- parsing[id].data.south = GetGameState()->GetWorld().GetSection(vec + Vector(0, 0, -1));
- parsing[id].data.west = GetGameState()->GetWorld().GetSection(vec + Vector(1, 0, 0));
- parsing[id].data.east = GetGameState()->GetWorld().GetSection(vec + Vector(-1, 0, 0));
- parsing[id].data.bottom = GetGameState()->GetWorld().GetSection(vec + Vector(0, -1, 0));
- parsing[id].data.top = GetGameState()->GetWorld().GetSection(vec + Vector(0, 1, 0));
+ for (int x = -1; x < 2; x++) {
+ for (int y = -1; y < 2; y++) {
+ for (int z = -1; z < 2; z++) {
+ parsing[id].data.data[x + 1][y + 1][z + 1] = GetGameState()->GetWorld().GetSection(vec + Vector(x, y, z));
+ }
+ }
+ }
parsing[id].parsing = true;
@@ -95,7 +97,7 @@ void RendererWorld::ParseQeueueRemoveUnnecessary() {
bool skip = false;
for (int i = 0; i < RendererWorld::parsingBufferSize; i++) {
- if (parsing[i].data.section.GetHash() == section.GetHash()) {
+ if (parsing[i].data.data[1][1][1].GetHash() == section.GetHash()) {
skip = true;
break;
}
@@ -151,8 +153,9 @@ void RendererWorld::UpdateAllSections(VectorF playerPos) {
}
}
-RendererWorld::RendererWorld(std::shared_ptr<Gal::Framebuffer> target) {
- OPTICK_EVENT();
+RendererWorld::RendererWorld(std::shared_ptr<Gal::Framebuffer> target, bool defferedShading, bool smoothLighting) {
+ OPTICK_EVENT();
+ this->smoothLighting = smoothLighting;
MaxRenderingDistance = 2;
numOfWorkers = _max(1, (signed int) std::thread::hardware_concurrency() - 2);
@@ -160,7 +163,7 @@ RendererWorld::RendererWorld(std::shared_ptr<Gal::Framebuffer> target) {
globalTimeStart = std::chrono::high_resolution_clock::now();
- PrepareRender(target);
+ PrepareRender(target, defferedShading);
listener->RegisterHandler("DeleteSectionRender", [this](const Event& eventData) {
OPTICK_EVENT("EV_DeleteSectionRender");
@@ -255,11 +258,6 @@ RendererWorld::RendererWorld(std::shared_ptr<Gal::Framebuffer> target) {
sections.erase(it);
});
- listener->RegisterHandler("SetMinLightLevel", [this](const Event& eventData) {
- auto value = eventData.get<float>();
- sectionsPipeline->SetShaderParameter("MinLightLevel", value);
- });
-
for (int i = 0; i < numOfWorkers; i++)
workers.push_back(std::thread(&RendererWorld::WorkerFunction, this, i));
@@ -282,18 +280,26 @@ RendererWorld::~RendererWorld() {
void RendererWorld::Render(float screenRatio) {
OPTICK_EVENT();
//Common
- glm::mat4 projection = glm::perspective(
+
+ auto globalSpb = Gal::GetImplementation()->GetGlobalShaderParameters();
+
+ auto& projection = globalSpb->Get<GlobalShaderParameters>()->proj;
+ projection = glm::perspective(
glm::radians(70.0f), screenRatio,
0.1f, 10000000.0f
);
- glm::mat4 view = GetGameState()->GetViewMatrix();
- glm::mat4 projView = projection * view;
+
+ globalSpb->Get<GlobalShaderParameters>()->invProj = glm::inverse(projection);
+
+ auto& view = globalSpb->Get<GlobalShaderParameters>()->view;
+ view = GetGameState()->GetViewMatrix();
+
+ auto& projView = globalSpb->Get<GlobalShaderParameters>()->projView;
+ projView = projection * view;
//Render Entities
constexpr size_t entitiesVerticesCount = 240;
entitiesPipeline->Activate();
- entitiesPipeline->SetShaderParameter("projView", projView);
-
entitiesPipelineInstance->Activate();
for (auto& it : entities) {
it.Render(entitiesPipeline, &GetGameState()->GetWorld());
@@ -309,7 +315,7 @@ void RendererWorld::Render(float screenRatio) {
model = glm::translate(model,glm::vec3(0.5f,0.5f,0.5f));
model = glm::scale(model,glm::vec3(1.01f,1.01f,1.01f));
entitiesPipeline->SetShaderParameter("model", model);
- entitiesPipeline->SetShaderParameter("color", glm::vec3(0, 0, 0));
+ entitiesPipeline->SetShaderParameter("entityColor", glm::vec3(0, 0, 0));
entitiesPipelineInstance->Render(0, entitiesVerticesCount);
}
}
@@ -325,14 +331,50 @@ void RendererWorld::Render(float screenRatio) {
//entityShader->SetUniform("model", model);
entitiesPipeline->SetShaderParameter("model", model);
if (selectedBlock == Vector())
- entitiesPipeline->SetShaderParameter("color", glm::vec3(0.7f, 0.0f, 0.0f));
+ entitiesPipeline->SetShaderParameter("entityColor", glm::vec3(0.7f, 0.0f, 0.0f));
else
- entitiesPipeline->SetShaderParameter("color", glm::vec3(0.0f, 0.0f, 0.7f));
+ entitiesPipeline->SetShaderParameter("entityColor", glm::vec3(0.0f, 0.0f, 0.7f));
entitiesPipelineInstance->Render(0, entitiesVerticesCount);
}
}
- //Render sky
+ //Render sections
+ 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();
+ size_t culledSections = sections.size();
+ unsigned int renderedFaces = 0;
+ for (auto& section : sections) {
+ glm::vec3 point{
+ section.second.GetPosition().x * 16 + 8,
+ section.second.GetPosition().y * 16 + 8,
+ section.second.GetPosition().z * 16 + 8
+ };
+
+ bool isVisible = frustum.TestSphere(point, 16.0f);
+
+ if (!isVisible) {
+ culledSections--;
+ continue;
+ }
+ renderList.push_back(section.first);
+ renderedFaces += section.second.numOfFaces;
+ }
+ 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);
+ });
+ for (const auto& renderPos : renderList) {
+ sections.at(renderPos).Render();
+ }
+ DebugInfo::culledSections = culledSections;
+ DebugInfo::renderFaces = renderedFaces;
+
+ //Render sky
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, GetGameState()->GetPlayer()->pos.glm());
const float scale = 1000000.0f;
@@ -367,52 +409,22 @@ void RendererWorld::Render(float screenRatio) {
mixLevel = 1.0 - (timePassed / moonriseLength);
}
+ globalSpb->Get<GlobalShaderParameters>()->dayTime = mixLevel;
+
skyPipeline->Activate();
- skyPipeline->SetShaderParameter("projView", projView);
skyPipeline->SetShaderParameter("model", model);
- skyPipeline->SetShaderParameter("DayTime", mixLevel);
skyPipelineInstance->Activate();
skyPipelineInstance->Render(0, 36);
-
-
- //Render sections
- auto rawGlobalTime = (std::chrono::high_resolution_clock::now() - globalTimeStart);
- float globalTime = rawGlobalTime.count() / 1000000000.0f;
- sectionsPipeline->Activate();
- sectionsPipeline->SetShaderParameter("DayTime", mixLevel);
- sectionsPipeline->SetShaderParameter("projView", projView);
-
- Frustum frustum(projView);
-
- size_t culledSections = sections.size();
- unsigned int renderedFaces = 0;
- for (auto& section : sections) {
- glm::vec3 point{
- section.second.GetPosition().x * 16 + 8,
- section.second.GetPosition().y * 16 + 8,
- section.second.GetPosition().z * 16 + 8
- };
-
- bool isVisible = frustum.TestSphere(point, 16.0f);
-
- if (!isVisible) {
- culledSections--;
- continue;
- }
- section.second.Render();
- renderedFaces += section.second.numOfFaces;
- }
- DebugInfo::culledSections = culledSections;
- DebugInfo::renderFaces = renderedFaces;
}
-void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target) {
+void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target, bool defferedShading) {
std::string sectionVertexSource, sectionPixelSource;
{
auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/face");
sectionVertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
- auto pixelAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/face");
+ 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());
}
@@ -421,7 +433,8 @@ void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target) {
auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/entity");
entitiesVertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
- auto pixelAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/entity");
+ auto pixelAsset = defferedShading ? AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/entity") :
+ AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/fwd_entity");
entitiesPixelSource = std::string((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size());
}
@@ -430,7 +443,8 @@ void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target) {
auto vertAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/vert/sky");
skyVertexSource = std::string((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size());
- auto pixelAsset = AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/sky");
+ auto pixelAsset = defferedShading ? AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/sky") :
+ AssetManager::GetAssetByAssetName("/altcraft/shaders/frag/fwd_sky");
skyPixelSource = std::string((char*)pixelAsset->data.data(), (char*)pixelAsset->data.data() + pixelAsset->data.size());
}
@@ -438,38 +452,31 @@ void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target) {
{
auto sectionsPLC = gal->CreatePipelineConfig();
sectionsPLC->SetTarget(target);
- sectionsPLC->AddShaderParameter("projView", Gal::Type::Mat4);
- sectionsPLC->AddShaderParameter("DayTime", Gal::Type::Float);
- sectionsPLC->AddShaderParameter("GlobalTime", Gal::Type::Float);
- sectionsPLC->AddShaderParameter("MinLightLevel", Gal::Type::Float);
sectionsPLC->AddStaticTexture("textureAtlas", AssetManager::GetTextureAtlas());
sectionsPLC->SetVertexShader(gal->LoadVertexShader(sectionVertexSource));
sectionsPLC->SetPixelShader(gal->LoadPixelShader(sectionPixelSource));
sectionsPLC->SetPrimitive(Gal::Primitive::TriangleFan);
sectionsBufferBinding = sectionsPLC->BindVertexBuffer({
- {"position", Gal::Type::Vec3, 4, 1},
+ {"pos", Gal::Type::Vec3, 4, 1},
{"uv", Gal::Type::Vec2, 4, 1},
- {"uvLayer", Gal::Type::Float, 1, 1},
- {"animation", Gal::Type::Float, 1, 1},
+ {"light", Gal::Type::Vec2, 4, 1},
+ {"normal", Gal::Type::Vec3, 1, 1},
{"color", Gal::Type::Vec3, 1, 1},
- {"light", Gal::Type::Vec2, 1, 1},
- {"", Gal::Type::Uint8, 20, 1}
+ {"layerAnimationAo", Gal::Type::Vec3, 1, 1},
});
sectionsPipeline = gal->BuildPipeline(sectionsPLC);
- sectionsPipeline->SetShaderParameter("MinLightLevel", 0.2f);
}
{
auto entitiesPLC = gal->CreatePipelineConfig();
entitiesPLC->SetTarget(target);
- entitiesPLC->AddShaderParameter("projView", Gal::Type::Mat4);
entitiesPLC->AddShaderParameter("model", Gal::Type::Mat4);
- entitiesPLC->AddShaderParameter("color", Gal::Type::Vec3);
+ entitiesPLC->AddShaderParameter("entityColor", Gal::Type::Vec3);
entitiesPLC->SetVertexShader(gal->LoadVertexShader(entitiesVertexSource));
entitiesPLC->SetPixelShader(gal->LoadPixelShader(entitiesPixelSource));
entitiesPLC->SetPrimitive(Gal::Primitive::Triangle);
auto entitiesPosBB = entitiesPLC->BindVertexBuffer({
- {"position", Gal::Type::Vec3},
+ {"pos", Gal::Type::Vec3},
});
auto entitiesIndicesBB = entitiesPLC->BindIndexBuffer();
@@ -630,14 +637,12 @@ void RendererWorld::PrepareRender(std::shared_ptr<Gal::Framebuffer> target) {
skyPPC->AddShaderParameter("sunTextureLayer", Gal::Type::Float);
skyPPC->AddShaderParameter("moonTexture", Gal::Type::Vec4);
skyPPC->AddShaderParameter("moonTextureLayer", Gal::Type::Float);
- skyPPC->AddShaderParameter("DayTime", Gal::Type::Float);
- skyPPC->AddShaderParameter("projView", Gal::Type::Mat4);
skyPPC->AddShaderParameter("model", Gal::Type::Mat4);
skyPPC->AddStaticTexture("textureAtlas", AssetManager::GetTextureAtlas());
skyPPC->SetVertexShader(gal->LoadVertexShader(skyVertexSource));
skyPPC->SetPixelShader(gal->LoadPixelShader(skyPixelSource));
auto skyPosUvBB = skyPPC->BindVertexBuffer({
- {"position", Gal::Type::Vec3},
+ {"pos", Gal::Type::Vec3},
{"", Gal::Type::Vec2},
});
diff --git a/src/RendererWorld.hpp b/src/RendererWorld.hpp
index e645b30..438c022 100644
--- a/src/RendererWorld.hpp
+++ b/src/RendererWorld.hpp
@@ -55,14 +55,15 @@ class RendererWorld {
std::shared_ptr<Gal::PipelineInstance> skyPipelineInstance;
std::shared_ptr<Gal::Buffer> skyBuffer;
public:
- RendererWorld(std::shared_ptr<Gal::Framebuffer> target);
+ RendererWorld(std::shared_ptr<Gal::Framebuffer> target, bool defferedShading, bool smoothLighting);
~RendererWorld();
void Render(float screenRatio);
- void PrepareRender(std::shared_ptr<Gal::Framebuffer> target);
+ void PrepareRender(std::shared_ptr<Gal::Framebuffer> target, bool defferedShading);
double MaxRenderingDistance;
void Update(double timeToUpdate);
+ bool smoothLighting;
};
diff --git a/src/Rml.cpp b/src/Rml.cpp
index fa2d4e7..f6fff44 100644
--- a/src/Rml.cpp
+++ b/src/Rml.cpp
@@ -64,15 +64,15 @@ RmlRenderInterface::RmlRenderInterface() {
{
auto pipelineConfig = gal->CreatePipelineConfig();
- pipelineConfig->AddShaderParameter("viewportSize", Gal::Type::Vec2u32);
pipelineConfig->AddShaderParameter("translation", Gal::Type::Vec2);
pipelineConfig->SetTarget(gal->GetDefaultFramebuffer());
pipelineConfig->SetVertexShader(gal->LoadVertexShader(vertexSource));
pipelineConfig->SetPixelShader(gal->LoadPixelShader(pixelSource));
+ pipelineConfig->SetBlending(Gal::Blending::Additive);
auto vertBuffBind = pipelineConfig->BindVertexBuffer({
{"pos", Gal::Type::Vec2},
- {"color", Gal::Type::Vec4u8},
+ {"col", Gal::Type::Vec4u8},
{"", Gal::Type::Vec2}, //it's not used in shader, so driver optimizes it away
});
@@ -88,17 +88,17 @@ RmlRenderInterface::RmlRenderInterface() {
{
auto texPipelineConfig = gal->CreatePipelineConfig();
- texPipelineConfig->AddShaderParameter("viewportSize", Gal::Type::Vec2u32);
texPipelineConfig->AddShaderParameter("translation", Gal::Type::Vec2);
texPipelineConfig->AddShaderParameter("fontTexture", Gal::Type::Int32);
texPipelineConfig->SetTarget(gal->GetDefaultFramebuffer());
texPipelineConfig->SetVertexShader(gal->LoadVertexShader(vertexSource));
texPipelineConfig->SetPixelShader(gal->LoadPixelShader(texPixelSource));
+ texPipelineConfig->SetBlending(Gal::Blending::Additive);
auto texVertBuffBind = texPipelineConfig->BindVertexBuffer({
{"pos", Gal::Type::Vec2},
- {"color", Gal::Type::Vec4u8},
- {"tex_coord", Gal::Type::Vec2},
+ {"col", Gal::Type::Vec4u8},
+ {"uvPos", Gal::Type::Vec2},
});
auto texIndexBuffBind = texPipelineConfig->BindIndexBuffer();
@@ -165,9 +165,6 @@ void RmlRenderInterface::ReleaseTexture(Rml::TextureHandle texture) {
}
void RmlRenderInterface::Update(unsigned int windowWidth, unsigned int windowHeight) {
- pipeline->SetShaderParameter("viewportSize", glm::uvec2(windowWidth, windowHeight));
- texPipeline->SetShaderParameter("viewportSize", glm::uvec2(windowWidth, windowHeight));
-
vpWidth = windowWidth;
vpHeight = windowHeight;
}
diff --git a/src/TextureAtlas.cpp b/src/TextureAtlas.cpp
index 7e44a86..9ad018e 100644
--- a/src/TextureAtlas.cpp
+++ b/src/TextureAtlas.cpp
@@ -89,6 +89,7 @@ TextureAtlas::TextureAtlas(std::vector<TextureData> &textures) {
texConfig->SetWrapping(Gal::Wrapping::Clamp);
texConfig->SetMinFilter(Gal::Filtering::Nearest);
texConfig->SetMaxFilter(Gal::Filtering::Nearest);
+ texConfig->SetLinear(false);
texture = gal->BuildTexture(texConfig);