diff --git a/Hazel/src/Hazel/Renderer/EditorCamera.h b/Hazel/src/Hazel/Renderer/EditorCamera.h index 1333a88..9911e62 100644 --- a/Hazel/src/Hazel/Renderer/EditorCamera.h +++ b/Hazel/src/Hazel/Renderer/EditorCamera.h @@ -38,7 +38,7 @@ namespace Hazel glm::vec3 GetUpDirection() const; glm::vec3 GetRightDirection() const; glm::vec3 GetForwardDirection() const; - glm::vec3 GetPosition() const { return m_Position; } + glm::vec3 GetPosition() const { return m_Position; } glm::quat GetOrientation() const; float GetPitch() const { return m_Pitch; } diff --git a/Hazel/src/Hazel/Renderer/Renderer2D.cpp b/Hazel/src/Hazel/Renderer/Renderer2D.cpp index 9be1dae..8469362 100644 --- a/Hazel/src/Hazel/Renderer/Renderer2D.cpp +++ b/Hazel/src/Hazel/Renderer/Renderer2D.cpp @@ -30,6 +30,27 @@ namespace Hazel int EntityID; }; + struct CircleVertex + { + glm::vec3 WorldPosition; + glm::vec3 LocalPosition; + glm::vec4 Color; + float Thickness; + float Fade; + + // TODO: Editor Only + int EntityID; + }; + + struct LineVertex + { + glm::vec3 Position; + glm::vec4 Color; + + // TODO: Editor Only + int EntityID; + }; + struct Renderer2DStorage { const uint32_t MaxQuad = 10000; @@ -39,13 +60,32 @@ namespace Hazel Ref QuadVertexArray; Ref QuadVertexBuffer; - Ref TextureShader; + Ref QuadShader; Ref WhiteTexture; + Ref CircleVertexArray; + Ref CircleVertexBuffer; + Ref CircleShader; + + Ref LineVertexArray; + Ref LineVertexBuffer; + Ref LineShader; + + uint32_t QuadIndexCount = 0; QuadVertex* QuadVertexBufferBase = nullptr; QuadVertex* QuadVertexBufferPtr = nullptr; + uint32_t CircleIndexCount = 0; + CircleVertex* CircleVertexBufferBase = nullptr; + CircleVertex* CircleVertexBufferPtr = nullptr; + + uint32_t LineVertexCount = 0; + LineVertex* LineVertexBufferBase = nullptr; + LineVertex* LineVertexBufferPtr = nullptr; + + float LineWidth = 2.0f; + std::array, MaxTextureSlots> TextureSlots; uint32_t TextureSlotIndex = 1; // 0 use white texture @@ -67,6 +107,7 @@ namespace Hazel { HZ_PROFILE_FUNCTION(); + ///////////////Quad////////////////// // s_Data = new Renderer2DStorage(); s_Data.QuadVertexArray = VertexArray::Create(); @@ -104,8 +145,44 @@ namespace Hazel Ref quadIB = IndexBuffer::Create(quadIndices, s_Data.MaxIndices); s_Data.QuadVertexArray->SetIndexBuffer(quadIB); delete[] quadIndices; + //////////////////////////////////////// + ///////////////Circle////////////////// + s_Data.CircleVertexArray = VertexArray::Create(); + + //= VertexBuffer::Create(squareVertices, sizeof(squareVertices)); + s_Data.CircleVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(CircleVertex)); + s_Data.CircleVertexBuffer->SetLayout( + { + {ShaderDataType::Float3, "a_WorldPostion"}, + {ShaderDataType::Float3, "a_LocalPostion"}, + {ShaderDataType::Float4, "a_Color"}, + {ShaderDataType::Float, "a_Thickness"}, + {ShaderDataType::Float, "a_Fade"}, + {ShaderDataType::Int, "a_EntityID"} + }); + s_Data.CircleVertexArray->AddVertexBuffer(s_Data.CircleVertexBuffer); + s_Data.CircleVertexArray->SetIndexBuffer(quadIB); + s_Data.CircleVertexBufferBase = new CircleVertex[s_Data.MaxVertices]; + /////////////////////////////////////// + + /////////////// line////////////////// + s_Data.LineVertexArray = VertexArray::Create(); + + //= VertexBuffer::Create(squareVertices, sizeof(squareVertices)); + s_Data.LineVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(LineVertex)); + s_Data.LineVertexBuffer->SetLayout( + { + {ShaderDataType::Float3, "a_Postion"}, + {ShaderDataType::Float4, "a_Color"}, + {ShaderDataType::Int, "a_EntityID"} + }); + s_Data.LineVertexArray->AddVertexBuffer(s_Data.LineVertexBuffer); + // s_Data.LineVertexArray->SetIndexBuffer(quadIB); + s_Data.LineVertexBufferBase = new LineVertex[s_Data.MaxVertices]; + /////////////////////////////////////// + s_Data.WhiteTexture = Texture2D::Create(1, 1); uint32_t whiteTextureData = 0xffffffff; s_Data.WhiteTexture->SetData(&whiteTextureData, sizeof(uint32_t)); @@ -117,9 +194,9 @@ namespace Hazel samplers[i] = i; } - s_Data.TextureShader = Shader::Create("assets/shaders/Texture.glsl"); - s_Data.TextureShader->Bind(); - s_Data.TextureShader->SetIntv("u_Textures", samplers, s_Data.MaxTextureSlots); + s_Data.QuadShader = Shader::Create("assets/shaders/Renderer2D_quad.glsl"); + s_Data.CircleShader = Shader::Create("assets/shaders/Renderer2D_circle.glsl"); + s_Data.LineShader = Shader::Create("assets/shaders/Renderer2D_line.glsl"); // set all texture slot to 0 s_Data.TextureSlots[0] = s_Data.WhiteTexture; @@ -184,20 +261,45 @@ namespace Hazel { HZ_PROFILE_FUNCTION(); - const uint32_t datasize = reinterpret_cast(s_Data.QuadVertexBufferPtr) - reinterpret_cast(s_Data.QuadVertexBufferBase); - s_Data.QuadVertexBuffer->SetData(s_Data.QuadVertexBufferBase, datasize); Flush(); } void Renderer2D::Flush() { - for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i ++ ) - { - s_Data.TextureSlots[i]->Bind(i); - } - RendererCommand::DrawIndexed(s_Data.QuadVertexArray, s_Data.QuadIndexCount); + if (s_Data.QuadIndexCount) + { + const uint32_t datasize = reinterpret_cast(s_Data.QuadVertexBufferPtr) - reinterpret_cast(s_Data.QuadVertexBufferBase); + s_Data.QuadVertexBuffer->SetData(s_Data.QuadVertexBufferBase, datasize); - s_Data.Stats.DrawCalls++; + for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++) + { + s_Data.TextureSlots[i]->Bind(i); + } + s_Data.QuadShader->Bind(); + RendererCommand::DrawIndexed(s_Data.QuadVertexArray, s_Data.QuadIndexCount); + s_Data.Stats.DrawCalls++; + } + + if (s_Data.CircleIndexCount) + { + const uint32_t datasize = reinterpret_cast(s_Data.CircleVertexBufferPtr) - reinterpret_cast(s_Data.CircleVertexBufferBase); + s_Data.CircleVertexBuffer->SetData(s_Data.CircleVertexBufferBase, datasize); + auto& a = s_Data; + s_Data.CircleShader->Bind(); + RendererCommand::DrawIndexed(s_Data.CircleVertexArray, s_Data.CircleIndexCount); + s_Data.Stats.DrawCalls++; + } + + if (s_Data.LineVertexCount) + { + const uint32_t datasize = reinterpret_cast(s_Data.LineVertexBufferPtr) - reinterpret_cast(s_Data.LineVertexBufferBase); + s_Data.LineVertexBuffer->SetData(s_Data.LineVertexBufferBase, datasize); + auto& a = s_Data; + s_Data.LineShader->Bind(); + RendererCommand::SetLineWidth(s_Data.LineWidth); + RendererCommand::DrawLines(s_Data.LineVertexArray, s_Data.LineVertexCount); + s_Data.Stats.DrawCalls++; + } } void Renderer2D::StartBatch() @@ -205,6 +307,12 @@ namespace Hazel s_Data.QuadIndexCount = 0; s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase; + s_Data.CircleIndexCount = 0; + s_Data.CircleVertexBufferPtr = s_Data.CircleVertexBufferBase; + + s_Data.LineVertexCount = 0; + s_Data.LineVertexBufferPtr = s_Data.LineVertexBufferBase; + s_Data.TextureSlotIndex = 1; } @@ -320,7 +428,7 @@ namespace Hazel s_Data.Stats.QuadCount ++; } - void Renderer2D::DrawQuad(const glm::mat4& transform, const glm::vec4& Color, const int entityID) + void Renderer2D::DrawQuad(const glm::mat4& transform, const glm::vec4& color, const int entityID) { HZ_PROFILE_FUNCTION(); if (s_Data.QuadIndexCount >= s_Data.MaxIndices) @@ -335,7 +443,7 @@ namespace Hazel for (unsigned int i = 0; i < 4; i++) { s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPosition[i]; - s_Data.QuadVertexBufferPtr->Color = Color; + s_Data.QuadVertexBufferPtr->Color = color; s_Data.QuadVertexBufferPtr->TexCoord = texCoords[i]; s_Data.QuadVertexBufferPtr->TexIndex = textureIndex; s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor; @@ -532,6 +640,82 @@ namespace Hazel s_Data.Stats.QuadCount ++; } + void Renderer2D::DrawCircle(const glm::mat4& transform, const glm::vec4& color, const float thickness, const float fade, const int entityID) + { + HZ_PROFILE_FUNCTION(); + + // TODO: implement for circles + // if (s_Data.CircleIndexCount >= s_Data.MaxIndices) + // FlushAndReset(); + + for (size_t i = 0; i < 4; i++) + { + s_Data.CircleVertexBufferPtr->WorldPosition = transform * s_Data.QuadVertexPosition[i]; + s_Data.CircleVertexBufferPtr->LocalPosition = s_Data.QuadVertexPosition[i] * 2.0f; + s_Data.CircleVertexBufferPtr->Color = color; + s_Data.CircleVertexBufferPtr->Thickness = thickness; + s_Data.CircleVertexBufferPtr->Fade = fade; + s_Data.CircleVertexBufferPtr->EntityID = entityID; + s_Data.CircleVertexBufferPtr++; + } + + s_Data.CircleIndexCount += 6; + + s_Data.Stats.QuadCount ++; + } + + void Renderer2D::DrawLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color, const int entityID) + { + s_Data.LineVertexBufferPtr->Position = p0; + s_Data.LineVertexBufferPtr->Color = color; + s_Data.LineVertexBufferPtr->EntityID = entityID; + s_Data.LineVertexBufferPtr++; + + s_Data.LineVertexBufferPtr->Position = p1; + s_Data.LineVertexBufferPtr->Color = color; + s_Data.LineVertexBufferPtr->EntityID = entityID; + s_Data.LineVertexBufferPtr++; + + s_Data.LineVertexCount += 2; + } + + void Renderer2D::DrawRect(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color, const int entityID) + { + const glm::vec3 p0 = glm::vec3(position.x - size.x * 0.5f, position.y - size.y * 0.5f, position.z); + const glm::vec3 p1 = glm::vec3(position.x + size.x * 0.5f, position.y - size.y * 0.5f, position.z); + const glm::vec3 p2 = glm::vec3(position.x + size.x * 0.5f, position.y + size.y * 0.5f, position.z); + const glm::vec3 p3 = glm::vec3(position.x - size.x * 0.5f, position.y + size.y * 0.5f, position.z); + + DrawLine(p0, p1, color, entityID); + DrawLine(p1, p2, color, entityID); + DrawLine(p2, p3, color, entityID); + DrawLine(p3, p0, color, entityID); + } + + void Renderer2D::DrawRect(const glm::mat4& transform, const glm::vec4& color, int entityID) + { + glm::vec3 lineVectices[4]; + for (int i = 0; i < 4; i++) + { + lineVectices[i] = transform * s_Data.QuadVertexPosition[i]; + } + + DrawLine(lineVectices[0], lineVectices[1], color, entityID); + DrawLine(lineVectices[1], lineVectices[2], color, entityID); + DrawLine(lineVectices[2], lineVectices[3], color, entityID); + DrawLine(lineVectices[3], lineVectices[0], color, entityID); + } + + float Renderer2D::GetLineWidth() + { + return s_Data.LineWidth; + } + + void Renderer2D::SetLineWidth(const float width) + { + s_Data.LineWidth = width; + } + void Renderer2D::DrawSprite(const glm::mat4& transform, SpriteRendererComponent& src, int entityID) { if (src.Texture) diff --git a/Hazel/src/Hazel/Renderer/Renderer2D.h b/Hazel/src/Hazel/Renderer/Renderer2D.h index bbd516a..2b61ad6 100644 --- a/Hazel/src/Hazel/Renderer/Renderer2D.h +++ b/Hazel/src/Hazel/Renderer/Renderer2D.h @@ -44,7 +44,7 @@ namespace Hazel static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref& subTexture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref& subTexture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); - static void DrawQuad(const glm::mat4& transform, const glm::vec4& Color, const int entityID = -1); + static void DrawQuad(const glm::mat4& transform, const glm::vec4& color, int entityID = -1); static void DrawQuad(const glm::mat4& transform, const Ref& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f), const int entityID = -1); static void DrawRotateQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color); @@ -54,6 +54,14 @@ namespace Hazel static void DrawRotateQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref& subTexture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); static void DrawRotateQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref& subTexture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f)); + static void DrawCircle(const glm::mat4& transform, const glm::vec4& color, float thickness = 1.0f, float fade = 0.005f, int entityID = -1); + static void DrawLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color, int entityID = -1); + + static void DrawRect(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color, int entityID = -1); + static void DrawRect(const glm::mat4& transform, const glm::vec4& color, int entityID = -1); + + static float GetLineWidth(); + static void SetLineWidth(float width); static void DrawSprite(const glm::mat4& transform, SpriteRendererComponent& src, int entityID); diff --git a/Hazel/src/Hazel/Renderer/RendererAPI.h b/Hazel/src/Hazel/Renderer/RendererAPI.h index 7648b1f..8e9eb1d 100644 --- a/Hazel/src/Hazel/Renderer/RendererAPI.h +++ b/Hazel/src/Hazel/Renderer/RendererAPI.h @@ -30,6 +30,8 @@ namespace Hazel virtual void Clear() = 0; virtual void DrawIndexed(const std::shared_ptr& vertexArray, uint32_t indexCount) = 0; + virtual void DrawLines(const std::shared_ptr& vertexArray, uint32_t vertexCount) = 0; + virtual void SetLineWidth(float width) = 0; inline static API GetAPI() {return s_API; } diff --git a/Hazel/src/Hazel/Renderer/RendererCommand.h b/Hazel/src/Hazel/Renderer/RendererCommand.h index 2589d85..588be48 100644 --- a/Hazel/src/Hazel/Renderer/RendererCommand.h +++ b/Hazel/src/Hazel/Renderer/RendererCommand.h @@ -40,6 +40,15 @@ namespace Hazel { s_RendererAPI->DrawIndexed(vertexArray, indexCount); } + inline static void DrawLines(const std::shared_ptr& vertexArray, const uint32_t vertexCount) + { + s_RendererAPI->DrawLines(vertexArray, vertexCount); + } + + inline static void SetLineWidth(const float width) + { + s_RendererAPI->SetLineWidth(width); + } private: diff --git a/Hazel/src/Hazel/Scene/Components.h b/Hazel/src/Hazel/Scene/Components.h index b533fec..8d21382 100644 --- a/Hazel/src/Hazel/Scene/Components.h +++ b/Hazel/src/Hazel/Scene/Components.h @@ -62,9 +62,20 @@ namespace Hazel SpriteRendererComponent() = default; SpriteRendererComponent(const SpriteRendererComponent&) = default; - SpriteRendererComponent(const glm::vec4& color) : Color(color) - { - } + SpriteRendererComponent(const glm::vec4& color) : Color(color) {} + }; + + struct CircleRendererComponent + { + glm::vec4 Color{1.0f, 1.0f, 1.0f, 1.0f}; + float Radius = 0.5f; + float Thickness = 0.5f; + float Fade = 0.005f; + + CircleRendererComponent() = default; + CircleRendererComponent(const CircleRendererComponent&) = default; + + CircleRendererComponent(const glm::vec4& color) : Color(color) {} }; struct TagComponent @@ -130,13 +141,24 @@ namespace Hazel float Restitution = 0.0f; // 弹力 float RestitutionThreshold = 0.5f; // 弹力阈值 - // Storage for runtime - void *RuntimeBody = nullptr; - BoxCollider2DComponent() = default; BoxCollider2DComponent(const BoxCollider2DComponent&) = default; }; + struct CircleCollider2DComponent + { + glm::vec2 Offset = {0.0f, 0.0f}; + float Radius = 0.5f; + + // TODO(Yan): move into material texture in the future + float Density = 1.0f; // 密度 + float Friction = 0.5f; // 摩擦力 + float Restitution = 0.0f; // 弹力 + float RestitutionThreshold = 0.5f; // 弹力阈值 + + CircleCollider2DComponent() = default; + CircleCollider2DComponent(const CircleCollider2DComponent&) = default; + }; } diff --git a/Hazel/src/Hazel/Scene/Scene.cpp b/Hazel/src/Hazel/Scene/Scene.cpp index 1416a73..6233c1a 100644 --- a/Hazel/src/Hazel/Scene/Scene.cpp +++ b/Hazel/src/Hazel/Scene/Scene.cpp @@ -90,10 +90,12 @@ namespace Hazel CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); + CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); + CopyComponent(dstSceneRegistry, srcSceneRegistry, enttMap); return newScene; } @@ -151,8 +153,9 @@ namespace Hazel float hx = bc2d.Size.x * transform.Scale.x; float hy = bc2d.Size.y * transform.Scale.y; - b2Polygon boxShape = b2MakeBox(hx, hy); b2ShapeDef shapedef = b2DefaultShapeDef(); + auto rot = b2Rot(cos(0), sin(0)); + b2Polygon boxShape = b2MakeOffsetBox(hx, hy, b2Vec2(bc2d.Offset.x, bc2d.Offset.y), rot); shapedef.density = bc2d.Density; shapedef.material.friction = bc2d.Friction; @@ -161,6 +164,23 @@ namespace Hazel b2CreatePolygonShape(body, &shapedef,&boxShape); } + if (entity.HasComponent()) + { + auto& cc2d = entity.GetComponent(); + + b2Circle circle; + circle.center.x = cc2d.Offset.x; + circle.center.y = cc2d.Offset.y; + circle.radius = transform.Scale.x * cc2d.Radius; + + b2ShapeDef shapedef = b2DefaultShapeDef(); + shapedef.density = cc2d.Density; + shapedef.material.friction = cc2d.Friction; + shapedef.material.restitution = cc2d.Restitution; + + b2CreateCircleShape(body, &shapedef,&circle); + + } } } @@ -232,28 +252,11 @@ namespace Hazel } - if (mainCamera != nullptr) + if (mainCamera) { - Renderer2D::BeginScene(mainCamera->GetProjection(), cameraTranform); - auto group = m_Registry.group(entt::get); - for (auto entity : group) - { - auto [transform, sprite] = group.get(entity); - - Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity); - } - - Renderer2D::EndScene(); - } - } - - - void Scene::OnUpdateEditor(TimeStep & ts, const EditorCamera & camera) - { - Renderer2D::BeginScene(camera); - + // Draw Sprites auto group = m_Registry.group(entt::get); for (auto entity : group) { @@ -263,7 +266,46 @@ namespace Hazel Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity); } + // Draw Circles + auto view = m_Registry.view(); + for (auto entity : view) + { + auto [transform, circle] = view.get(entity); + + // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); + Renderer2D::DrawCircle(transform.GetTransform(), circle.Color, circle.Thickness, circle.Fade, (int)entity); + } + Renderer2D::EndScene(); + } + } + + + void Scene::OnUpdateEditor(TimeStep & ts, const EditorCamera & camera) + { + Renderer2D::BeginScene(camera); + + // Draw Sprites + auto group = m_Registry.group(entt::get); + for (auto entity : group) + { + auto [transform, sprite] = group.get(entity); + + // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); + Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity); + } + + // Draw Circles + auto view = m_Registry.view(); + for (auto entity : view) + { + auto [transform, circle] = view.get(entity); + + // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); + Renderer2D::DrawCircle(transform.GetTransform(), circle.Color, circle.Thickness, circle.Fade, (int)entity); + } + + Renderer2D::EndScene(); } void Scene::OnViewportResize(uint32_t width, uint32_t height) @@ -291,10 +333,12 @@ namespace Hazel CopyComponentIfExists(newEntity, entity); CopyComponentIfExists(newEntity, entity); + CopyComponentIfExists(newEntity, entity); CopyComponentIfExists(newEntity, entity); CopyComponentIfExists(newEntity, entity); CopyComponentIfExists(newEntity, entity); CopyComponentIfExists(newEntity, entity); + CopyComponentIfExists(newEntity, entity); } Entity Scene::GetPrimaryCameraEntity() @@ -336,6 +380,11 @@ namespace Hazel { } + template<> + void Scene::OnComponentAdded(Entity entity, CircleRendererComponent& component) + { + } + template<> void Scene::OnComponentAdded(Entity entity, TagComponent& component) { @@ -356,13 +405,20 @@ namespace Hazel { } + template<> + void Scene::OnComponentAdded(Entity entity, CircleCollider2DComponent& component) + { + } + template HAZEL_API void Scene::OnComponentAdded(Entity, IDComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, TransformComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, CameraComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, TagComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, SpriteRendererComponent&); + template HAZEL_API void Scene::OnComponentAdded(Entity, CircleRendererComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, NativeScriptComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, RigidBody2DComponent&); template HAZEL_API void Scene::OnComponentAdded(Entity, BoxCollider2DComponent&); + template HAZEL_API void Scene::OnComponentAdded(Entity, CircleCollider2DComponent&); } diff --git a/Hazel/src/Hazel/Scene/Scene.h b/Hazel/src/Hazel/Scene/Scene.h index 65d4eb3..615e349 100644 --- a/Hazel/src/Hazel/Scene/Scene.h +++ b/Hazel/src/Hazel/Scene/Scene.h @@ -42,6 +42,12 @@ namespace Hazel Entity GetPrimaryCameraEntity(); + template + auto GetAllEntitiesWith() + { + return m_Registry.view(); + } + private: template void OnComponentAdded(Entity entity, T& component); diff --git a/Hazel/src/Hazel/Scene/SceneSerializer.cpp b/Hazel/src/Hazel/Scene/SceneSerializer.cpp index c13a813..935c1e1 100644 --- a/Hazel/src/Hazel/Scene/SceneSerializer.cpp +++ b/Hazel/src/Hazel/Scene/SceneSerializer.cpp @@ -200,6 +200,19 @@ namespace Hazel out << YAML::EndMap; // CameraComponent } + if (entity.HasComponent()) + { + out << YAML::Key << "CircleRendererComponent"; + + out << YAML::BeginMap; // CircleRendererComponent + auto& circleRendererComponent = entity.GetComponent(); + out << YAML::Key << "Color" << YAML::Value << circleRendererComponent.Color; + out << YAML::Key << "Radius" << YAML::Value << circleRendererComponent.Radius; + out << YAML::Key << "Thickness" << YAML::Value << circleRendererComponent.Thickness; + out << YAML::Key << "Fade" << YAML::Value << circleRendererComponent.Fade; + out << YAML::EndMap; // CircleRendererComponent + } + if (entity.HasComponent()) { out << YAML::Key << "SpriteRendererComponent"; @@ -237,6 +250,22 @@ namespace Hazel out << YAML::EndMap; // BoxCollider2DComponent } + if (entity.HasComponent()) + { + out << YAML::Key << "CircleCollider2DComponent"; + + out << YAML::BeginMap; // CircleCollider2DComponent + auto& cc2dComponent = entity.GetComponent(); + out << YAML::Key << "Offset" << YAML::Value << cc2dComponent.Offset; + out << YAML::Key << "Radius" << YAML::Value << cc2dComponent.Radius; + out << YAML::Key << "Density" << YAML::Value << cc2dComponent.Density; + out << YAML::Key << "Friction" << YAML::Value << cc2dComponent.Friction; + out << YAML::Key << "Restitution" << YAML::Value << cc2dComponent.Restitution; + out << YAML::Key << "Restitution" << YAML::Value << cc2dComponent.Restitution; + out << YAML::Key << "RestitutionThreshold" << YAML::Value << cc2dComponent.RestitutionThreshold; + out << YAML::EndMap; // CircleCollider2DComponent + } + out << YAML::EndMap; // entity } @@ -333,6 +362,16 @@ namespace Hazel sprite.Color = spriteRendererComponent["Color"].as(); } + auto circleRendererComponent = entity["CircleRendererComponent"]; + if (circleRendererComponent) + { + auto& circle = deserializedEntity.AddComponent(); + circle.Color = circleRendererComponent["Color"].as(); + circle.Radius = circleRendererComponent["Radius"].as(); + circle.Thickness = circleRendererComponent["Thickness"].as(); + circle.Fade = circleRendererComponent["Fade"].as(); + } + auto rigidBody2DComponent = entity["RigidBody2DComponent"]; if (rigidBody2DComponent) { @@ -353,6 +392,17 @@ namespace Hazel bc2d.RestitutionThreshold = boxCollider2DComponent["RestitutionThreshold"].as(); } + auto circleCollider2DComponent = entity["CircleCollider2DComponent"]; + if (circleCollider2DComponent) + { + auto& cc2d = deserializedEntity.AddComponent(); + cc2d.Offset = circleCollider2DComponent["Offset"].as(); + cc2d.Radius = circleCollider2DComponent["Radius"].as(); + cc2d.Density = circleCollider2DComponent["Density"].as(); + cc2d.Friction = circleCollider2DComponent["Friction"].as(); + cc2d.Restitution = circleCollider2DComponent["Restitution"].as(); + cc2d.RestitutionThreshold = circleCollider2DComponent["RestitutionThreshold"].as(); + } } } diff --git a/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.cpp index 64ad287..6df8986 100644 --- a/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -4,8 +4,8 @@ #include "OpenGLRendererAPI.h" +#include #include -#include namespace Hazel { @@ -14,6 +14,7 @@ namespace Hazel HZ_PROFILE_FUNCTION(); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); + glEnable(GL_LINE_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } @@ -40,7 +41,27 @@ namespace Hazel count = indexCount; else count = vertexArray->GetIndexBuffer()->GetCount(); + if (count <= 0) + return; + vertexArray->Bind(); glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr); - glBindTexture(GL_TEXTURE_2D, 0); + } + + void OpenGLRendererAPI::DrawLines(const std::shared_ptr& vertexArray, const uint32_t vertexCount) + { + uint32_t count; + if (vertexCount != -1) + count = vertexCount; + else + count = vertexArray->GetIndexBuffer()->GetCount(); + if (count <= 0) + return; + vertexArray->Bind(); + glDrawArrays(GL_LINES, 0, count); + } + + void OpenGLRendererAPI::SetLineWidth(const float width) + { + glLineWidth(width); } } diff --git a/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.h b/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.h index 654607b..de7cbf0 100644 --- a/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.h +++ b/Hazel/src/Platform/OpenGL/OpenGLRendererAPI.h @@ -17,6 +17,8 @@ namespace Hazel virtual void SetViewPort(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; virtual void Clear() override; virtual void DrawIndexed(const std::shared_ptr& vertexArray, uint32_t indexCount = 0) override; + virtual void DrawLines(const std::shared_ptr& vertexArray, uint32_t vertexCount = 0) override; + virtual void SetLineWidth(float width) override; }; } diff --git a/Hazel/src/Platform/OpenGL/OpenGLShader.cpp b/Hazel/src/Platform/OpenGL/OpenGLShader.cpp index 6c25472..46ec084 100644 --- a/Hazel/src/Platform/OpenGL/OpenGLShader.cpp +++ b/Hazel/src/Platform/OpenGL/OpenGLShader.cpp @@ -130,7 +130,7 @@ namespace Hazel auto shaderSources = PreProcess(shaderSrc); Compile(shaderSources); - // example: /assets/shaders/Texture.glsl + // example: /assets/shaders/Renderer2D_quad.glsl auto lastSlash = filepath.find_last_of("\\/"); auto lastDot = filepath.find_last_of("."); m_Name = filepath.substr(lastSlash + 1, lastDot - lastSlash - 1); diff --git a/Sandbox/assets/shaders/Renderer2D_circle.glsl b/Sandbox/assets/shaders/Renderer2D_circle.glsl new file mode 100644 index 0000000..21e9c74 --- /dev/null +++ b/Sandbox/assets/shaders/Renderer2D_circle.glsl @@ -0,0 +1,72 @@ +// Basic circle Texture Shader + +#type vertex +#version 450 core + +layout(location = 0) in vec3 a_WorldPosition; +layout(location = 1) in vec3 a_LocalPosition; +layout(location = 2) in vec4 a_Color; +layout(location = 3) in float a_Thickness; +layout(location = 4) in float a_Fade; +layout(location = 5) in int a_EntityID; + +layout(std140, binding = 0) uniform Camera +{ + mat4 u_ViewProjection; +}; + +struct VertexOutput +{ + vec3 LocalPosition; + vec4 Color; + float Thickness; + float Fade; +}; + +layout (location = 0) out VertexOutput Output; +layout (location = 4) out flat int v_EntityID; + +void main() +{ + Output.LocalPosition = a_LocalPosition; + Output.Color = a_Color; + Output.Thickness = a_Thickness; + Output.Fade = a_Fade; + + v_EntityID = a_EntityID; + + gl_Position = u_ViewProjection * vec4(a_WorldPosition, 1.0); +} + +#type fragment +#version 450 core + +layout(location = 0) out vec4 o_Color; +layout(location = 1) out int o_EntityID; + +struct VertexOutput +{ + vec3 LocalPosition; + vec4 Color; + float Thickness; + float Fade; +}; + +layout (location = 0) in VertexOutput Input; +layout (location = 4) in flat int v_EntityID; + + +void main() +{ + float distance = 1.0f - length(Input.LocalPosition); + + float circle = smoothstep(0.0f, Input.Fade, distance); + circle *= smoothstep(Input.Thickness + Input.Fade, Input.Thickness, distance); + + if(circle == 0.0f) + discard; + + o_Color = Input.Color; + o_Color.a *= circle; + o_EntityID = v_EntityID; +} diff --git a/Sandbox/assets/shaders/Renderer2D_line.glsl b/Sandbox/assets/shaders/Renderer2D_line.glsl new file mode 100644 index 0000000..aec62ec --- /dev/null +++ b/Sandbox/assets/shaders/Renderer2D_line.glsl @@ -0,0 +1,49 @@ +// Basic Line Texture Shader + +#type vertex +#version 450 core + +layout(location = 0) in vec3 a_Position; +layout(location = 1) in vec4 a_Color; +layout(location = 2) in int a_EntityID; + +layout(std140, binding = 0) uniform Camera +{ + mat4 u_ViewProjection; +}; + +struct VertexOutput +{ + vec4 Color; +}; + +layout (location = 0) out VertexOutput Output; +layout (location = 1) out flat int v_EntityID; + +void main() +{ + Output.Color = a_Color; + v_EntityID = a_EntityID; + + gl_Position = u_ViewProjection * vec4(a_Position, 1.0); +} + +#type fragment +#version 450 core + +layout(location = 0) out vec4 o_Color; +layout(location = 1) out int o_EntityID; + +struct VertexOutput +{ + vec4 Color; +}; + +layout (location = 0) in VertexOutput Input; +layout (location = 1) in flat int v_EntityID; + +void main() +{ + o_Color = Input.Color; + o_EntityID = v_EntityID; +} diff --git a/Sandbox/assets/shaders/Texture.glsl b/Sandbox/assets/shaders/Renderer2D_quad.glsl similarity index 97% rename from Sandbox/assets/shaders/Texture.glsl rename to Sandbox/assets/shaders/Renderer2D_quad.glsl index 3df0c0a..3581011 100644 --- a/Sandbox/assets/shaders/Texture.glsl +++ b/Sandbox/assets/shaders/Renderer2D_quad.glsl @@ -1,4 +1,4 @@ -// Basic Texture Shader +// Basic quad Texture Shader #type vertex #version 450 core diff --git a/Sandbox/src/Editor/EditorLayer.cpp b/Sandbox/src/Editor/EditorLayer.cpp index 0550934..9704945 100644 --- a/Sandbox/src/Editor/EditorLayer.cpp +++ b/Sandbox/src/Editor/EditorLayer.cpp @@ -96,7 +96,6 @@ namespace Hazel break; } - // Renderer2D::BeginScene(m_CameraController.GetCamera()); auto [mx, my] = ImGui::GetMousePos(); mx -= m_ViewPortBounds[0].x; @@ -104,8 +103,8 @@ namespace Hazel const glm::vec2 viewPortSize = m_ViewPortBounds[1] - m_ViewPortBounds[0]; my = viewPortSize.y - my; - int mouseX = (int)mx; - int mouseY = (int)my; + const int mouseX = (int)mx; + const int mouseY = (int)my; if (mouseX >= 0 && mouseY >= 0 && mouseX < m_ViewPortSize.x && mouseY < m_ViewPortSize.y) { @@ -117,11 +116,54 @@ namespace Hazel // Renderer2D::DrawQuad({0, -0.5f}, {1.0f, 1.0f}, {0.8f, 0.2f, 0.2f, 1.0f}); // Renderer2D::DrawQuad({-1, 0}, {1, 1}, m_LogoTexture); // Renderer2D::DrawQuad({1, 0}, {1, 1}, m_CheckerBoardTexture); + OnOverLayRender(); // Renderer2D::EndScene(); m_FrameBuffer->UnBind(); } + void EditorLayer::OnOverLayRender() + { + + if (m_SceneState == SceneState::Play) + { + Entity camera = m_ActiveScene->GetPrimaryCameraEntity(); + Renderer2D::BeginScene(camera.GetComponent().Camera, camera.GetComponent().GetTransform()); + }else + { + Renderer2D::BeginScene(m_EditorCamera); + } + + if (m_ShowPhysicsColliders) + { + // box collider + auto bcview = m_ActiveScene->GetAllEntitiesWith(); + for (auto entity : bcview) + { + auto [tc, bc2D] = bcview.get(entity); + glm::vec3 translation = tc.Translation + glm::vec3(bc2D.Offset, 0.001f); + glm::vec3 scale = tc.Scale * glm::vec3(bc2D.Size * 2.0f, 1.0f); + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), translation) * glm::rotate( + glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f)) * glm::scale(glm::mat4(1.0f), scale); + Renderer2D::DrawRect(transform, glm::vec4(0.2, 1.0f, 0.2f, 1.0f)); + } + + // circle collider + auto ccview = m_ActiveScene->GetAllEntitiesWith(); + for (auto entity : ccview) + { + auto [tc, cc2D] = ccview.get(entity); + glm::vec3 translation = tc.Translation + glm::vec3(cc2D.Offset, 0.001f); + glm::vec3 scale = tc.Scale * glm::vec3(cc2D.Radius * 2.0f); + + glm::mat4 transform = glm::translate(glm::mat4(1.0f), translation) * glm::scale(glm::mat4(1.0f), scale); + Renderer2D::DrawCircle(transform, glm::vec4(0.2, 1.0f, 0.2f, 1.0f), Renderer2D::GetLineWidth() * 0.01f); + } + } + Renderer2D::EndScene(); + } + void EditorLayer::OnImGuiRender() { static bool showDockspace = true; @@ -229,12 +271,25 @@ namespace Hazel ImGui::Separator(); + auto editorCameraPos = m_EditorCamera.GetPosition(); + ImGui::Text("Editor Camera(%.3f, %.3f, %.3f)", editorCameraPos.x, editorCameraPos.y, editorCameraPos.z); + ImGui::Text("Editor Camera Distance: %f", m_EditorCamera.GetDistance()); + + float lineWidth = Renderer2D::GetLineWidth(); + if (ImGui::DragFloat("LineWidth", &lineWidth, 0.01f, 0.0f, 10.0f)) + { + Renderer2D::SetLineWidth(lineWidth); + } // std::string name = "none"; // if (m_HoveredEntity) // name = m_HoveredEntity.GetComponent().Tag; // ImGui::Text("Hovered Entity: %s", name.c_str()); + ImGui::Separator(); + + ImGui::Checkbox("Show Colliders", &m_ShowPhysicsColliders); + ImGui::End(); } @@ -464,11 +519,12 @@ namespace Hazel #define SHORTCUT_CTRL_D (SDL_KMOD_CTRL + SDLK_D) - const auto mod = SDL_GetModState(); - const auto ctrl = (mod & SDL_KMOD_CTRL) ? SDL_KMOD_CTRL : 0; - const auto shift = (mod & SDL_KMOD_SHIFT) ? SDL_KMOD_SHIFT : 0; if (e.key.down && e.key.repeat == 0) { + const auto mod = SDL_GetModState(); + const auto ctrl = (mod & SDL_KMOD_CTRL) ? SDL_KMOD_CTRL : 0; + const auto shift = (mod & SDL_KMOD_SHIFT) ? SDL_KMOD_SHIFT : 0; + switch (ctrl + shift + e.key.key) { case SHORTCUT_EXIT: @@ -539,7 +595,6 @@ namespace Hazel } - ImGui::PopStyleVar(2); ImGui::PopStyleColor(3); ImGui::End(); diff --git a/Sandbox/src/Editor/EditorLayer.h b/Sandbox/src/Editor/EditorLayer.h index 57ab064..18617df 100644 --- a/Sandbox/src/Editor/EditorLayer.h +++ b/Sandbox/src/Editor/EditorLayer.h @@ -41,6 +41,8 @@ namespace Hazel void ChangeOptMode(unsigned int mode); + void OnOverLayRender(); + private: OrthographicCameraController m_CameraController; @@ -63,12 +65,15 @@ namespace Hazel glm::vec2 m_ViewPortBounds[2]; Ref m_FrameBuffer; + Ref m_RuntimeFrameBuffer; SceneHierachyPanel m_SceneHierachyPanel; ContentBroswerPanel m_ContentBroswerPanel; int m_GizmoType = -1; + bool m_ShowPhysicsColliders = false; + enum class SceneState { Edit = 0, Play = 1 diff --git a/Sandbox/src/Editor/Panels/SceneHierachyPanel.cpp b/Sandbox/src/Editor/Panels/SceneHierachyPanel.cpp index 2baa2f8..8729879 100644 --- a/Sandbox/src/Editor/Panels/SceneHierachyPanel.cpp +++ b/Sandbox/src/Editor/Panels/SceneHierachyPanel.cpp @@ -265,13 +265,22 @@ namespace Hazel if (!m_SelectionContext.HasComponent()) { - if (ImGui::MenuItem("Sprite")) + if (ImGui::MenuItem("Sprite Renderer")) { m_SelectionContext.AddComponent(); ImGui::CloseCurrentPopup(); } } + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::MenuItem("Circle Renderer")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + if (!m_SelectionContext.HasComponent()) { if (ImGui::MenuItem("RigidBody 2D")) @@ -290,6 +299,15 @@ namespace Hazel } } + if (!m_SelectionContext.HasComponent()) + { + if (ImGui::MenuItem("Circle Collider 2D")) + { + m_SelectionContext.AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + ImGui::EndPopup(); } ImGui::PopItemWidth(); @@ -385,6 +403,13 @@ namespace Hazel ImGui::DragFloat("Tiling Color", &component.TilingFactor, 0.1f, 0.0f, 100.f); }); + DrawComponent("Circle Renderer", entity, [](auto& component) + { + ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); + // ImGui::DragFloat("Radius", &component.Radius, 0.01f, 0.0f, 1.f); + ImGui::DragFloat("Thickness", &component.Thickness, 0.01f, 0.0f, 1.f); + ImGui::DragFloat("Fade", &component.Fade, 0.00001f, 0.0f, 1.f); + }); DrawComponent("Rigidbody 2D", entity, [](auto& component) { @@ -415,8 +440,19 @@ namespace Hazel DrawComponent("Box Collider 2D", entity, [](auto& component) { - ImGui::DragFloat2("Offset", glm::value_ptr(component.Offset)); - ImGui::DragFloat2("Size", glm::value_ptr(component.Size)); + ImGui::DragFloat2("Offset", glm::value_ptr(component.Offset), 0.001f); + ImGui::DragFloat2("Size", glm::value_ptr(component.Size), 0.001f); + + ImGui::DragFloat("Density", &component.Density, 0.01f, 0.0f); + ImGui::DragFloat("Friction", &component.Friction, 0.01f, 0.0f, 1.0f); + ImGui::DragFloat("Restitution", &component.Restitution, 0.01f, 0.0f, 1.0f); + ImGui::DragFloat("Restitution Threshold", &component.RestitutionThreshold, 0.01f, 0.0f); + }); + + DrawComponent("Circle Collider 2D", entity, [](auto& component) + { + ImGui::DragFloat2("Offset", glm::value_ptr(component.Offset), 0.001f); + ImGui::DragFloat("Radius", &component.Radius, 0.001f); ImGui::DragFloat("Density", &component.Density, 0.01f, 0.0f); ImGui::DragFloat("Friction", &component.Friction, 0.01f, 0.0f, 1.0f); diff --git a/Sandbox/src/Example/ExampleLayer.cpp b/Sandbox/src/Example/ExampleLayer.cpp index 9db7a99..ea38b22 100644 --- a/Sandbox/src/Example/ExampleLayer.cpp +++ b/Sandbox/src/Example/ExampleLayer.cpp @@ -132,8 +132,8 @@ ExampleLayer::ExampleLayer() : Layer("ExampleLayer"), m_CameraController(1280.0f // Texture.Shader - // m_TextureShader = Hazel::Shader::Create("assets/shaders/Texture.glsl"); - auto textureShader = m_ShaderLibrary.Load("assets/shaders/Texture.glsl"); + // m_TextureShader = Hazel::Shader::Create("assets/shaders/Renderer2D_quad.glsl"); + auto textureShader = m_ShaderLibrary.Load("assets/shaders/Renderer2D_quad.glsl"); // Texture