From 450b4d65d613dcedec63327d21e23a75ea9e8f3b Mon Sep 17 00:00:00 2001 From: Mikulas Florek Date: Sun, 21 Dec 2014 21:13:00 +0100 Subject: [PATCH] matching mesh's vertex format with shader's vertex format - closes #390 --- src/graphics/geometry.cpp | 229 ++++++++++++++++++---------------- src/graphics/geometry.h | 33 +++-- src/graphics/model.cpp | 14 +-- src/graphics/model_manager.h | 12 +- src/graphics/pipeline.cpp | 10 +- src/graphics/pipeline.h | 5 +- src/graphics/render_scene.cpp | 7 +- src/graphics/renderer.cpp | 22 +++- src/graphics/renderer.h | 1 + src/graphics/shader.cpp | 3 +- src/graphics/terrain.cpp | 6 +- src/graphics/terrain.h | 3 +- 12 files changed, 201 insertions(+), 144 deletions(-) diff --git a/src/graphics/geometry.cpp b/src/graphics/geometry.cpp index cdd201ae1..5688cc8a1 100644 --- a/src/graphics/geometry.cpp +++ b/src/graphics/geometry.cpp @@ -1,92 +1,89 @@ #include "graphics/geometry.h" +#include "core/fs/ifile.h" +#include "core/log.h" #include "core/math_utils.h" #include "core/profiler.h" #include "graphics/gl_ext.h" +#include "graphics/renderer.h" #include "graphics/shader.h" namespace Lumix { -void VertexDef::parse(const char* data, int size) +void VertexDef::addAttribute(Renderer& renderer, const char* name, VertexAttributeDef type) { + m_attributes[m_attribute_count].m_name_index = renderer.getAttributeNameIndex(name); + m_attributes[m_attribute_count].m_type = type; +} + + +bool VertexDef::parse(Renderer& renderer, FS::IFile* file) +{ + uint32_t attribute_count; + file->read(&attribute_count, sizeof(attribute_count)); + m_vertex_size = 0; - int index = 0; - for(int i = 0; i < size; ++i) + for (uint32_t i = 0; i < attribute_count; ++i) { - ASSERT(index < 15); - switch(data[i]) + char tmp[50]; + uint32_t len; + file->read(&len, sizeof(len)); + if (len > sizeof(tmp) - 1) { - case 'f': - ++i; - if (data[i] == '4') - { - m_attributes[index] = VertexAttributeDef::FLOAT4; - m_vertex_size += 4 * sizeof(float); - } - else if (data[i] == '2') - { - m_attributes[index] = VertexAttributeDef::FLOAT2; - m_vertex_size += 2 * sizeof(float); - } - else - { - ASSERT(false); - } + return false; + } + file->read(tmp, len); + tmp[len] = '\0'; + + m_attributes[i].m_name_index = renderer.getAttributeNameIndex(tmp); + + file->read(&m_attributes[i].m_type, sizeof(m_attributes[i].m_type)); + + switch (m_attributes[i].m_type) + { + case VertexAttributeDef::FLOAT4: + m_vertex_size += 4 * sizeof(GLfloat); break; - case 'i': - ++i; - if (data[i] == '4') - { - m_attributes[index] = VertexAttributeDef::INT4; - m_vertex_size += 4 * sizeof(int); - } - else if (data[i] == '1') - { - m_attributes[index] = VertexAttributeDef::INT1; - m_vertex_size += sizeof(int); - } - else - { - ASSERT(false); - } + case VertexAttributeDef::POSITION: + case VertexAttributeDef::FLOAT3: + m_vertex_size += 3 * sizeof(GLfloat); break; - case 'p': - m_attributes[index] = VertexAttributeDef::POSITION; - m_vertex_size += 3 * sizeof(float); + case VertexAttributeDef::FLOAT2: + m_vertex_size += 2 * sizeof(GLfloat); break; - case 'b': - ++i; - if (data[i] == '4') - { - m_attributes[index] = VertexAttributeDef::BYTE4; - m_vertex_size += 4 * sizeof(char); - } - else - { - ASSERT(false); - } + case VertexAttributeDef::FLOAT1: + m_vertex_size += 1 * sizeof(GLfloat); break; - case 's': - ++i; - if (data[i] == '2') - { - m_attributes[index] = VertexAttributeDef::SHORT2; - m_vertex_size += 2 * sizeof(short); - } - else - { - ASSERT(false); - } + case VertexAttributeDef::INT4: + m_vertex_size += 4 * sizeof(GLint); + break; + case VertexAttributeDef::INT3: + m_vertex_size += 3 * sizeof(GLint); + break; + case VertexAttributeDef::INT2: + m_vertex_size += 2 * sizeof(GLint); + break; + case VertexAttributeDef::INT1: + m_vertex_size += sizeof(GLint); + break; + case VertexAttributeDef::BYTE4: + m_vertex_size += 4 * sizeof(GLbyte); + break; + case VertexAttributeDef::SHORT4: + m_vertex_size += 4 * sizeof(GLshort); + break; + case VertexAttributeDef::SHORT2: + m_vertex_size += 2 * sizeof(GLshort); break; default: ASSERT(false); break; } - ++index; } - m_attributes[index] = VertexAttributeDef::NONE; - m_attribute_count = index; + m_attribute_count = attribute_count; + return true; + } @@ -95,26 +92,41 @@ int VertexDef::getPositionOffset() const int offset = 0; for(int i = 0; i < m_attribute_count; ++i) { - switch(m_attributes[i]) + switch (m_attributes[i].m_type) { - case VertexAttributeDef::FLOAT2: - offset += 2 * sizeof(float); - break; case VertexAttributeDef::FLOAT4: offset += 4 * sizeof(float); break; - case VertexAttributeDef::INT4: - offset += 4 * sizeof(int); - break; - case VertexAttributeDef::INT1: - offset += sizeof(int); - break; case VertexAttributeDef::POSITION: return offset; break; + case VertexAttributeDef::FLOAT3: + offset += 3 * sizeof(float); + break; + case VertexAttributeDef::FLOAT2: + offset += 2 * sizeof(float); + break; + case VertexAttributeDef::FLOAT1: + offset += 1 * sizeof(float); + break; + case VertexAttributeDef::INT4: + offset += 4 * sizeof(int); + break; + case VertexAttributeDef::INT3: + offset += 3 * sizeof(int); + break; + case VertexAttributeDef::INT2: + offset += 2 * sizeof(int); + break; + case VertexAttributeDef::INT1: + offset += 1 * sizeof(int); + break; case VertexAttributeDef::BYTE4: offset += 4 * sizeof(char); break; + case VertexAttributeDef::SHORT4: + offset += 4 * sizeof(short); + break; case VertexAttributeDef::SHORT2: offset += 2 * sizeof(short); break; @@ -131,54 +143,67 @@ void VertexDef::begin(Shader& shader, int start_offset) const { PROFILE_FUNCTION(); int offset = start_offset; - int shader_attrib_idx = 0; int attribute_count = Math::minValue(m_attribute_count, shader.getAttributeCount()); for(int i = 0; i < attribute_count; ++i) { - GLint attrib_id = shader.getAttribId(shader_attrib_idx); - switch(m_attributes[i]) + GLint attrib_id = shader.getAttribId(m_attributes[i].m_name_index); + switch (m_attributes[i].m_type) { + case VertexAttributeDef::FLOAT4: + glEnableVertexAttribArray(attrib_id); + glVertexAttribPointer(attrib_id, 4, GL_FLOAT, GL_FALSE, m_vertex_size, (GLvoid*)offset); + offset += sizeof(GLfloat) * 4; + break; case VertexAttributeDef::POSITION: + case VertexAttributeDef::FLOAT3: glEnableVertexAttribArray(attrib_id); glVertexAttribPointer(attrib_id, 3, GL_FLOAT, GL_FALSE, m_vertex_size, (GLvoid*)offset); offset += sizeof(GLfloat) * 3; - ++shader_attrib_idx; - break; - case VertexAttributeDef::SHORT2: - glEnableVertexAttribArray(attrib_id); - glVertexAttribPointer(attrib_id, 2, GL_SHORT, GL_FALSE, m_vertex_size, (GLvoid*)offset); - offset += sizeof(GLshort) * 2; - ++shader_attrib_idx; break; case VertexAttributeDef::FLOAT2: glEnableVertexAttribArray(attrib_id); glVertexAttribPointer(attrib_id, 2, GL_FLOAT, GL_FALSE, m_vertex_size, (GLvoid*)offset); offset += sizeof(GLfloat) * 2; - ++shader_attrib_idx; break; - case VertexAttributeDef::FLOAT4: + case VertexAttributeDef::FLOAT1: glEnableVertexAttribArray(attrib_id); - glVertexAttribPointer(attrib_id, 4, GL_FLOAT, GL_FALSE, m_vertex_size, (GLvoid*)offset); - offset += sizeof(GLfloat) * 4; - ++shader_attrib_idx; + glVertexAttribPointer(attrib_id, 1, GL_FLOAT, GL_FALSE, m_vertex_size, (GLvoid*)offset); + offset += sizeof(GLfloat) * 1; + break; + case VertexAttributeDef::SHORT4: + glEnableVertexAttribArray(attrib_id); + glVertexAttribPointer(attrib_id, 4, GL_SHORT, GL_FALSE, m_vertex_size, (GLvoid*)offset); + offset += sizeof(GLshort) * 4; + break; + case VertexAttributeDef::SHORT2: + glEnableVertexAttribArray(attrib_id); + glVertexAttribPointer(attrib_id, 2, GL_SHORT, GL_FALSE, m_vertex_size, (GLvoid*)offset); + offset += sizeof(GLshort) * 2; break; case VertexAttributeDef::INT4: glEnableVertexAttribArray(attrib_id); glVertexAttribPointer(attrib_id, 4, GL_INT, GL_FALSE, m_vertex_size, (GLvoid*)offset); offset += sizeof(GLint) * 4; - ++shader_attrib_idx; + break; + case VertexAttributeDef::INT3: + glEnableVertexAttribArray(attrib_id); + glVertexAttribPointer(attrib_id, 3, GL_INT, GL_FALSE, m_vertex_size, (GLvoid*)offset); + offset += sizeof(GLint) * 3; + break; + case VertexAttributeDef::INT2: + glEnableVertexAttribArray(attrib_id); + glVertexAttribPointer(attrib_id, 2, GL_INT, GL_FALSE, m_vertex_size, (GLvoid*)offset); + offset += sizeof(GLint) * 2; break; case VertexAttributeDef::INT1: glEnableVertexAttribArray(attrib_id); glVertexAttribPointer(attrib_id, 1, GL_INT, GL_FALSE, m_vertex_size, (GLvoid*)offset); offset += sizeof(GLint) * 1; - ++shader_attrib_idx; break; case VertexAttributeDef::BYTE4: glEnableVertexAttribArray(attrib_id); glVertexAttribPointer(attrib_id, 4, GL_BYTE, GL_FALSE, m_vertex_size, (GLvoid*)offset); offset += sizeof(char) * 4; - ++shader_attrib_idx; break; default: ASSERT(false); @@ -192,25 +217,9 @@ void VertexDef::begin(Shader& shader, int start_offset) const void VertexDef::end(Shader& shader) const { PROFILE_FUNCTION(); - int shader_attrib_idx = 0; for(int i = 0; i < m_attribute_count; ++i) { - switch(m_attributes[i]) - { - case VertexAttributeDef::POSITION: - case VertexAttributeDef::BYTE4: - case VertexAttributeDef::SHORT2: - case VertexAttributeDef::INT1: - case VertexAttributeDef::INT4: - case VertexAttributeDef::FLOAT4: - case VertexAttributeDef::FLOAT2: - glDisableVertexAttribArray(shader.getAttribId(shader_attrib_idx)); - ++shader_attrib_idx; - break; - default: - ASSERT(false); - break; - } + glDisableVertexAttribArray(shader.getAttribId(m_attributes[i].m_name_index)); } } diff --git a/src/graphics/geometry.h b/src/graphics/geometry.h index 7f75df92e..b4641c6e9 100644 --- a/src/graphics/geometry.h +++ b/src/graphics/geometry.h @@ -4,7 +4,7 @@ #include "core/delegate.h" #include "core/vec3.h" #include "graphics/gl_ext.h" - +#include "graphics/shader.h" namespace Lumix { @@ -13,14 +13,19 @@ namespace Lumix class Shader; -enum class VertexAttributeDef : uint8_t +enum class VertexAttributeDef : uint32_t { - FLOAT4, - FLOAT2, - INT4, - INT1, POSITION, + FLOAT1, + FLOAT2, + FLOAT3, + FLOAT4, + INT1, + INT2, + INT3, + INT4, SHORT2, + SHORT4, BYTE4, NONE }; @@ -29,15 +34,25 @@ enum class VertexAttributeDef : uint8_t struct VertexDef { public: - void parse(const char* data, int size); + VertexDef() : m_attribute_count(0) {} + void addAttribute(Renderer& renderer, const char* name, VertexAttributeDef type); + bool parse(Renderer& renderer, FS::IFile* file); int getVertexSize() const { return m_vertex_size; } int getPositionOffset() const; void begin(Shader& shader, int start_offset) const; void end(Shader& shader) const; - VertexAttributeDef getAttributeType(int i) const { return i < m_attribute_count ? m_attributes[i] : VertexAttributeDef::NONE; } + VertexAttributeDef getAttributeType(int i) const { return i < m_attribute_count ? m_attributes[i].m_type : VertexAttributeDef::NONE; } private: - VertexAttributeDef m_attributes[16]; + class Attribute + { + public: + VertexAttributeDef m_type; + int m_name_index; + }; + + private: + Attribute m_attributes[Shader::MAX_ATTRIBUTE_COUNT]; int m_attribute_count; int m_vertex_size; }; diff --git a/src/graphics/model.cpp b/src/graphics/model.cpp index 8541a38fd..83187ea49 100644 --- a/src/graphics/model.cpp +++ b/src/graphics/model.cpp @@ -12,6 +12,7 @@ #include "core/vec3.h" #include "graphics/geometry.h" #include "graphics/material.h" +#include "graphics/model_manager.h" #include "graphics/pose.h" #include "graphics/renderer.h" @@ -155,18 +156,7 @@ void Model::getPose(Pose& pose) bool Model::parseVertexDef(FS::IFile* file, VertexDef* vertex_definition) { ASSERT(vertex_definition); - int vertex_def_size = 0; - file->read(&vertex_def_size, sizeof(vertex_def_size)); - char tmp[16]; - ASSERT(vertex_def_size < 16); - if (vertex_def_size >= 16) - { - g_log_error.log("renderer") << "Model file corrupted " << getPath().c_str(); - return false; - } - file->read(tmp, vertex_def_size); - vertex_definition->parse(tmp, vertex_def_size); - return true; + return vertex_definition->parse(static_cast(m_resource_manager.get(ResourceManager::MODEL))->getRenderer(), file); } bool Model::parseGeometry(FS::IFile* file) diff --git a/src/graphics/model_manager.h b/src/graphics/model_manager.h index 5eb72c9ad..9216cf328 100644 --- a/src/graphics/model_manager.h +++ b/src/graphics/model_manager.h @@ -4,21 +4,29 @@ namespace Lumix { + + class Renderer; + + class LUMIX_ENGINE_API ModelManager : public ResourceManagerBase { public: - ModelManager(IAllocator& allocator) + ModelManager(IAllocator& allocator, Renderer& renderer) : ResourceManagerBase(allocator) - , m_allocator(allocator) + , m_allocator(allocator) + , m_renderer(renderer) {} ~ModelManager() {} + Renderer& getRenderer() { return m_renderer; } + protected: virtual Resource* createResource(const Path& path) override; virtual void destroyResource(Resource& resource) override; private: IAllocator& m_allocator; + Renderer& m_renderer; }; } \ No newline at end of file diff --git a/src/graphics/pipeline.cpp b/src/graphics/pipeline.cpp index b2895b043..ba406f1f5 100644 --- a/src/graphics/pipeline.cpp +++ b/src/graphics/pipeline.cpp @@ -279,6 +279,12 @@ struct PipelineImpl : public Pipeline } + Renderer& getRenderer() + { + return static_cast(m_resource_manager.get(ResourceManager::PIPELINE))->getRenderer(); + } + + virtual ~PipelineImpl() override { ASSERT(isEmpty()); @@ -1093,7 +1099,9 @@ void DrawScreenQuadCommand::deserialize(PipelineImpl& pipeline, JsonSerializer& { m_geometry = m_allocator.newObject(); VertexDef def; - def.parse("pt", 2); + Renderer& renderer = pipeline.getRenderer(); + def.addAttribute(renderer, "in_position", VertexAttributeDef::POSITION); + def.addAttribute(renderer, "in_tex_coords", VertexAttributeDef::SHORT2); int indices[6] = { 0, 1, 2, 0, 2, 3 }; const int GEOMETRY_VERTEX_ATTRIBUTE_COUNT = 20; float v[GEOMETRY_VERTEX_ATTRIBUTE_COUNT]; diff --git a/src/graphics/pipeline.h b/src/graphics/pipeline.h index a1089f4ff..c639b7190 100644 --- a/src/graphics/pipeline.h +++ b/src/graphics/pipeline.h @@ -27,11 +27,13 @@ class IFile; class LUMIX_ENGINE_API PipelineManager : public ResourceManagerBase { public: - PipelineManager(IAllocator& allocator) + PipelineManager(IAllocator& allocator, Renderer& renderer) : ResourceManagerBase(allocator) + , m_renderer(renderer) , m_allocator(allocator) {} ~PipelineManager() {} + Renderer& getRenderer() { return m_renderer; } protected: virtual Resource* createResource(const Path& path) override; @@ -39,6 +41,7 @@ protected: private: IAllocator& m_allocator; + Renderer& m_renderer; }; diff --git a/src/graphics/render_scene.cpp b/src/graphics/render_scene.cpp index d6554b230..02a058323 100644 --- a/src/graphics/render_scene.cpp +++ b/src/graphics/render_scene.cpp @@ -149,7 +149,8 @@ namespace Lumix count += m_texts.at(i).m_text.length() << 2; } VertexDef vertex_definition; - vertex_definition.parse("f2f2", 4); + vertex_definition.addAttribute(m_engine.getRenderer(), "in_position", VertexAttributeDef::FLOAT2); + vertex_definition.addAttribute(m_engine.getRenderer(), "in_tex_coords", VertexAttributeDef::SHORT2); Array indices(m_allocator); Array data(m_allocator); indices.reserve(count); @@ -574,7 +575,7 @@ namespace Lumix serializer.read(exists); if(exists) { - m_terrains[i] = m_allocator.newObject(Entity::INVALID, *this, m_allocator); + m_terrains[i] = m_allocator.newObject(m_renderer, Entity::INVALID, *this, m_allocator); Terrain* terrain = m_terrains[i]; terrain->deserialize(serializer, m_universe, *this, i); } @@ -649,7 +650,7 @@ namespace Lumix { if (type == TERRAIN_HASH) { - Terrain* terrain = m_allocator.newObject(entity, *this, m_allocator); + Terrain* terrain = m_allocator.newObject(m_renderer, entity, *this, m_allocator); m_terrains.push(terrain); Component cmp = m_universe.addComponent(entity, type, this, m_terrains.size() - 1); m_universe.componentCreated().invoke(cmp); diff --git a/src/graphics/renderer.cpp b/src/graphics/renderer.cpp index ef13dc296..36eb597ea 100644 --- a/src/graphics/renderer.cpp +++ b/src/graphics/renderer.cpp @@ -44,11 +44,12 @@ struct RendererImpl : public Renderer : m_engine(engine) , m_allocator(engine.getAllocator()) , m_texture_manager(m_allocator) - , m_model_manager(m_allocator) + , m_model_manager(m_allocator, *this) , m_material_manager(m_allocator) , m_shader_manager(m_allocator) , m_font_manager(m_allocator) - , m_pipeline_manager(m_allocator) + , m_pipeline_manager(m_allocator, *this) + , m_attribute_names(m_allocator) { m_texture_manager.create(ResourceManager::TEXTURE, engine.getResourceManager()); m_model_manager.create(ResourceManager::MODEL, engine.getResourceManager()); @@ -419,6 +420,20 @@ struct RendererImpl : public Renderer } + virtual int getAttributeNameIndex(const char* name) override + { + for (int i = 0; i < m_attribute_names.size(); ++i) + { + if (m_attribute_names[i] == name) + { + return i; + } + } + m_attribute_names.emplace(name, m_allocator); + return m_attribute_names.size() - 1; + } + + Engine& m_engine; Debug::Allocator m_allocator; TextureManager m_texture_manager; @@ -436,6 +451,7 @@ struct RendererImpl : public Renderer Matrix m_view_matrix; Matrix m_projection_matrix; Shader* m_debug_shader; + Array m_attribute_names; }; @@ -607,11 +623,13 @@ void renderGeometry(int indices_offset, int vertex_count) glDrawElements(GL_TRIANGLES, vertex_count, GL_UNSIGNED_INT, (void*)(indices_offset * sizeof(GLint))); } + void renderQuadGeometry(int indices_offset, int vertex_count) { glDrawElements(GL_QUADS, vertex_count, GL_UNSIGNED_INT, (void*)(indices_offset * sizeof(GLint))); } + int getUniformLocation(const Shader& shader, int name) { return shader.getFixedCachedUniformLocation((Shader::FixedCachedUniforms)name); diff --git a/src/graphics/renderer.h b/src/graphics/renderer.h index 0bbb00825..aab3d4493 100644 --- a/src/graphics/renderer.h +++ b/src/graphics/renderer.h @@ -59,6 +59,7 @@ class LUMIX_ENGINE_API Renderer : public IPlugin virtual uint32_t getPass() = 0; virtual void applyShader(Shader& shader, uint32_t combination) = 0; virtual Shader& getDebugShader() = 0; + virtual int getAttributeNameIndex(const char* name) = 0; virtual void setProjection(float width, float height, float fov, float near_plane, float far_plane, const Matrix& mtx) = 0; virtual void setViewMatrix(const Matrix& matrix) = 0; diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index a24f74b3d..f8d218d08 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -151,7 +151,8 @@ void Shader::createCombination(const char* defines) for (int i = 0; i < m_attributes.size(); ++i) { - combination->m_vertex_attributes_ids[i] = glGetAttribLocation(combination->m_program_id, m_attributes[i].c_str()); + int attr_idx = m_renderer.getAttributeNameIndex(m_attributes[i].c_str()); + combination->m_vertex_attributes_ids[attr_idx] = glGetAttribLocation(combination->m_program_id, m_attributes[i].c_str()); } combination->m_fixed_cached_uniforms[(int)FixedCachedUniforms::WORLD_MATRIX] = glGetUniformLocation(combination->m_program_id, "world_matrix"); combination->m_fixed_cached_uniforms[(int)FixedCachedUniforms::GRASS_MATRICES] = glGetUniformLocation(combination->m_program_id, "grass_matrices"); diff --git a/src/graphics/terrain.cpp b/src/graphics/terrain.cpp index eda0ef422..ada705176 100644 --- a/src/graphics/terrain.cpp +++ b/src/graphics/terrain.cpp @@ -163,7 +163,7 @@ namespace Lumix }; - Terrain::Terrain(const Entity& entity, RenderScene& scene, IAllocator& allocator) + Terrain::Terrain(Renderer& renderer, const Entity& entity, RenderScene& scene, IAllocator& allocator) : m_mesh(NULL) , m_material(NULL) , m_root(NULL) @@ -181,6 +181,7 @@ namespace Lumix , m_last_camera_position(m_allocator) , m_grass_types(m_allocator) , m_free_grass_quads(m_allocator) + , m_renderer(renderer) { generateGeometry(); } @@ -850,7 +851,8 @@ namespace Lumix generateSubgrid(points, indices, indices_offset, 8, 8); VertexDef vertex_def; - vertex_def.parse("pt", 2); + vertex_def.addAttribute(m_renderer, "in_position", VertexAttributeDef::POSITION); + vertex_def.addAttribute(m_renderer, "in_tex_coords", VertexAttributeDef::SHORT2); m_geometry.setAttributesData(&points[0], sizeof(points[0]) * points.size()); m_geometry.setIndicesData(&indices[0], sizeof(indices[0]) * indices.size()); m_mesh = m_allocator.newObject(vertex_def, m_material, 0, 0, points.size() * sizeof(points[0]), indices.size(), "terrain", m_allocator); diff --git a/src/graphics/terrain.h b/src/graphics/terrain.h index b6b31b416..3cc63fce0 100644 --- a/src/graphics/terrain.h +++ b/src/graphics/terrain.h @@ -75,7 +75,7 @@ class Terrain static const int GRASS_QUAD_SIZE = 10; public: - Terrain(const Entity& entity, RenderScene& scene, IAllocator& allocator); + Terrain(Renderer& renderer, const Entity& entity, RenderScene& scene, IAllocator& allocator); ~Terrain(); void render(Renderer& renderer, PipelineInstance& pipeline, const Vec3& camera_pos); @@ -135,6 +135,7 @@ class Terrain Vec3 m_brush_position; float m_brush_size; bool m_force_grass_update; + Renderer& m_renderer; };