added pan zoom editor camera

This commit is contained in:
OusmBlueNinja 2025-04-12 21:36:40 -05:00
parent a71d221ad9
commit 1f7fceb9b5
6 changed files with 144 additions and 80 deletions

View File

@ -16,25 +16,12 @@ In file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13,
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\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\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" )
| ^
[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" )
| ^
src\src\Engine.cpp:35:13: warning: 'isDragging' defined but not used [-Wunused-variable]
35 | static bool isDragging = false;
| ^~~~~~~~~~
[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
[TIME] Build duration: 6.12s
[RUN] Executed app.exe successfully.
[TIME] Total runtime: 72.36s

31
src/build/imgui.ini Normal file
View File

@ -0,0 +1,31 @@
[Window][WindowOverViewport_11111111]
Pos=0,19
Size=1280,701
Collapsed=0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Scene Tree]
Pos=60,60
Size=128,48
Collapsed=0
[Window][Inspector]
Pos=1123,19
Size=157,701
Collapsed=0
DockId=0x00000002,0
[Window][Viewport]
Pos=60,60
Size=32,35
Collapsed=0
[Docking][Data]
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
DockNode ID=0x00000001 Parent=0x11111111 SizeRef=1121,701 CentralNode=1
DockNode ID=0x00000002 Parent=0x11111111 SizeRef=157,701 Selected=0x36DC96AB

View File

@ -11,11 +11,11 @@ unsigned int SpriteComponent::LoadTexture(const std::string& path) {
stbi_set_flip_vertically_on_load(1);
unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4);
if (!data) {
std::cerr << "Failed to load image: " << path << std::endl;
std::cerr << "Failed to load image: " << path << "\nReason: " << stbi_failure_reason() << std::endl;
return 0;
}
size = glm::vec2(w,h);
size = glm::vec2(w, h);
unsigned int id;
glGenTextures(1, &id);
@ -33,6 +33,7 @@ unsigned int SpriteComponent::LoadTexture(const std::string& path) {
return id;
}
void SpriteComponent::SetTexture(const std::string& path) {
texturePath = path;
textureID = LoadTexture(path);

View File

@ -30,34 +30,10 @@ 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;
static glm::vec2 cameraPos = {0, 0};
static float cameraZoom = 1.0f;
static bool isDragging = false;
static ImVec2 lastMousePos = {};
GLFWwindow *window = nullptr;
@ -257,32 +233,47 @@ void Engine::Run()
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)
if (!playing && ImGui::IsWindowHovered())
{
for (const auto &obj : objects)
if (ImGui::IsMouseDragging(ImGuiMouseButton_Right))
{
if (auto cam = obj->GetComponent<CameraComponent>())
{
if (cam->IsPrimary())
{
cameraOffset = obj->GetWorldPosition();
camZoom = cam->GetZoom();
break;
}
}
ImVec2 mouseDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Right);
cameraPos -= glm::vec2(mouseDelta.x, mouseDelta.y) / cameraZoom;
}
float wheel = ImGui::GetIO().MouseWheel;
if (wheel != 0.0f)
{
float zoomFactor = (wheel > 0) ? 1.1f : 1.0f / 1.1f;
// Get mouse position in screen space
ImVec2 mousePos = ImGui::GetMousePos();
ImVec2 windowPos = ImGui::GetWindowPos();
ImVec2 contentRegionMin = ImGui::GetWindowContentRegionMin();
glm::vec2 relativeMouse = glm::vec2(mousePos.x - windowPos.x - contentRegionMin.x,
mousePos.y - windowPos.y - contentRegionMin.y);
// Convert to world position before zoom
glm::vec2 beforeZoom = (relativeMouse - glm::vec2(size.x / 2, size.y / 2)) / cameraZoom + cameraPos;
// Apply zoom
cameraZoom *= zoomFactor;
cameraZoom = std::clamp(cameraZoom, 0.1f, 10.0f);
// Convert to world position after zoom
glm::vec2 afterZoom = (relativeMouse - glm::vec2(size.x / 2, size.y / 2)) / cameraZoom + cameraPos;
// Offset camera so zoom is centered at mouse
cameraPos += beforeZoom - afterZoom;
}
}
Renderer::Resize((int)size.x, (int)size.y);
Renderer::Begin();
Renderer::Begin(); // assumes orthographic matrix is set up here
std::vector<std::shared_ptr<Object>> toDraw;
std::function<void(const std::shared_ptr<Object> &)> collect = [&](const std::shared_ptr<Object> &obj)
{
toDraw.push_back(obj);
@ -301,8 +292,8 @@ void Engine::Run()
{
if (auto sprite = obj->GetComponent<SpriteComponent>())
{
glm::vec2 renderPos = (obj->GetWorldPosition() - cameraOffset) * camZoom;
Renderer::DrawSprite(sprite.get(), renderPos, camZoom);
glm::vec2 worldPos = obj->GetWorldPosition();
Renderer::DrawSprite(sprite.get(), worldPos, cameraZoom, cameraPos);
}
}

View File

@ -92,18 +92,71 @@ void Renderer::End() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float scale) {
GLuint tex = sprite->GetTextureID();
if (!tex) return;
//void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float scale) {
// GLuint tex = sprite->GetTextureID();
// if (!tex) return;
//
// glBindTexture(GL_TEXTURE_2D, tex);
// glBegin(GL_QUADS);
// float size = 100.0f * scale;
//
// 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();
//}
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
float size = 100.0f * scale;
void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos) {
if (!sprite || sprite->GetTextureID() == 0) return;
spriteShader.Use();
glm::vec2 size = sprite->GetSize();
glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(size.x / 2, size.y / 2);
spriteShader.SetVec2("uPos", screenPos);
spriteShader.SetVec2("uSize", size*zoom);
spriteShader.SetVec2("uScreen", glm::vec2(width, height));
spriteShader.SetInt("uTex", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID());
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindVertexArray(0);
}
void Renderer::DrawEditorGrid(const glm::vec2& cameraPos, float zoom) {
glUseProgram(0);
glColor4f(0.5f, 0.5f, 0.5f, 0.25f);
glLineWidth(1.0f);
glBegin(GL_LINES);
float spacing = 100.0f;
float viewWidth = width / zoom;
float viewHeight = height / zoom;
float left = cameraPos.x - viewWidth / 2;
float right = cameraPos.x + viewWidth / 2;
float bottom = cameraPos.y + viewHeight / 2;
float top = cameraPos.y - viewHeight / 2;
int minX = static_cast<int>(std::floor(left / spacing)) * spacing;
int maxX = static_cast<int>(std::ceil(right / spacing)) * spacing;
int minY = static_cast<int>(std::floor(top / spacing)) * spacing;
int maxY = static_cast<int>(std::ceil(bottom / spacing)) * spacing;
for (int x = minX; x <= maxX; x += spacing) {
glVertex2f((float)x, top);
glVertex2f((float)x, bottom);
}
for (int y = minY; y <= maxY; y += spacing) {
glVertex2f(left, (float)y);
glVertex2f(right, (float)y);
}
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();
}

View File

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