From 980460305b0d7bc3205534e5db222082f32cc8ec Mon Sep 17 00:00:00 2001 From: Troy Neubauer Date: Tue, 3 Dec 2019 17:49:04 -0500 Subject: [PATCH] Game Design pre release --- GameDesign/assets/textures/Rocket.png | Bin 2649 -> 1977 bytes GameDesign/src/GameDesign.cpp | 6 +- GameDesign/src/layers/SandboxLayer.cpp | 186 +++++++++++++++++++++ GameDesign/src/layers/SandboxLayer.h | 31 ++++ GameDesign/src/layers/WorldLayer.cpp | 18 +- GameDesign/src/ship/Ship.cpp | 35 ++++ GameDesign/src/ship/Ship.h | 55 ++++++ GameDesign/src/world/Body.h | 11 +- GameDesign/src/world/Ship.cpp | 37 ---- GameDesign/src/world/Ship.h | 21 --- GameDesign/src/world/World.cpp | 83 +++++++-- GameDesign/src/world/World.h | 30 +++- Hazel/src/Hazel/Camera/Camera.h | 19 +++ Hazel/src/Hazel/Core/Core.h | 2 + Hazel/src/Hazel/Core/Input.h | 1 + Hazel/src/Hazel/Renderer/Texture.h | 2 +- Hazel/src/Hazel/Renderer2D/Animation2D.cpp | 74 ++++++++ Hazel/src/Hazel/Renderer2D/Animation2D.h | 53 ++++++ Hazel/src/Hazel/Renderer2D/Renderer2D.cpp | 150 +++++++++-------- Hazel/src/Hazel/Renderer2D/Renderer2D.h | 21 ++- Hazel/src/Platform/GLFW/GLFWInput.cpp | 5 + Hazel/src/Platform/NoAPI/NoAPI.h | 6 +- Hazel/src/Platform/OpenGL/OpenGLUtils.cpp | 1 + premake5.lua | 1 + 24 files changed, 685 insertions(+), 163 deletions(-) create mode 100644 GameDesign/src/layers/SandboxLayer.cpp create mode 100644 GameDesign/src/layers/SandboxLayer.h create mode 100644 GameDesign/src/ship/Ship.cpp create mode 100644 GameDesign/src/ship/Ship.h delete mode 100644 GameDesign/src/world/Ship.cpp delete mode 100644 GameDesign/src/world/Ship.h create mode 100644 Hazel/src/Hazel/Renderer2D/Animation2D.cpp create mode 100644 Hazel/src/Hazel/Renderer2D/Animation2D.h diff --git a/GameDesign/assets/textures/Rocket.png b/GameDesign/assets/textures/Rocket.png index bb85616a32254713fe315a02e4861059148f5474..b2c1ae5d54e59bbad3f37274e3f2541894c937ee 100644 GIT binary patch literal 1977 zcma)-cU03?8^?oTsw524T1=P{mKZ3ANf5%&hCpO08-zxdsD!1`2(p9%5>_fu0*atw z(NMquK_ikVVMGl}>R<+H!Zeg6L*E}gt?zmNd;fUubDwk1x#yne`Fy`O%hegLxKnK> z2n13jI2?5cav~79^0L7Ct4jP4AW6l#>wAhom<=#%T0Kx2eNN;J~+Rh#NMb@-~3KG8abMpixPI8RH8%H<~jbbaj0H)Yc0e_v1!eaHuZurs*2p;rL3^D+4k`b5f$G zrm?ibB*Kl^%bylQ_9n3(eS_0bZi-UKfWSTQ2gTne(2Ex*yNY^+)}<~A8(Qrx$HnHh1(tIX!8(F_*0q5N#! zL4 zO)#%pE39?Dwbv2%EKOL4=rIF2IeiZXMYu}5(Kn+O?$v0DQX%v}Ir>u6=#x*2^TUs3 z!e(qlPet*a;=l>*RV5l3dT+2e4FWgAANSu(^{T|=o19C5(C>p`L+KB4QMPi<#bDN5 zN_$T+YKw@CA5crSlY99Mb$r5*mW|Z)9odCI*IFV|yEol|_D1sqzSLUk9blj8O(9Lx z4EHzg7%Jl2RWMfEK8+pt>3v}ab0r8%ZXzq$$!n$mv+yGlh{crM;aeqn5c+e-LoH0o zkFebcbO5AU`A|yVK43dcWyxyp2#GL>8!JKIY@_J$0FD;>${zpeYbeRN=u`>jaZJmW zSk1@-BkzH}aN2t|{w1hnNp*)_;sV#FO3<6X#D<3D+Tn#$<=hw{S+wvya3RK#@FD*V z8ous_Ou9pTM}w5Em156(_~HAl%He6|Vn!^vbGFKIqMDKt6Up_#3rvOo|7->Icn`-O zCS$Ex7qJoDa%x3b0n<4pk3MbDVT_q17C-xtjW<-T=IkvWT2Aq|Vop?o4b^waEzMcM zVA27Af@YG7M$87xcOcMg2xi!c+<6ub*%}5R(4mkM{;EwDPo%dyHCZt)gN29ucS2$Z zuJ5fWwjiakm84z6M_q-$ReA51+gf8eeH$75%8>rF~oQb z^)QfNy*LM7T$`>0FDSCITYvI+#++ZvR$2C~9Qq|*znz&)%8a)8GOk?>dvWqThsl@( z8CWr9Y~9^6-8fex5te|aTQy;46mt0bg9bf%QipFYU!QKiGg&azyoWa}YR`}G-*hDX zKqaGg*S7YyULJOn80CJ4Q4{_VP?xo@?T5OT2)Lv(#%Z)dXc9$4sqy`}lq~35HAdC5 zX!K@Lj&R|x~*>RI9S{$S_xA7{M=HG`}>@*1h_zWYLsdIvz|D_Hb(>aU4 zcxpMfLhV@0@%uW|32()~5tpBli3735ol8O3ou}co+60ZR>myY({%3a_;=7&HK}lHa z=6RYdE%hsTt44?x(z$tmgO!7y`r5S`O?M*-i%u4p1?*={^x`B0%5N`c)@>LSz7m0{ zVJ$e3;*w?{-7AB5C#A;@tBH`tHdS4~i~|bsL-T8pRz$yWYwzH<93MpJ%?V#u&)mBt zoqP)L$jmC@U8--se%$P}u7BvO*FoBz__NrK*TEkq`Kq-nB^~2+49tt)X!=Jf-atN- zejt#5zWRcC^4rpb;NDN+mlNi?H(VzhY2j=VK`HJCNI?2SxwQWIi%QbTPzrsfbhW&H z`Lz*2iBZU?DEk{Pp{(%tpcP`9MT5YPlG>uaUpIcQdQBwauzIG9V2VB9?PIObBK4s8 zMB5?VyaR2w(Vlo{22nWSrDhgGkMo{44xcWK77mF9S!p`zKIg@jj&P@lGs&`z7r4T- xri>Z=XgCBDB(Z&TlB&WBg-->|8Bv4Rpoi=#O(?fG?Z9^nA{=u*%CHMc{SQGk#8LnN literal 2649 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 diff --git a/GameDesign/src/GameDesign.cpp b/GameDesign/src/GameDesign.cpp index b10ec82..ef3b06a 100644 --- a/GameDesign/src/GameDesign.cpp +++ b/GameDesign/src/GameDesign.cpp @@ -1,13 +1,13 @@ #include "GameDesign.h" -#include "layers/WorldLayer.h" +#include "layers/SandboxLayer.h" #include "Hazel.h" GameDesign::GameDesign() { PushOverlay(new Hazel::DebugLayer()); - PushLayer(new WorldLayer(new World())); + PushLayer(new SandboxLayer(new World())); } void GameDesign::Update() @@ -17,7 +17,7 @@ void GameDesign::Update() void GameDesign::Render() { - Hazel::RenderCommand::SetClearColor(glm::vec4(1.0f, 0.0f, 0.5f, 1.0f)); + Hazel::RenderCommand::SetClearColor(glm::vec4(glm::vec3(0.6f), 1.0f)); Hazel::RenderCommand::Clear(); if (Hazel::Input::IsMouseButtonPressed(HZ_MOUSE_BUTTON_5) || Hazel::Input::IsKeyPressed(HZ_KEY_H)) { diff --git a/GameDesign/src/layers/SandboxLayer.cpp b/GameDesign/src/layers/SandboxLayer.cpp new file mode 100644 index 0000000..8eab6c9 --- /dev/null +++ b/GameDesign/src/layers/SandboxLayer.cpp @@ -0,0 +1,186 @@ +#include "SandboxLayer.h" + +#include +#include + +void SandboxLayer::OnAttach() +{ + std::default_random_engine gen; + std::uniform_real_distribution pos(-12.0f, 12.0f); + Part& part = m_World->AddPart({ 0.0f, 0.0f }, Parts::StaticShip); + + for (int i = 0; i < 2; i++) + { + Part& part = m_World->AddPart({ pos(gen), pos(gen) }, Parts::MK1Capsule); + } + m_World->SetBodyRemovedCallback([this](Body* body) { + if (body == m_SelectedBody) m_SelectedBody = nullptr; + if (body == m_DraggedBody) + { + m_DraggedBody = nullptr; + m_MouseDragged = false; + } + + }); +} + +void SandboxLayer::OnDetach() +{ + +} + +float lastMoved = 0.0f; + +void SandboxLayer::OnUpdate() +{ + if (Hazel::Input::GetMouseDelta().x || Hazel::Input::GetMouseDelta().y) lastMoved = Hazel::Engine::GetTime(); + + if (m_Paused) + m_World->GetCamera().Update(); + else + m_World->Update(); + + if (m_DraggedBody && m_MouseDragged) + { + b2Vec2 velocity = {0.0f, 0.0f}; + if (Hazel::Input::DidMouseMove()) { + glm::vec2 delta = { Hazel::Input::GetMouseDelta().x, Hazel::Input::GetMouseDelta().y }; + delta /= Hazel::Engine::GetDeltaTime(); + glm::vec2 result = m_World->GetCamera().GetWorldDelta(delta); + velocity = { result.x, result.y }; + } + + m_DraggedBody->GetBody()->SetLinearVelocity(velocity); + } + +} + +void SandboxLayer::OnEvent(Hazel::Event* event) +{ + Hazel::EventDispatcher dispatcher(event); + dispatcher.Dispatch(HZ_BIND_EVENT_FN(SandboxLayer::OnMouseMoved)); + dispatcher.Dispatch(HZ_BIND_EVENT_FN(SandboxLayer::OnMousePressed)); + dispatcher.Dispatch(HZ_BIND_EVENT_FN(SandboxLayer::OnMouseReleased)); +} + +bool SandboxLayer::OnMouseMoved(Hazel::MouseMovedEvent* event) +{ + if (m_DraggedBody) + m_MouseDragged = true; + return false; +} + +template +class QueryCallback : public b2QueryCallback +{ +public: + QueryCallback(T func) : m_Func(func) {} + + bool ReportFixture(b2Fixture* fixture) + { + b2Body* body = fixture->GetBody(); + m_Func(World::ToBody(body)); + + return false;// Return true to continue the query. + } +private: + T m_Func; +}; + +bool SandboxLayer::OnMousePressed(Hazel::MouseButtonPressedEvent* event) +{ + glm::vec2 worldCoords = m_World->GetCamera().ToWorldCoordinates(Hazel::Input::GetMousePosition()); + b2AABB aabb; + aabb.lowerBound.Set(worldCoords.x, worldCoords.y); + aabb.upperBound.Set(worldCoords.x + 0.001f, worldCoords.y + 0.001f); + bool found = false; + auto callback = QueryCallback([this, &found](Body* body) { + found = true; + m_SelectedBody = body; + m_DraggedBody = body; + m_MouseDragged = false; + }); + if (!found) + { + m_SelectedBody = nullptr; + m_DraggedBody = nullptr; + m_MouseDragged = false; + } + m_World->GetWorld()->QueryAABB(&callback, aabb); + return false; +} + +bool SandboxLayer::OnMouseReleased(Hazel::MouseButtonReleasedEvent* event) +{ + m_DraggedBody = nullptr; + m_MouseDragged = false; + return false; +} + +static bool SliderDouble(const char* label, double* v, double v_min, double v_max, const char* format, float power) +{ + return ImGui::SliderScalar(label, ImGuiDataType_Double, v, &v_min, &v_max, format, power); +} + +static void Tooltip(const char* text) +{ + if (ImGui::IsItemHovered() && (Hazel::Engine::GetTime() - lastMoved) > 0.05f) + { + ImGui::BeginTooltip(); + ImGui::Text(text); + ImGui::EndTooltip(); + } +} + +void SandboxLayer::OnImGuiRender() +{ + ImGui::Begin("World Settings"); + + SliderDouble("G", &World::Constants::G, -0.01f, 10.0f, "%.5f", 3.0f); Tooltip("G is a universal constant like PI that determines how much objects attract each other"); + ImGui::Checkbox("Paused", &m_Paused); Tooltip("Pauses the simulation"); + int count = 0; + for (b2Body* body = m_World->GetWorld()->GetBodyList(); body != nullptr; body = body->GetNext()) + { + count++; + } + + ImGui::Text("%d bodies exist", count); + if (ImGui::Button("Stop all bodies")) + { + m_World->ForEachBody([](b2Body* body) { body->SetLinearVelocity({ 0.0f, 0.0f }); }); + } + if (ImGui::Button("Delete all bodies")) + { + m_World->ForEachBody([this](b2Body* body) { m_World->Remove(World::ToBody(body)); }); + } + ImGui::End(); + + ImGui::Begin("Selected Body"); + if (m_SelectedBody == nullptr) + { + ImGui::Text("No body is currently selected"); + } + else + { + ImGui::Text("mass %.2f kg", m_SelectedBody->GetBody()->GetMass()); + ImGui::Text("speed %.3f m/s", m_SelectedBody->GetBody()->GetLinearVelocity().Length()); + ImGui::Text("speed %.2f rad/s", m_SelectedBody->GetBody()->GetAngularVelocity()); + + if (ImGui::Button("Delete")) + { + m_World->Remove(m_SelectedBody); + } + } + ImGui::End(); +} + + +void SandboxLayer::Render() +{ + m_World->Render(); +} + +SandboxLayer::~SandboxLayer() +{ + +} diff --git a/GameDesign/src/layers/SandboxLayer.h b/GameDesign/src/layers/SandboxLayer.h new file mode 100644 index 0000000..d677b8f --- /dev/null +++ b/GameDesign/src/layers/SandboxLayer.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "../world/World.h" + +class SandboxLayer : public Hazel::Layer +{ +public: + inline SandboxLayer(World* world) : Hazel::Layer("Sandbox Layer") { m_World.reset(world); } + + virtual void OnAttach() override; + virtual void OnDetach() override; + virtual void OnUpdate() override; + + virtual void OnEvent(Hazel::Event* event) override; + + bool OnMouseMoved(Hazel::MouseMovedEvent* event); + bool OnMousePressed(Hazel::MouseButtonPressedEvent* event); + bool OnMouseReleased(Hazel::MouseButtonReleasedEvent* event); + + virtual void OnImGuiRender() override; + virtual void Render() override; + + virtual ~SandboxLayer() override; + +private: + Hazel::Scope m_World; + Body* m_SelectedBody = nullptr; + Body* m_DraggedBody = nullptr; bool m_MouseDragged = false; + bool m_Paused = false; +}; diff --git a/GameDesign/src/layers/WorldLayer.cpp b/GameDesign/src/layers/WorldLayer.cpp index a600f3e..721108e 100644 --- a/GameDesign/src/layers/WorldLayer.cpp +++ b/GameDesign/src/layers/WorldLayer.cpp @@ -1,10 +1,18 @@ #include "WorldLayer.h" #include +#include + void WorldLayer::OnAttach() { - + std::default_random_engine gen; + std::uniform_real_distribution pos(-6.0f, 6.0f); + for (int i = 0; i < 2; i++) + { + Part& part = m_World->AddPart({ pos(gen), pos(gen) }, Parts::MK1Capsule); + + } } void WorldLayer::OnDetach() @@ -22,11 +30,17 @@ void WorldLayer::OnEvent(Hazel::Event* event) } +static bool SliderDouble(const char* label, double* v, double v_min, double v_max, const char* format, double power) +{ + return ImGui::SliderScalar(label, ImGuiDataType_Double, v, &v_min, &v_max, format, power); +} + void WorldLayer::OnImGuiRender() { - ImGui::SliderFloat("G", &World::Constants::G, -0.01f, 10.0f); + SliderDouble("G", &World::Constants::G, -0.01f, 10.0f, "%.5f", 1.0f); } + void WorldLayer::Render() { m_World->Render(); diff --git a/GameDesign/src/ship/Ship.cpp b/GameDesign/src/ship/Ship.cpp new file mode 100644 index 0000000..401ee86 --- /dev/null +++ b/GameDesign/src/ship/Ship.cpp @@ -0,0 +1,35 @@ +#include "Ship.h" +#include "world/World.h" + + +Part::Part(World& world, b2Vec2 pos, const Hazel::Ref& partDef) : m_Def(partDef), m_Animation(partDef->Animation) +{ + b2BodyDef def; + def.position = pos; + def.userData = this; + def.type = b2_dynamicBody; + def.active = true; + m_Body = world.GetWorld()->CreateBody(&def); + + + b2PolygonShape shape; + shape.SetAsBox(partDef->Size.x / 2.0f, partDef->Size.y / 2.0f); + + b2FixtureDef fixtureDef; + fixtureDef.shape = &shape; + fixtureDef.density = partDef->Density; + fixtureDef.friction = 0.2f; + fixtureDef.restitution = 0.1f; + b2Fixture* myFixture = m_Body->CreateFixture(&fixtureDef); +} + +void Part::Render(const World& world) +{ + float x = m_Body->GetPosition().x, y = m_Body->GetPosition().y; + Hazel::Renderer2D::DrawQuad( { x, y }, { m_Def->Size.x, m_Def->Size.y }, m_Animation, m_Body->GetAngle()); +} + +void Part::Update(const World& world) +{ + m_Animation.Update(); +} diff --git a/GameDesign/src/ship/Ship.h b/GameDesign/src/ship/Ship.h new file mode 100644 index 0000000..80b35ad --- /dev/null +++ b/GameDesign/src/ship/Ship.h @@ -0,0 +1,55 @@ +#pragma once +#include "world/Body.h" +#include "Hazel.h" + +#include +#include + +struct PartDef { + PartDef(const char* name, float density, float maxGForce, const Hazel::Ref animation, float realWidth) + : Name(name), Density(density), MaxGForce(maxGForce), Animation(animation) + { + glm::vec2 spriteSize = { animation->m_Frames[0].Bottom - animation->m_Frames[0].Top }; + Size.x = realWidth; + Size.y = realWidth * (spriteSize.y / spriteSize.x); + } + + const char* Name; + float Density; + float MaxGForce; + glm::vec2 Size; + + Hazel::Ref Animation; +}; + +class Part : public Body +{ +public: + Part(World& world, b2Vec2 pos, const Hazel::Ref& partDef); + + virtual void Render(const World& world) override; + virtual void Update(const World& world) override; + + const Hazel::Ref& GetDef() { return m_Def; } + + virtual ~Part() {} + + inline void SetSelected(bool selected) { m_IsSelected = selected; } + inline bool IsSelected() { return m_IsSelected; } + +private: + Hazel::Ref m_Def; + Hazel::Animation2D m_Animation; + bool m_IsSelected = false; +}; + +class Ship +{ +public: + + std::vector& GetParts() { return m_Parts; } + +private: + std::vector m_Parts; +}; + diff --git a/GameDesign/src/world/Body.h b/GameDesign/src/world/Body.h index 18d2de7..a523c97 100644 --- a/GameDesign/src/world/Body.h +++ b/GameDesign/src/world/Body.h @@ -9,14 +9,15 @@ class Body { public: //m_Body must be initalized in the child's constructor - Body() :m_Body(nullptr) {} + Body() : m_Body(nullptr) {} - inline b2Body* GetBody() { return m_Body; } + inline b2Body* GetBody() const { return m_Body; } - inline glm::vec2 GetPosition() { return { m_Body->GetPosition().x, m_Body->GetPosition().y }; } + inline glm::vec2 GetPosition() const { return { m_Body->GetPosition().x, m_Body->GetPosition().y }; } - //Returns the angle in radains - inline float GetRotation() { return m_Body->GetAngle(); } + //Returns the angle in degrees + inline float GetRotation() const { return glm::degrees(m_Body->GetAngle()); } + inline void SetRotation(float degrees) { m_Body->SetTransform(m_Body->GetWorldCenter(), glm::radians(degrees)); } virtual void Render(const World& world) = 0; virtual void Update(const World& world) = 0; diff --git a/GameDesign/src/world/Ship.cpp b/GameDesign/src/world/Ship.cpp deleted file mode 100644 index 4609f81..0000000 --- a/GameDesign/src/world/Ship.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "Ship.h" -#include "World.h" - - -Ship::Ship(World& world, b2Vec2 pos, b2Vec2 size, float density) : m_Size(size) -{ - b2BodyDef def; - def.position = pos; - def.userData = this; - def.type = b2_dynamicBody; - def.active = true; - m_Body = world.GetWorld()->CreateBody(&def); - - - b2PolygonShape shape; - shape.SetAsBox(size.x / 2.0f, size.y / 2.0f); - - b2FixtureDef fixtureDef; - fixtureDef.shape = &shape; - fixtureDef.density = density; - fixtureDef.friction = 0.2f; - b2Fixture* myFixture = m_Body->CreateFixture(&fixtureDef); - - m_Texture = Hazel::Texture2D::Load("assets/textures/RocketComponents.png", Hazel::TextureBuilder::Default().NearestFiltering()); - -} - -void Ship::Render(const World& world) -{ - float x = m_Body->GetPosition().x, y = m_Body->GetPosition().y; - Hazel::Renderer2D::DrawQuad( { x, y, 0.0f }, { m_Size.x, m_Size.y }, m_Texture, m_Body->GetAngle()); -} - -void Ship::Update(const World& world) -{ - -} diff --git a/GameDesign/src/world/Ship.h b/GameDesign/src/world/Ship.h deleted file mode 100644 index 68ff354..0000000 --- a/GameDesign/src/world/Ship.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "Body.h" -#include "Hazel.h" - -#include - - -class Ship : public Body -{ -public: - Ship(World& world, b2Vec2 pos, b2Vec2 size, float density); - - virtual void Render(const World& world) override; - virtual void Update(const World& world) override; - - virtual ~Ship() {} -private: - Hazel::Ref m_Texture; - b2Vec2 m_Size; -}; - diff --git a/GameDesign/src/world/World.cpp b/GameDesign/src/world/World.cpp index 49bdac1..5465bf6 100644 --- a/GameDesign/src/world/World.cpp +++ b/GameDesign/src/world/World.cpp @@ -1,15 +1,25 @@ #include "World.h" -#include "Ship.h" +#include "ship/Ship.h" #include "Planet.h" -#include -float World::Constants::G = 6.67430E-11 * 10000000000.0f; + +double World::Constants::G = 6.67430E-11 * 10000000.0f; +Hazel::Ref Parts::MK1Capsule = nullptr; +Hazel::Ref Parts::FlyingShip = nullptr; +Hazel::Ref Parts::StaticShip = nullptr; + +Hazel::TextureBuilder builder = Hazel::TextureBuilder::Default().NearestFiltering().ClampEdges(); World::World() : m_Camera(new WorldCameraController()) { m_World.reset(new b2World( {0.0f, 0.0f} ));//No gravity since we handle it ourselves + Hazel::Ref RocketComponents = Hazel::Texture2D::Load("assets/textures/RocketComponents.png", builder); + Hazel::Ref DefaultShip = Hazel::Texture2D::Load("assets/textures/Rocket.png", builder); + + Parts::MK1Capsule.reset(new PartDef{ "MK1 Capsule", 1.0f, 15.0f, Hazel::AnimationDef2D::Create(RocketComponents, { 0, 16 }, { 14, 16 }), 1.0f }); + Parts::FlyingShip.reset(new PartDef{ "Flying Ship", 1.5f, 15.0f, Hazel::AnimationDef2D::Create(DefaultShip, 0.2f, {25, 47}, {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}}), 2.0f }); + Parts::StaticShip.reset(new PartDef{ "Ship", 1.5f, 15.0f, Hazel::AnimationDef2D::Create(DefaultShip, {0, 0}, {25, 47}), 2.0f }); - Ship* ship = new Ship(*this, { 0.0f, 0.0f }, { 1.0f, 1.0f }, 10.0f); m_Camera.SetPosition(vec2(0.0, 0.0)); m_Camera.SetRotation(0.0f); m_Camera.SetZoom(10.0f); @@ -28,13 +38,19 @@ void World::Update() { b2Vec2 force = other->GetPosition() - body->GetPosition(); double distance = force.Normalize();// Determine the amount of force to give - force *= (World::Constants::G * body->GetMass() * other->GetMass()) / (distance * distance); + force *= static_cast((World::Constants::G * (double) body->GetMass() * (double) other->GetMass()) / (distance * distance)); body->ApplyForceToCenter(force, true); other->ApplyForceToCenter(-force, true); } } } + body = m_World->GetBodyList(); + for (int i = 0; i < m_World->GetBodyCount(); i++, body = body->GetNext()) + { + Body* myBody = ToBody(body); + myBody->Update(*this); + } m_World->Step(Hazel::Engine::GetDeltaTime(), 10, 10); m_World->ClearForces(); } @@ -51,22 +67,60 @@ void World::Render() Hazel::Renderer2D::EndScene(); } +Part& World::AddPart(b2Vec2 pos, const Hazel::Ref& partDef, float rot) +{ + Ship* ship = new Ship(); + m_Ships.push_back(Hazel::S(ship)); + Part& part = ship->GetParts().emplace_back(*this, pos, partDef); + return part; +} + +void World::Remove(Body* body) +{ + + if(m_OnRemovedFunction) + m_OnRemovedFunction(body); + + m_World->DestroyBody(body->GetBody()); + for (auto& it = m_Ships.begin(); it != m_Ships.end(); it++) + { + Ship* ship = it->get(); + for (auto& it2 = ship->GetParts().begin(); it2 != ship->GetParts().end(); it2++) + { + const Part& part = *it2; + if (part.GetBody() == body->GetBody()) + { + ship->GetParts().erase(it2); + break; + } + } + if (ship->GetParts().empty()) + { + m_Ships.erase(it); + break; + } + } + +} + + const float ACCEL_SPEED = 25.0f; void WorldCameraController::Update(Hazel::Camera2D& camera) { - glm::vec2 move = {0, 0}; + glm::vec2 move = { 0, 0 }; glm::vec2 right = glm::rotate(glm::vec2(1.0f, 0.0f), glm::radians(camera.m_Rot)); glm::vec2 up = glm::rotate(glm::vec2(0.0f, 1.0f), glm::radians(camera.m_Rot)); + bool moving = false; if (Hazel::Input::IsKeyPressed(HZ_KEY_W)) { - move += up; + move += up; moving = true; } if (Hazel::Input::IsKeyPressed(HZ_KEY_S)) { - move -= up; + move -= up; moving = true; } if (Hazel::Input::IsKeyPressed(HZ_KEY_D)) { - move += right; + move += right; moving = true; } if (Hazel::Input::IsKeyPressed(HZ_KEY_A)) { - move -= right; + move -= right; moving = true; } float length = move.length(); if (length > 0.0f) @@ -75,11 +129,14 @@ void WorldCameraController::Update(Hazel::Camera2D& camera) move *= ACCEL_SPEED; } - camera.m_ZoomVel -= Hazel::Input::GetScrollDelta() / 1.0f; + camera.m_ZoomVel -= Hazel::Input::GetScrollDelta() * 3.0f; camera.m_Vel += move * Hazel::Engine::GetDeltaTime(); camera.m_Pos += camera.m_Vel * Hazel::Engine::GetDeltaTime(); - camera.m_Vel *= (1.0f - Hazel::Engine::GetDeltaTime() / 2.0f); + if (!moving) + { + camera.m_Vel *= (1.0f - Hazel::Engine::GetDeltaTime() * 2.0f); + } camera.m_Zoom += camera.m_ZoomVel * Hazel::Engine::GetDeltaTime(); camera.m_ZoomVel *= (1.0f - Hazel::Engine::GetDeltaTime() * 5.0f); @@ -87,4 +144,4 @@ void WorldCameraController::Update(Hazel::Camera2D& camera) if (camera.m_Zoom <= 0.00001f) camera.m_Zoom = 0.00001f; -} +} \ No newline at end of file diff --git a/GameDesign/src/world/World.h b/GameDesign/src/world/World.h index a482384..29a5253 100644 --- a/GameDesign/src/world/World.h +++ b/GameDesign/src/world/World.h @@ -5,7 +5,7 @@ #include #include "Body.h" -#include "Ship.h" +#include "ship/Ship.h" #include "Hazel/Camera/Camera.h" @@ -30,28 +30,54 @@ struct LinkedListIterator }; +class Parts { +public: + static Hazel::Ref MK1Capsule; + static Hazel::Ref FlyingShip; + static Hazel::Ref StaticShip; +}; + class World { public: World(); struct Constants { - static float G; + static double G; }; void Update(); void Render(); + Part& AddPart(b2Vec2 pos, const Hazel::Ref& partDef, float rot = 0.0f); + void Remove(Body* body); + inline LinkedListIterator BodiesBegin() { return m_World->GetBodyList(); } inline LinkedListIterator BodiesEnd() { return nullptr; } inline b2World* GetWorld() { return m_World.get(); } + inline Hazel::Camera2D& GetCamera() { return m_Camera; } + + inline void SetBodyRemovedCallback(std::function func) { m_OnRemovedFunction = func; } + + template + void ForEachBody(T callback) + { + for (b2Body* body = m_World->GetBodyList(); body != nullptr; ) + { + b2Body* next = body->GetNext();//Cache next to allow for deleting bodies here + callback(body); + body = next; + } + } static inline Body* ToBody(b2Body* body) { return reinterpret_cast(body->GetUserData()); } private: + std::vector> m_Ships; Hazel::Scope m_World; Hazel::Camera2D m_Camera; + std::function m_OnRemovedFunction; }; class WorldCameraController : public Hazel::CameraController2D diff --git a/Hazel/src/Hazel/Camera/Camera.h b/Hazel/src/Hazel/Camera/Camera.h index d07c77f..21a402e 100644 --- a/Hazel/src/Hazel/Camera/Camera.h +++ b/Hazel/src/Hazel/Camera/Camera.h @@ -88,6 +88,25 @@ namespace Hazel { m_ViewMatrix = inverse(transform); } + inline glm::vec2 ToWorldCoordinates(glm::ivec2 screenPos) + { + screenPos.y = Application::Get().GetWindow().GetHeight() - screenPos.y - 1; + screenPos -= glm::ivec2(Application::Get().GetWindow().GetWidth() / 2, Application::Get().GetWindow().GetHeight() / 2 ); + //([-width/2, width/2], [-height/2, height/2]) + + float halfHeight = Application::Get().GetWindow().GetHeight() / 2.0f; + glm::vec2 result = glm::vec2(screenPos) / glm::vec2(halfHeight); + //([-aspect, aspect], [-1, 1]) + + result *= m_Zoom;//Account for zoom + return result; + } + + inline glm::vec2 GetWorldDelta(glm::ivec2 delta) + { + return ToWorldCoordinates(delta) - ToWorldCoordinates({ 0, 0 }); + } + public: mat4 m_ProjectionMatrix; mat4 m_ViewMatrix; diff --git a/Hazel/src/Hazel/Core/Core.h b/Hazel/src/Hazel/Core/Core.h index 9d25a4f..7dbb6f0 100644 --- a/Hazel/src/Hazel/Core/Core.h +++ b/Hazel/src/Hazel/Core/Core.h @@ -31,6 +31,7 @@ #elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) #define HZ_PLATFORM_WINDOWS + #define HZ_LITTLE_ENDIAN #elif defined(__APPLE__) || defined(__MACH__) #include @@ -56,6 +57,7 @@ #elif defined(__linux__)//Defined after android to target desktop linux #define HZ_PLATFORM_UNIX #define HZ_PLATFORM_LINUX + #define HZ_LITTLE_ENDIAN #else #error Unknown platform #endif diff --git a/Hazel/src/Hazel/Core/Input.h b/Hazel/src/Hazel/Core/Input.h index 14b4463..cc97f1d 100644 --- a/Hazel/src/Hazel/Core/Input.h +++ b/Hazel/src/Hazel/Core/Input.h @@ -17,6 +17,7 @@ namespace Hazel { static inline glm::vec2 GetMousePosition() { return s_MousePos; } static inline glm::vec2 GetMouseDelta() { return s_MouseDelta; } + static bool DidMouseMove(); static void NextFrame(); private: static glm::vec2 s_MousePos, s_LastMousePos, s_MouseDelta, s_ScrollDelta; diff --git a/Hazel/src/Hazel/Renderer/Texture.h b/Hazel/src/Hazel/Renderer/Texture.h index 28d6225..ec0d1d8 100644 --- a/Hazel/src/Hazel/Renderer/Texture.h +++ b/Hazel/src/Hazel/Renderer/Texture.h @@ -74,7 +74,7 @@ namespace Hazel { class Texture2D { public: - inline Texture2D() : Texture2D(INVALID_LENGTH, INVALID_LENGTH) {} + inline explicit Texture2D() : Texture2D(INVALID_LENGTH, INVALID_LENGTH) {} inline Texture2D(uint32_t width, uint32_t height) : m_Width(width), m_Height(height) {} static Ref Load(Path path, TextureBuilder builder = TextureBuilder::Default()); diff --git a/Hazel/src/Hazel/Renderer2D/Animation2D.cpp b/Hazel/src/Hazel/Renderer2D/Animation2D.cpp new file mode 100644 index 0000000..8aebb9f --- /dev/null +++ b/Hazel/src/Hazel/Renderer2D/Animation2D.cpp @@ -0,0 +1,74 @@ +#include "hzpch.h" +#include "Animation2D.h" + +#include "Hazel/Core/Engine.h" + +namespace Hazel { + + const int TEMP_FRAME_COUNT = 1000; + static Frame s_TempFrames[TEMP_FRAME_COUNT]; + + Ref AnimationDef2D::Create(Ref texture, glm::ivec2 top, glm::ivec2 size) + { + AnimationDef2D* result = new AnimationDef2D(); + result->m_Texture = texture; + result->m_Frames = { {top, top + size, 0.0f} }; + + return Hazel::R(result); + } + + Ref AnimationDef2D::Create(Ref texture, float frameDuration, glm::ivec2 spriteSize, std::initializer_list spriteCoordinates) + { + if (spriteCoordinates.size() > TEMP_FRAME_COUNT) + HZ_CORE_ASSERT(false, "Too many frames!"); + + const glm::ivec2* spriteCoords = spriteCoordinates.begin(); + for (int i = 0; i < spriteCoordinates.size(); i++) + { + s_TempFrames[i].Duration = frameDuration; + s_TempFrames[i].Top = spriteSize * spriteCoords[i]; + //The bottom corner of the texture coordinates is the next sprite over + s_TempFrames[i].Bottom = spriteSize * spriteCoords[i] + spriteSize; + } + AnimationDef2D* result = new AnimationDef2D(); + result->m_Texture = texture; + result->m_Frames = std::vector(std::initializer_list(s_TempFrames, s_TempFrames + spriteCoordinates.size())); + + return Hazel::R(result); + } + + + + + void Animation2D::Update() + { + float timestep = Engine::GetDeltaTime() + m_InFrameFor; + bool advance = true; + + if (m_Def->m_Frames.size() == 1)// Always display the only frame + advance = false; + if (m_CurrentFrame == (m_Def->m_Frames.size() - 1) && !m_RepeatOnEnd)// Stay on the last frame + advance = false; + + if (advance) + { + while (timestep >= m_Def->m_Frames[m_CurrentFrame].Duration) + { + timestep -= m_Def->m_Frames[m_CurrentFrame].Duration; + m_CurrentFrame++;// Advance to the next frame + + if (m_CurrentFrame == m_Def->m_Frames.size()) + { + if (m_RepeatOnEnd) m_CurrentFrame = 0; + else break; + } + + } + + } + m_InFrameFor = timestep; + + } + +} + diff --git a/Hazel/src/Hazel/Renderer2D/Animation2D.h b/Hazel/src/Hazel/Renderer2D/Animation2D.h new file mode 100644 index 0000000..09b4e7a --- /dev/null +++ b/Hazel/src/Hazel/Renderer2D/Animation2D.h @@ -0,0 +1,53 @@ +#pragma once + +#include "Hazel/Renderer/Texture.h" +#include "Hazel/Core/Core.h" +#include "Hazel/Core/glm.h" + +namespace Hazel { + + struct Frame + { + glm::ivec2 Top; + glm::ivec2 Bottom; + float Duration; + }; + + struct AnimationDef2D + { + Ref m_Texture; + std::vector m_Frames; + + static Ref Create(Ref texture, glm::ivec2 top, glm::ivec2 size); + static Ref Create(Ref texture, float frameDuration, glm::ivec2 spriteSize, std::initializer_list spriteCoordinates); + + }; + + class Animation2D + { + public: + + Animation2D(const Ref& def) : m_Def(def) { } + + //Must be called every frame to update the animation + //Advanced m_CurrentFrame if neccsarry + void Update(); + + inline void RepeatOnEnd() { m_RepeatOnEnd = true; } + inline void StopOnEnd() { m_RepeatOnEnd = false; } + + inline const Ref& GetTexture() const { return m_Def->m_Texture; } + + inline const Frame& GetFrame() const { return m_Def->m_Frames[m_CurrentFrame]; } + + private: + Ref m_Def; + + float m_InFrameFor = 0.0f; + int m_CurrentFrame = 0; + bool m_RepeatOnEnd = true; + + }; + + +} \ No newline at end of file diff --git a/Hazel/src/Hazel/Renderer2D/Renderer2D.cpp b/Hazel/src/Hazel/Renderer2D/Renderer2D.cpp index c224101..3f3c64b 100644 --- a/Hazel/src/Hazel/Renderer2D/Renderer2D.cpp +++ b/Hazel/src/Hazel/Renderer2D/Renderer2D.cpp @@ -12,7 +12,8 @@ namespace Hazel { - struct VertexData { + struct VertexData + { glm::vec3 Position; glm::vec2 TexCoord; glm::vec4 Color; @@ -25,35 +26,55 @@ namespace Hazel { const uint32_t VERTEX_BUFFER_SIZE = SPRITE_SIZE * MAX_SPRITES; const uint32_t INDEX_BUFFER_COUNT = 6 * MAX_SPRITES; - struct Renderer2DStorage + struct PerTextureData { Ref VertexArray; - Ref IndexBuffer; - Ref VertexBuffer; - VertexData* MapedVertexBuffer; uint32_t IndexCount = 0, VertexCount = 0; - Ref TextureShader; + VertexData Vertices[MAX_VERTICES]; + Ref Texture; + }; + + + struct Renderer2DStorage + { + Ref IndexBuffer; + Ref TextureShader; + + std::unordered_map> DataMap; }; static Renderer2DStorage* s_Data; - void Renderer2D::Init() + static PerTextureData* InitForTexture(const Ref& texture) { - s_Data = new Renderer2DStorage(); - s_Data->VertexArray = VertexArray::Create(); + PerTextureData* data = new PerTextureData(); + data->Texture = texture; + + data->VertexArray = VertexArray::Create(); - s_Data->VertexBuffer = VertexBuffer::CreateVertex(VERTEX_BUFFER_SIZE); + data->VertexBuffer = VertexBuffer::CreateVertex(VERTEX_BUFFER_SIZE); - s_Data->VertexBuffer->SetLayout({ + data->VertexBuffer->SetLayout({ { ShaderDataType::Float3, "a_Position" }, { ShaderDataType::Float2, "a_TexCoord" }, { ShaderDataType::Float4, "a_Color" }, }); - s_Data->VertexArray->AddVertexBuffer(s_Data->VertexBuffer); + data->VertexArray->AddVertexBuffer(data->VertexBuffer); + + data->VertexArray->SetIndexBuffer(s_Data->IndexBuffer); + + data->VertexArray->Unbind(); + + return data; + } + + void Renderer2D::Init() + { + s_Data = new Renderer2DStorage(); uint32_t indices[INDEX_BUFFER_COUNT]; uint32_t offset = 0; @@ -71,9 +92,6 @@ namespace Hazel { } s_Data->IndexBuffer = IndexBuffer::Create(indices, sizeof(indices)); - s_Data->VertexArray->SetIndexBuffer(s_Data->IndexBuffer); - - s_Data->VertexArray->Unbind(); s_Data->TextureShader = Shader::Create("assets/shaders/Texture.glsl"); } @@ -83,98 +101,86 @@ namespace Hazel { delete s_Data; } - static void BeginBatch() - { - // Prepares the render's state to render a new batch of sprites - s_Data->MapedVertexBuffer = reinterpret_cast(s_Data->VertexBuffer->Map(MapAccess::WRITE_ONLY)); - s_Data->VertexCount = 0; - s_Data->IndexCount = 0; - } - void Renderer2D::BeginScene(const Camera2D& cam) { s_Data->TextureShader->Bind(); s_Data->TextureShader->SetMat4("u_ViewProjection", cam.GetViewProjectionMatrix()); - - s_Data->VertexBuffer->Bind(); - s_Data->VertexArray->Bind(); - BeginBatch(); } - static void Flush(bool reBind) + static void Flush(PerTextureData* data) { - s_Data->VertexBuffer->Unmap(s_Data->MapedVertexBuffer); - s_Data->Texture->Bind(); + data->VertexBuffer->Bind(); + data->VertexArray->Bind(); - RenderCommand::DrawIndexed(s_Data->VertexArray, s_Data->IndexCount); - if (reBind) - BeginBatch(); - } + VertexData* glData = reinterpret_cast(data->VertexBuffer->Map(MapAccess::WRITE_ONLY)); + std::copy(data->Vertices, data->Vertices + data->VertexCount, glData); + data->VertexBuffer->Unmap(glData); - void Renderer2D::EndScene() - { - Flush(false); - } + data->Texture->Bind(); - - - void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref& texture, float rotation) - { - DrawQuad({ position.x, position.y, 0.0f }, size, texture, rotation); + RenderCommand::DrawIndexed(data->VertexArray, data->IndexCount); + data->IndexCount = 0; + data->VertexCount = 0; } - void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref& texture, float rotation) + void Renderer2D::EndScene() { - DrawQuad(position, size, { 0.0f, 0.0f }, { 1.0f, 1.0f }, texture, {1.0f, 1.0f, 1.0f, 1.0f}, rotation); + for (auto& it = s_Data->DataMap.begin(); it != s_Data->DataMap.end(); it++) + { + PerTextureData* data = it->second.get(); + Flush(data); + } } - void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color, float rotation) - { - DrawQuad({ position.x, position.y, 0.0f }, size, textureTop, textureBottom, texture, color, rotation); - } - void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color, float rotation) + void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color, float degrees) { - if (s_Data->Texture != texture) + PerTextureData* data; + if (s_Data->DataMap.find(texture.get()) == s_Data->DataMap.end()) + { + data = InitForTexture(texture); + s_Data->DataMap[texture.get()] = Hazel::S(data); + } + else { - HZ_CORE_WARN("Cannot use more than one texture!"); + data = s_Data->DataMap.find(texture.get())->second.get(); } - if (s_Data->VertexCount >= MAX_VERTICES) + if (data->VertexCount >= MAX_VERTICES) { HZ_CORE_INFO("FLUSHING!"); - Flush(true); + Flush(data); } - s_Data->Texture = texture; glm::vec2 halfSize = size / 2.0f; glm::vec2 v1 = { -halfSize.x, -halfSize.y }, v2 = { -halfSize.x, +halfSize.y }, v3 = { +halfSize.x, +halfSize.y }, v4 = { +halfSize.x, -halfSize.y }; + float rotation = glm::radians(degrees); v1 = glm::rotate(v1, rotation); v2 = glm::rotate(v2, rotation); v3 = glm::rotate(v3, rotation); v4 = glm::rotate(v4, rotation); - s_Data->MapedVertexBuffer[s_Data->VertexCount].Position = { v1.x + position.x, v1.y + position.y, position.z }; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Color = color; - s_Data->MapedVertexBuffer[s_Data->VertexCount].TexCoord = textureTop; - s_Data->VertexCount++; + data->Vertices[data->VertexCount].Position = { v1.x + position.x, v1.y + position.y, position.z }; + data->Vertices[data->VertexCount].Color = color; + data->Vertices[data->VertexCount].TexCoord = textureTop; + data->VertexCount++; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Position = { v2.x + position.x, v2.y + position.y, position.z }; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Color = color; - s_Data->MapedVertexBuffer[s_Data->VertexCount].TexCoord = { textureTop.x, textureBottom.y }; - s_Data->VertexCount++; + data->Vertices[data->VertexCount].Position = { v2.x + position.x, v2.y + position.y, position.z }; + data->Vertices[data->VertexCount].Color = color; + data->Vertices[data->VertexCount].TexCoord = { textureTop.x, textureBottom.y }; + data->VertexCount++; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Position = { v3.x + position.x, v3.y + position.y, position.z }; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Color = color; - s_Data->MapedVertexBuffer[s_Data->VertexCount].TexCoord = textureBottom; - s_Data->VertexCount++; + data->Vertices[data->VertexCount].Position = { v3.x + position.x, v3.y + position.y, position.z }; + data->Vertices[data->VertexCount].Color = color; + data->Vertices[data->VertexCount].TexCoord = textureBottom; + data->VertexCount++; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Position = { v4.x + position.x, v4.y + position.y, position.z }; - s_Data->MapedVertexBuffer[s_Data->VertexCount].Color = color; - s_Data->MapedVertexBuffer[s_Data->VertexCount].TexCoord = { textureBottom.x, textureTop.y }; - s_Data->VertexCount++; + data->Vertices[data->VertexCount].Position = { v4.x + position.x, v4.y + position.y, position.z }; + data->Vertices[data->VertexCount].Color = color; + data->Vertices[data->VertexCount].TexCoord = { textureBottom.x, textureTop.y }; + data->VertexCount++; - s_Data->IndexCount += 6; + data->IndexCount += 6; } } diff --git a/Hazel/src/Hazel/Renderer2D/Renderer2D.h b/Hazel/src/Hazel/Renderer2D/Renderer2D.h index 9e838a5..97cfb12 100644 --- a/Hazel/src/Hazel/Renderer2D/Renderer2D.h +++ b/Hazel/src/Hazel/Renderer2D/Renderer2D.h @@ -3,6 +3,7 @@ #include "Hazel/Camera/Camera.h" #include "Hazel/Renderer/Texture.h" +#include "Hazel/Renderer2D/Animation2D.h" namespace Hazel { @@ -16,11 +17,23 @@ namespace Hazel { static void EndScene(); // Primitives - static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref& texture, float rotation = 0.0f); - static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref& texture, float rotation = 0.0f); - static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color = {1.0f, 1.0f , 1.0f , 1.0f }, float rotation = 0.0f); - static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color = { 1.0f, 1.0f , 1.0f , 1.0f }, float rotation = 0.0f); + inline static void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Animation2D& animation, float degrees) + { + const Frame& frame = animation.GetFrame(); + glm::vec2 textureSize = { animation.GetTexture()->GetWidth(), animation.GetTexture()->GetHeight() }; + + glm::vec2 top = glm::vec2(frame.Top.x, frame.Top.y) / textureSize; + glm::vec2 bottom = glm::vec2(frame.Bottom.x, frame.Bottom.y) / textureSize; + DrawQuad({ position.x, position.y, 0.0f }, size, top, bottom, animation.GetTexture(), { 1.0f, 1.0f, 1.0f, 1.0f }, degrees); + } + + + inline static void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref& texture, float degrees) { DrawQuad({ position.x, position.y, 0.0f }, size, texture, degrees); } + inline static void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref& texture, float degrees) { DrawQuad(position, size, { 0.0f, 0.0f }, { 1.0f, 1.0f }, texture, { 1.0f, 1.0f, 1.0f, 1.0f }, degrees); } + inline static void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color, float degrees) { DrawQuad({ position.x, position.y, 0.0f }, size, textureTop, textureBottom, texture, color, degrees); } + + static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec2& textureTop, const glm::vec2& textureBottom, const Ref& texture, const glm::vec4& color = { 1.0f, 1.0f , 1.0f , 1.0f }, float degrees = 0.0f); }; } diff --git a/Hazel/src/Platform/GLFW/GLFWInput.cpp b/Hazel/src/Platform/GLFW/GLFWInput.cpp index 8dd29ef..061dde0 100644 --- a/Hazel/src/Platform/GLFW/GLFWInput.cpp +++ b/Hazel/src/Platform/GLFW/GLFWInput.cpp @@ -45,6 +45,11 @@ namespace Hazel { return { (float)xpos, (float)ypos }; } + bool Input::DidMouseMove() + { + return s_MouseDelta.x || s_MouseDelta.y; + } + void Input::NextFrame() { HZ_PROFILE_FUNCTION(); diff --git a/Hazel/src/Platform/NoAPI/NoAPI.h b/Hazel/src/Platform/NoAPI/NoAPI.h index 382e469..4f97248 100644 --- a/Hazel/src/Platform/NoAPI/NoAPI.h +++ b/Hazel/src/Platform/NoAPI/NoAPI.h @@ -129,9 +129,9 @@ namespace Hazel { class NoAPITexture2D : public Texture2D { public: - NoAPITexture2D(File* file, const TextureBuilder& builder) {} - NoAPITexture2D(int width, int height, const TextureBuilder& builder) {} - NoAPITexture2D(int width, int height, void* data, TextureFormat format, TextureBuilder builder) {} + NoAPITexture2D(File* file, const TextureBuilder& builder) : Texture2D(-1, -1) {} + NoAPITexture2D(int width, int height, const TextureBuilder& builder) : Texture2D(-1, -1) {} + NoAPITexture2D(int width, int height, void* data, TextureFormat format, TextureBuilder builder) : Texture2D(-1, -1) {} virtual void SetPixels(void* pixels, TextureFormat format) override {} diff --git a/Hazel/src/Platform/OpenGL/OpenGLUtils.cpp b/Hazel/src/Platform/OpenGL/OpenGLUtils.cpp index 01f928e..3bf2cb4 100644 --- a/Hazel/src/Platform/OpenGL/OpenGLUtils.cpp +++ b/Hazel/src/Platform/OpenGL/OpenGLUtils.cpp @@ -243,6 +243,7 @@ namespace Hazel { HZ_PROFILE_SCOPE("glGenerateMipmap"); glGenerateMipmap(GL_TEXTURE_2D); } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); if (builder.IsAnisotropic()) { diff --git a/premake5.lua b/premake5.lua index a717265..784179f 100644 --- a/premake5.lua +++ b/premake5.lua @@ -282,6 +282,7 @@ project "GameDesign" includedirs { + "%{prj.name}/src/", "Hazel/vendor/spdlog/include", "Hazel/src", "Hazel/vendor",