Added Editor Camera

This commit is contained in:
OusmBlueNinja 2025-04-12 21:01:08 -05:00
parent ae7a8b2b29
commit a71d221ad9
9 changed files with 270 additions and 151 deletions

View File

@ -1,5 +1,5 @@
[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Engine.cpp -o src\build\src\Engine.osrc\src\Engine.cpp:23:9: warning: "NOMINMAX" redefined
23 | #define NOMINMAX
[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Engine.cpp -o src\build\src\Engine.osrc\src\Engine.cpp:24:9: warning: "NOMINMAX" redefined
24 | #define NOMINMAX
| ^~~~~~~~
In file included from C:/msys64/mingw64/include/c++/14.2.0/x86_64-w64-mingw32/bits/c++config.h:680,
from C:/msys64/mingw64/include/c++/14.2.0/bits/memoryfwd.h:48,
@ -11,32 +11,30 @@ C:/msys64/mingw64/include/c++/14.2.0/x86_64-w64-mingw32/bits/os_defines.h:45:9:
| ^~~~~~~~
In file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13,
from C:/msys64/mingw64/include/yaml-cpp/yaml.h:10,
from src\src\Entitys/Object.h:6,
from src\src\Entitys/Object.h:7,
from src\src\Engine.cpp:2:
C:/msys64/mingw64/include/yaml-cpp/dll.h:22:65: note: '#pragma message: Defining YAML_CPP_API for DLL import'
22 | # pragma message( "Defining YAML_CPP_API for DLL import" )
| ^
[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Entitys\Object.cpp -o src\build\src\Entitys\Object.oIn file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13,
[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Renderer.cpp -o src\build\src\Renderer.oIn file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13,
from C:/msys64/mingw64/include/yaml-cpp/yaml.h:10,
from src\src\Entitys\Object.h:6,
from src\src\Entitys\Object.cpp:1:
from src\src\Components/Component.h:5,
from src\src\Components/SpriteComponent.h:3,
from src\src\Renderer.cpp:2:
C:/msys64/mingw64/include/yaml-cpp/dll.h:22:65: note: '#pragma message: Defining YAML_CPP_API for DLL import'
22 | # pragma message( "Defining YAML_CPP_API for DLL import" )
| ^
src\src\Entitys\Object.h: In constructor 'Object::Object(const std::string&)':
src\src\Entitys\Object.h:48:15: warning: 'Object::localPosition' will be initialized after [-Wreorder]
48 | glm::vec2 localPosition;
| ^~~~~~~~~~~~~
src\src\Entitys\Object.h:41:9: warning: 'int Object::id' [-Wreorder]
41 | int id;
| ^~
src\src\Entitys\Object.cpp:10:1: warning: when initialized here [-Wreorder]
10 | Object::Object(const std::string& name)
| ^~~~~~
[LINK] g++ src\build\src\Engine.o src\build\src\main.o src\build\src\Renderer.o src\build\src\Components\SpriteComponent.o src\build\src\Entitys\Object.o src\build\src\utils\FileDialog.o src\build\src\utils\Shader.o src\build\vendor\imgui\imgui.o src\build\vendor\imgui\imgui_demo.o src\build\vendor\imgui\imgui_draw.o src\build\vendor\imgui\imgui_impl_glfw.o src\build\vendor\imgui\imgui_impl_opengl3.o src\build\vendor\imgui\imgui_tables.o src\build\vendor\imgui\imgui_widgets.o -o src\build\app.exe -LC:/msys64/mingw64/lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Components\CameraComponent.cpp -o src\build\src\Components\CameraComponent.oIn file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13,
from C:/msys64/mingw64/include/yaml-cpp/yaml.h:10,
from src\src\Components\Component.h:5,
from src\src\Components\CameraComponent.h:2,
from src\src\Components\CameraComponent.cpp:1:
C:/msys64/mingw64/include/yaml-cpp/dll.h:22:65: note: '#pragma message: Defining YAML_CPP_API for DLL import'
22 | # pragma message( "Defining YAML_CPP_API for DLL import" )
| ^
[TIME] Build duration: 9.21s
[RUN] Executed app.exe successfully.
[TIME] Total runtime: 55.09s
[LINK] g++ src\build\src\Engine.o src\build\src\main.o src\build\src\Renderer.o src\build\src\Components\CameraComponent.o src\build\src\Components\SpriteComponent.o src\build\src\Entitys\Object.o src\build\src\utils\FileDialog.o src\build\src\utils\Shader.o src\build\vendor\imgui\imgui.o src\build\vendor\imgui\imgui_demo.o src\build\vendor\imgui\imgui_draw.o src\build\vendor\imgui\imgui_impl_glfw.o src\build\vendor\imgui\imgui_impl_opengl3.o src\build\vendor\imgui\imgui_tables.o src\build\vendor\imgui\imgui_widgets.o -o src\build\app.exe -LC:/msys64/mingw64/lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
[TIME] Build duration: 11.26s

View File

@ -1,12 +1,41 @@
engine_version: 0.1.0
scene_name: test
scene_hash: 2bef506b8552068aab28115edf9550411c1fab67befdc32a4946ec33da7a8021
scene_hash: b3488ddfbb343e554cb1782c1b79598e15545d752cfec63be97f90c8d422aaf5
format_version: 1
objects:
- name: Face Image
position: [0, 0]
- name: Sprite Object
position: [438, 0]
layer: 0
components:
- type: CameraComponent
fov: 45
aspect: 1.76999998
zoom: 1
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: ""
children:
- name: NewObject
position: [190, 189]
layer: 0
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: ""
children: []
- name: NewObject
position: [0, 444]
layer: 0
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: ""
children: []
- name: NewObject
position: [0, 444]
layer: 0
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: ""
children: []

View File

@ -1,19 +1,29 @@
#include "CameraComponent.h"
#include "../Entitys/Object.h"
CameraComponent::CameraComponent(Object* owner)
: Component(owner) {}
CameraComponent::CameraComponent(Object* owner) : Component(owner) {}
void CameraComponent::Save(YAML::Emitter& out) {
std::string CameraComponent::GetName() const {
return "CameraComponent";
}
void CameraComponent::Save(YAML::Emitter& out) const {
out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << "CameraComponent";
out << YAML::Key << "zoom" << YAML::Value << zoom;
out << YAML::Key << "aspectRatio" << YAML::Value << aspectRatio;
out << YAML::Key << "type" << YAML::Value << GetName();
out << YAML::Key << "fov" << YAML::Value << fov;
out << YAML::Key << "aspect" << YAML::Value << aspect;
out << YAML::Key << "zoom" << YAML::Value << zoom;
out << YAML::Key << "primary" << YAML::Value << primary;
out << YAML::EndMap;
}
void CameraComponent::Load(const YAML::Node& node) {
zoom = node["zoom"] ? node["zoom"].as<float>() : 1.0f;
aspectRatio = node["aspectRatio"] ? node["aspectRatio"].as<float>() : 16.0f / 9.0f;
fov = node["fov"] ? node["fov"].as<float>() : 45.0f;
if (node["fov"]) fov = node["fov"].as<float>();
if (node["aspect"]) aspect = node["aspect"].as<float>();
if (node["zoom"]) zoom = node["zoom"].as<float>();
if (node["primary"]) primary = node["primary"].as<bool>();
}

View File

@ -1,24 +1,35 @@
#pragma once
#include "Component.h"
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
class CameraComponent : public Component {
public:
float zoom = 1.0f;
float aspectRatio = 16.0f / 9.0f;
float fov = 45.0f;
CameraComponent(Object* owner);
void Save(YAML::Emitter& out) override;
std::string GetName() const override;
void Save(YAML::Emitter& out) const override;
void Load(const YAML::Node& node) override;
float GetZoom() const { return zoom; }
float GetAspectRatio() const { return aspectRatio; }
float GetAspect() const { return aspect; }
float GetFOV() const { return fov; }
bool IsPrimary() const { return primary; }
void SetZoom(float z) { zoom = z; }
void SetAspectRatio(float a) { aspectRatio = a; }
void SetAspect(float a) { aspect = a; }
void SetFOV(float f) { fov = f; }
void SetPrimary(bool p) { primary = p; }
private:
float zoom = 1.0f;
float fov = 45.0f;
float aspect = 1.77f;
bool primary = true;
};

View File

@ -2,6 +2,8 @@
#include "Entitys/Object.h"
#include "Renderer.h"
#include "components/SpriteComponent.h"
#include "components/CameraComponent.h"
#include "utils/FileDialog.h"
#include <GL/glew.h>
@ -10,7 +12,6 @@
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <functional>
#include <fstream>
#include <sstream>
@ -28,6 +29,36 @@
static std::vector<std::shared_ptr<Object>> objects;
static std::shared_ptr<Object> selected = nullptr;
static bool playing = false;
struct EditorCamera
{
glm::vec2 position = glm::vec2(0.0f);
float zoom = 1.0f;
void HandleInput()
{
if (ImGui::IsWindowHovered())
{
if (ImGui::IsMouseDragging(ImGuiMouseButton_Right))
{
ImVec2 delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Right);
position -= glm::vec2(delta.x, -delta.y) / zoom;
}
float wheel = ImGui::GetIO().MouseWheel;
if (wheel != 0.0f)
{
float zoomFactor = 1.1f;
zoom *= (wheel > 0) ? zoomFactor : (1.0f / zoomFactor);
zoom = std::clamp(zoom, 0.1f, 10.0f);
}
}
}
};
static EditorCamera editorCamera;
GLFWwindow *window = nullptr;
Engine::Engine()
@ -106,8 +137,6 @@ void Engine::Run()
ImGui::Begin("Scene Tree");
if (ImGui::BeginPopupContextWindow("SceneTreeContext", ImGuiPopupFlags_MouseButtonRight))
{
if (ImGui::MenuItem("Create New Object"))
@ -129,16 +158,11 @@ void Engine::Run()
}
ImGui::EndPopup();
}
for (auto &obj : objects)
if (!obj->GetParent()) // Only draw root nodes
DrawObjectNode(obj);
ImGui::End();
ImGui::Begin("Inspector");
@ -155,13 +179,20 @@ void Engine::Run()
ImGui::InputInt("Layer", &selected->layer);
// Add component
// Add SpriteComponent
if (ImGui::Button("Add SpriteComponent"))
{
if (!selected->GetComponent<SpriteComponent>())
selected->AddComponent<SpriteComponent>();
}
// Add CameraComponent
if (ImGui::Button("Add CameraComponent"))
{
if (!selected->GetComponent<CameraComponent>())
selected->AddComponent<CameraComponent>();
}
// Show SpriteComponent UI
if (auto sprite = selected->GetComponent<SpriteComponent>())
{
@ -192,6 +223,29 @@ void Engine::Run()
selected->RemoveComponent<SpriteComponent>();
}
}
// Show CameraComponent UI
if (auto cam = selected->GetComponent<CameraComponent>())
{
ImGui::Separator();
ImGui::Text("Camera Component");
float fov = cam->GetFOV();
float aspect = cam->GetAspect();
float zoom = cam->GetZoom();
if (ImGui::DragFloat("FOV", &fov, 0.1f, 1.0f, 179.0f))
cam->SetFOV(fov);
if (ImGui::DragFloat("Aspect", &aspect, 0.01f, 0.1f, 5.0f))
cam->SetAspect(aspect);
if (ImGui::DragFloat("Zoom", &zoom, 0.1f, 0.1f, 10.0f))
cam->SetZoom(zoom);
if (ImGui::Button("Remove CameraComponent"))
{
selected->RemoveComponent<CameraComponent>();
}
}
}
else
{
@ -199,67 +253,91 @@ void Engine::Run()
}
ImGui::End();
// Viewport
ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
ImVec2 size = ImGui::GetContentRegionAvail();
if (!playing)
editorCamera.HandleInput();
glm::vec2 cameraOffset = editorCamera.position;
float camZoom = editorCamera.zoom;
if (playing)
{
for (const auto &obj : objects)
{
if (auto cam = obj->GetComponent<CameraComponent>())
{
if (cam->IsPrimary())
{
cameraOffset = obj->GetWorldPosition();
camZoom = cam->GetZoom();
break;
}
}
}
}
Renderer::Resize((int)size.x, (int)size.y);
Renderer::Begin();
std::vector<std::shared_ptr<Object>> toDraw;
std::function<void(const std::shared_ptr<Object>&)> collect = [&](const std::shared_ptr<Object>& obj) {
std::function<void(const std::shared_ptr<Object> &)> collect = [&](const std::shared_ptr<Object> &obj)
{
toDraw.push_back(obj);
for (const auto& child : obj->GetChildren())
for (const auto &child : obj->GetChildren())
collect(child);
};
for (const auto& obj : objects)
for (const auto &obj : objects)
if (!obj->GetParent())
collect(obj);
std::sort(toDraw.begin(), toDraw.end(), [](const auto& a, const auto& b) {
return a->layer < b->layer;
});
for (const auto& obj : toDraw) {
if (auto sprite = obj->GetComponent<SpriteComponent>()) {
Renderer::DrawSprite(sprite.get(), obj->GetWorldPosition());
std::sort(toDraw.begin(), toDraw.end(), [](const auto &a, const auto &b)
{ return a->layer < b->layer; });
for (const auto &obj : toDraw)
{
if (auto sprite = obj->GetComponent<SpriteComponent>())
{
glm::vec2 renderPos = (obj->GetWorldPosition() - cameraOffset) * camZoom;
Renderer::DrawSprite(sprite.get(), renderPos, camZoom);
}
}
Renderer::End();
GLuint texID = Renderer::GetRenderTexture();
ImGui::Image((ImTextureID)(uintptr_t)texID, size, ImVec2(0, 1), ImVec2(1, 0));
ImGui::End();
if (ImGui::BeginPopup("RenameObject")) {
if (ImGui::BeginPopup("RenameObject"))
{
static char nameBuffer[128];
static bool once = true;
if (once && selected) {
if (once && selected)
{
strcpy(nameBuffer, selected->GetName().c_str());
once = false;
}
ImGui::InputText("##rename", nameBuffer, sizeof(nameBuffer));
if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::Button("OK")) {
if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::Button("OK"))
{
if (selected)
selected->SetName(nameBuffer);
ImGui::CloseCurrentPopup();
once = true;
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
if (ImGui::Button("Cancel"))
{
ImGui::CloseCurrentPopup();
once = true;
}
ImGui::EndPopup();
}

View File

@ -1,14 +1,14 @@
#include "Object.h"
#include "../Components/SpriteComponent.h"
#include "../Components/Component.h"
#include "../Components/SpriteComponent.h"
#include "../Components/CameraComponent.h"
#include <algorithm>
static int nextID = 0;
Object::Object(const std::string& name)
: name(name), localPosition(0.0f, 0.0f), id(nextID++), layer(1) {}
: name(name), localPosition(0.0f, 0.0f), id(nextID++) {}
Object::~Object() {}
@ -49,79 +49,48 @@ void Object::SetName(const std::string& n) { name = n; }
std::vector<std::shared_ptr<Object>>& Object::GetChildren() { return children; }
Object* Object::GetParent() const { return parent; }
// === Component System ===
template<typename T>
std::shared_ptr<T> Object::GetComponent() const {
for (const auto& comp : components) {
if (auto casted = std::dynamic_pointer_cast<T>(comp))
return casted;
}
return nullptr;
}
template<typename T>
std::shared_ptr<T> Object::AddComponent() {
auto existing = GetComponent<T>();
if (existing) return existing;
std::shared_ptr<T> component = std::make_shared<T>(this);
components.push_back(component);
return component;
}
template<typename T>
void Object::RemoveComponent() {
components.erase(std::remove_if(components.begin(), components.end(),
[](const std::shared_ptr<Component>& comp) {
return std::dynamic_pointer_cast<T>(comp) != nullptr;
}), components.end());
}
// Explicit template instantiation
template std::shared_ptr<class SpriteComponent> Object::GetComponent<class SpriteComponent>() const;
template std::shared_ptr<class SpriteComponent> Object::AddComponent<class SpriteComponent>();
template void Object::RemoveComponent<class SpriteComponent>();
void Object::Save(YAML::Emitter& out) const {
out << YAML::BeginMap;
out << YAML::Key << "name" << YAML::Value << name;
out << YAML::Key << "position" << YAML::Value << YAML::Flow << YAML::BeginSeq << localPosition.x << localPosition.y << YAML::EndSeq;
out << YAML::Key << "layer" << YAML::Value << layer;
out << YAML::Key << "components" << YAML::Value << YAML::BeginSeq;
for (const auto& comp : components) {
for (const auto& comp : components)
comp->Save(out);
}
out << YAML::EndSeq;
out << YAML::Key << "children" << YAML::Value << YAML::BeginSeq;
for (const auto& child : children)
child->Save(out);
out << YAML::EndSeq;
out << YAML::EndMap;
}
void Object::Load(const YAML::Node& node) {
name = node["name"].as<std::string>();
auto pos = node["position"];
localPosition = { pos[0].as<float>(), pos[1].as<float>() };
if (pos && pos.IsSequence() && pos.size() == 2) {
localPosition.x = pos[0].as<float>();
localPosition.y = pos[1].as<float>();
}
if (node["layer"])
layer = node["layer"].as<int>();
components.clear();
if (node["components"]) {
for (const auto& compNode : node["components"]) {
std::string type = compNode["type"].as<std::string>();
if (type == "SpriteComponent") {
auto comp = AddComponent<class SpriteComponent>();
auto comp = AddComponent<SpriteComponent>();
comp->Load(compNode);
} else if (type == "CameraComponent") {
auto comp = AddComponent<CameraComponent>();
comp->Load(compNode);
}
}
}
children.clear();
if (node["children"]) {
for (const auto& childNode : node["children"]) {
auto child = std::make_shared<Object>("(loaded)");
auto child = std::make_shared<Object>("Child");
child->Load(childNode);
AddChild(child);
}

View File

@ -1,30 +1,30 @@
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
#include "../Components/Component.h"
class Component;
class Object {
public:
Object(const std::string& name);
~Object();
void SetParent(Object* newParent);
void AddChild(std::shared_ptr<Object> child);
void RemoveChild(Object* child);
glm::vec2 GetWorldPosition() const;
glm::vec2 GetLocalPosition() const;
void SetLocalPosition(glm::vec2 pos);
const std::string& GetName() const;
void SetName(const std::string& name);
std::vector<std::shared_ptr<Object>>& GetChildren();
glm::vec2 GetLocalPosition() const;
void SetLocalPosition(glm::vec2 pos);
glm::vec2 GetWorldPosition() const;
void SetParent(Object* parent);
Object* GetParent() const;
void AddChild(std::shared_ptr<Object> child);
void RemoveChild(Object* child);
std::vector<std::shared_ptr<Object>>& GetChildren();
template<typename T>
std::shared_ptr<T> GetComponent() const;
@ -38,10 +38,8 @@ public:
void Save(YAML::Emitter& out) const;
void Load(const YAML::Node& node);
int id;
bool selected = false;
int layer;
int id = 0;
int layer = 0;
private:
std::string name;
@ -50,3 +48,30 @@ private:
std::vector<std::shared_ptr<Object>> children;
std::vector<std::shared_ptr<Component>> components;
};
template<typename T>
std::shared_ptr<T> Object::GetComponent() const {
for (const auto& comp : components) {
if (auto casted = std::dynamic_pointer_cast<T>(comp))
return casted;
}
return nullptr;
}
template<typename T>
std::shared_ptr<T> Object::AddComponent() {
auto existing = GetComponent<T>();
if (existing) return existing;
std::shared_ptr<T> component = std::make_shared<T>(this);
components.push_back(component);
return component;
}
template<typename T>
void Object::RemoveComponent() {
components.erase(std::remove_if(components.begin(), components.end(),
[](const std::shared_ptr<Component>& comp) {
return std::dynamic_pointer_cast<T>(comp) != nullptr;
}), components.end());
}

View File

@ -92,23 +92,22 @@ void Renderer::End() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos) {
if (!sprite || sprite->GetTextureID() == 0) return;
void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float scale) {
GLuint tex = sprite->GetTextureID();
if (!tex) return;
spriteShader.Use();
spriteShader.SetVec2("uPos", pos);
spriteShader.SetVec2("uSize", sprite->GetSize());
spriteShader.SetVec2("uScreen", glm::vec2(width, height));
spriteShader.SetInt("uTex", 0);
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
float size = 100.0f * scale;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID());
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindVertexArray(0);
glTexCoord2f(0, 0); glVertex2f(pos.x, pos.y);
glTexCoord2f(1, 0); glVertex2f(pos.x + size, pos.y);
glTexCoord2f(1, 1); glVertex2f(pos.x + size, pos.y + size);
glTexCoord2f(0, 1); glVertex2f(pos.x, pos.y + size);
glEnd();
}
GLuint Renderer::GetRenderTexture() {
return textureColorBuffer;
}

View File

@ -10,7 +10,7 @@ public:
static void Resize(int w, int h);
static void Begin();
static void End();
static void DrawSprite(SpriteComponent* sprite, const glm::vec2& pos);
static void DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float scale);
static GLuint GetRenderTexture();
static glm::ivec2 GetSize();