diff --git a/Resources/scripts/ai/grunt_behaviour.lua b/Resources/scripts/ai/grunt_behaviour.lua index d1ce686..cf21dea 100644 --- a/Resources/scripts/ai/grunt_behaviour.lua +++ b/Resources/scripts/ai/grunt_behaviour.lua @@ -1,42 +1,30 @@ -- global vars -patrolDestination = { x=500.0, y=500.0, z=0.0 } -moveLeft = true +MoveLeft = true -- helper functions -function watchPosition(actor, pos) +local function watchPosition(actor, pos) local y = pos.y - actor.position.y local x = pos.x - actor.position.x local rotation = math.atan2(y, x) actor.rotation = math.deg(rotation) end -function distance(a, b) +local function distance(a, b) local dx = a.x - b.x local dy = a.y - b.y return math.sqrt(dx * dx + dy * dy) end -function moveTo(actor, pos) - local a = actor - local p = pos - watchPosition(a, p) - if distance(a.position, p) < 50 then - return true - end - a:moveForward() - return false -end - -- Behaviour Functions called on AI -- These functions are ai behaviour functions called in the game --- The AI will be spawned in idle mode, so if you want to put the bot into patrol mode +-- The AI will be spawned in idle mode, so if you want to put the bot into patrol mode -- It's on you to do that in this function. function idle(actor, target) local a = actor local t = target if t ~= nil then - -- print("target is at " .. target.position.x) - -- watchPosition(actor, target.position) + -- print("target is at " .. target.position.x) + -- watchPosition(actor, target.position) ai.state = AIState.Patrol a.rotation = 180 end @@ -48,24 +36,12 @@ end function patrol(actor, target) local a = actor local t = target - if t ~= nil then - -- print("target is at " .. target.position.x) - end - --if moveTo(actor, patrolDestination) == true then - -- patrolDestination = { x=math.random(400.0, 750.0), y=math.random(400.0, 750.0), z=0.0 } - --end - -- performRaycast returns if true if the raycast hits the target position it also sets the getter function - -- distFromWall, at bot creation distFromWall is and infinite float value. - -- This performRaycast function is highly discourage due to slow down - --if raycaster:performRaycast(actor.position, actor.rotation, target.position) == true then - --ai.state = AIState.Alert - --end if raycaster:bresenhamRaycast(a.position, a.rotation, t.position) == true then --target hit! ai.state = AIState.Alert end if raycaster:distFromWall() < 3 then - upOrDown = math.random(2) + local upOrDown = math.random(2) if moveLeft == true then if upOrDown == 1 then a.rotation = 180 @@ -73,7 +49,7 @@ function patrol(actor, target) a.rotation = 270 end moveLeft = false - else + else if upOrDown == 1 then a.rotation = 0 else @@ -90,10 +66,8 @@ function alert(actor, target) local a = actor local t = target if target ~= nil then - -- print("target is at " .. target.position.x) watchPosition(a, t.position) end - --print("actor is alert at " .. actor.position.x) if distance(a.position, t.position) > 300 then a:moveForward() end diff --git a/Resources/scripts/ai/scared_behaviour.lua b/Resources/scripts/ai/scared_behaviour.lua index 2b9ade1..60e22ca 100644 --- a/Resources/scripts/ai/scared_behaviour.lua +++ b/Resources/scripts/ai/scared_behaviour.lua @@ -1,18 +1,18 @@ -- helper functions -function lookAway(actor, pos) - y = actor.position.y - pos.y - x = actor.position.x - pos.x - rotation = math.atan(y, x) +local function lookAway(actor, pos) + local y = actor.position.y - pos.y + local x = actor.position.x - pos.x + local rotation = math.atan(y, x) actor.rotation = math.deg(rotation) end -function distance(a, b) - return math.sqrt((math.abs(a.x - b.x)^2) + (math.abs(a.y - b.y)^2)) +local function distance(a, b) + return math.sqrt((math.abs(a.x - b.x) ^ 2) + (math.abs(a.y - b.y) ^ 2)) end function idle(actor, target) - -- do nothing here for now + -- do nothing here for now end function patrol(actor, target) diff --git a/YuppleMayham/CMakeLists.txt b/YuppleMayham/CMakeLists.txt index ad7a6da..baf683d 100644 --- a/YuppleMayham/CMakeLists.txt +++ b/YuppleMayham/CMakeLists.txt @@ -3,7 +3,7 @@ # find_package(SDL2 2.30.2 REQUIRED) -find_package(SDL2_IMAGE 2.8.2 REQUIRED) +find_package(SDL2_image 2.8.2 REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(LuaJIT REQUIRED IMPORTED_TARGET GLOBAL luajit) find_package(sol2 REQUIRED) @@ -42,6 +42,7 @@ add_executable (YuppleMayham "src/utility/ftfont.cpp" "src/graphics/sprite.cpp" "src/graphics/mesh.cpp" + "src/graphics/glwindow.cpp" "src/gameplay/entity.cpp" "src/gameplay/gameactor.cpp" "src/graphics/shader.cpp" @@ -104,6 +105,6 @@ endif() target_include_directories(YuppleMayham PRIVATE "${PROJECT_SOURCE_DIR}/YuppleMayham/include" ${LuaJIT_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIR_ft2build}) -target_link_libraries(YuppleMayham SDL2::SDL2main SDL2::SDL2 SDL2_image::SDL2_image openal glm::glm-header-only tinyxml2 freetype ${LuaJIT_LINK_LIBRARIES}) +target_link_libraries(YuppleMayham SDL2::SDL2main SDL2::SDL2 SDL2_image::SDL2_image openal glm::glm tinyxml2 freetype ${LuaJIT_LINK_LIBRARIES}) # TODO: Add tests and install targets if needed. diff --git a/YuppleMayham/include/gameplay/game.h b/YuppleMayham/include/gameplay/game.h index 6015be5..8bae688 100644 --- a/YuppleMayham/include/gameplay/game.h +++ b/YuppleMayham/include/gameplay/game.h @@ -1,10 +1,12 @@ #ifndef _H_GAME_H #define _H_GAME_H -#include #include +#include #include +#include "gameplay/camera.h" + class InputHandler; class Scene; class Text; @@ -13,47 +15,42 @@ class Renderer; class AudioEngine; class GLWindow; -enum { - GAME_QUITTING = 0, - GAME_RUNNING = 1, - GAME_MENU = 2, - GAME_PLAYING = 4 -}; +enum { GAME_QUITTING = 0, GAME_RUNNING = 1, GAME_MENU = 2, GAME_PLAYING = 4 }; -class Game -{ +class Game { public: - Game() {} - bool init(); + Game() {} + bool init(); - bool loadDebugScene(); - - void captureInput(SDL_Event& e); - void executeInputs(); + bool loadDebugScene(); - void update(double deltaTime); - void render(); + void captureInput(SDL_Event &e); + void executeInputs(); - const unsigned getGameState() const { return game_state; } + void update(double deltaTime); + void render(); - const unsigned getWindowWidth() const; - const unsigned getWindowHeight() const; + const unsigned getGameState() const { return game_state; } - void quit(); - ~Game(); + const unsigned getWindowWidth() const; + const unsigned getWindowHeight() const; + + void quit(); + ~Game(); private: - unsigned game_state = GAME_QUITTING; + unsigned game_state = GAME_QUITTING; - std::shared_ptr window; + std::shared_ptr window; - std::shared_ptr currentScene; - std::shared_ptr inputHandler; - std::shared_ptr resourceManager; - std::shared_ptr renderer; - std::shared_ptr textHandler; - std::shared_ptr audioEngine; - std::shared_ptr globalEventManager; + std::unique_ptr camera; + std::shared_ptr currentScene; + std::shared_ptr inputHandler; + std::shared_ptr resourceManager; + std::shared_ptr renderer; + std::shared_ptr textHandler; + std::shared_ptr audioEngine; + std::shared_ptr globalEventManager; }; #endif diff --git a/YuppleMayham/include/graphics/glwindow.h b/YuppleMayham/include/graphics/glwindow.h index d510578..d4ea144 100644 --- a/YuppleMayham/include/graphics/glwindow.h +++ b/YuppleMayham/include/graphics/glwindow.h @@ -2,52 +2,33 @@ #define _H_GLWINDOW_H #include -//#include - #include -class GLWindow -{ +#include "utility/logger.h" + +class GLWindow { public: - GLWindow(const char* windowName, int width, int height) : - w(width), - h(height), - name(windowName) {}; - ~GLWindow(); + GLWindow(const char *windowName, int width, int height) + : w(width), h(height), name(windowName) {}; + ~GLWindow(); - bool Init(); + bool Init(); - void swap() { SDL_GL_SwapWindow(window); } - void makeCurrent() { SDL_GL_MakeCurrent(window, glContext); } + void swap() { SDL_GL_SwapWindow(window); } + void makeCurrent() { SDL_GL_MakeCurrent(window, glContext); } - unsigned width() const { return w; } - unsigned height() const { return h; } + unsigned Width() const { return w; } + unsigned Height() const { return h; } + + SDL_Window *getWindow() const { return window; } + const SDL_GLContext &getContext() const { return glContext; } - SDL_Window* getWindow() const { return window; } - const SDL_GLContext& getContext() const { return glContext; } private: - SDL_Window* window = nullptr; - SDL_GLContext glContext = NULL; + SDL_Window *window = nullptr; + SDL_GLContext glContext = NULL; - unsigned w, h; - const char* name; + unsigned w, h; + const char *name; }; -bool GLWindow::Init() -{ - window = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL); - if (!window) - return false; - glContext = SDL_GL_CreateContext(window); - if (!glContext) - return false; - return true; -} - -GLWindow::~GLWindow() -{ - SDL_GL_DeleteContext(glContext); - SDL_DestroyWindow(window); -} - #endif // _H_GLWINDOW_H diff --git a/YuppleMayham/include/graphics/renderer.h b/YuppleMayham/include/graphics/renderer.h index 1bdc0fa..41f81ac 100644 --- a/YuppleMayham/include/graphics/renderer.h +++ b/YuppleMayham/include/graphics/renderer.h @@ -1,74 +1,65 @@ #ifndef _H_RENDERER_H #define _H_RENDERER_H -#include -#include #include #include +#include +#include -#include "graphics/quad.h" #include "graphics/drawable.h" +#include "graphics/glwindow.h" #include "graphics/postprocess.h" +#include "graphics/quad.h" class ResourceManager; class Shader; -enum class RenderLayer { - Background, - Map, - GameObjects, - Effects, - HUD, - Menu -}; +enum class RenderLayer { Background, Map, GameObjects, Effects, HUD, Menu }; -class Renderer -{ +class Renderer { public: - Renderer(const std::shared_ptr&); + Renderer(const std::shared_ptr &, + const std::shared_ptr &); - void clear(); + void clear(); - void hookEventManager(const std::weak_ptr eventManager); + void hookEventManager(const std::weak_ptr eventManager); - void setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view); - void addDrawable(RenderLayer renderLayer, Drawable *drawable); - void removeDrawable(RenderLayer renderLayer, Drawable *drawable); + void setProjAndViewMatrix(const glm::mat4 &proj, const glm::mat4 &view); + void addDrawable(RenderLayer renderLayer, Drawable *drawable); + void removeDrawable(RenderLayer renderLayer, Drawable *drawable); - void render(); + void render(); private: - std::unordered_map> worldLayerPool; - std::unordered_map> HUDLayerPool; - std::vector renderingOrder = { - RenderLayer::Background, - RenderLayer::Map, - RenderLayer::GameObjects, - RenderLayer::Effects, - RenderLayer::HUD, - RenderLayer::Menu - }; + std::unordered_map> worldLayerPool; + std::unordered_map> HUDLayerPool; + std::vector renderingOrder = { + RenderLayer::Background, RenderLayer::Map, RenderLayer::GameObjects, + RenderLayer::Effects, RenderLayer::HUD, RenderLayer::Menu}; - void uploadUniforms(const unsigned shaderID, const std::vector& uniforms); + void uploadUniforms(const unsigned shaderID, + const std::vector &uniforms); - unsigned uboMatrices; + unsigned uboMatrices; - union FrameBuffer { - unsigned int frame; - unsigned int texture; - }worldBuffer, hudBuffer; + union FrameBuffer { + unsigned int frame; + unsigned int texture; + } worldBuffer, hudBuffer; - std::unique_ptr screenQuad; + std::unique_ptr screenQuad; - std::shared_ptr resourceManager; + std::shared_ptr resourceManager; + std::shared_ptr glWindow; - void initFrameBuffers(); - void initUniformBuffers(); + void initFrameBuffers(); + void initUniformBuffers(); - std::unique_ptr postProcessor; + std::unique_ptr postProcessor; - void sortLayerPool(auto& layerPool); - void renderPool(auto& layerPool); + void sortLayerPool(auto &layerPool); + void renderPool(auto &layerPool); }; #endif diff --git a/YuppleMayham/src/gameplay/ai.cpp b/YuppleMayham/src/gameplay/ai.cpp index 874792c..47a3fc1 100644 --- a/YuppleMayham/src/gameplay/ai.cpp +++ b/YuppleMayham/src/gameplay/ai.cpp @@ -9,6 +9,9 @@ AI::AI(GameActor* actor, std::unique_ptr raycaster) lastGCTime(std::chrono::high_resolution_clock::now()), GCTimeout(3) {} +/* + * The behavior script works off of three different states, idle, patrol and alert. + * When the script is idle, this is */ void AI::attachBehaviourScript(std::unique_ptr behaviour) { // passing out instance of raycaster and this AI into our scripting api @@ -25,6 +28,8 @@ void AI::attachBehaviourScript(std::unique_ptr behaviour) void AI::update() { try { + // If our ai doesn't have a reference to the actor it's controlling it will do nothing. + // If our ai script does have an actor but no target, it will default to its idle state. if (actor && target) { switch (state) { @@ -35,7 +40,7 @@ void AI::update() if (!result.valid()) { sol::error err = result; - std::cerr << "lua error: " << err.what() << std::endl; + LOG(ERROR, "Lua error: {}", err.what(), NULL); } } break; @@ -46,7 +51,7 @@ void AI::update() if (!result.valid()) { sol::error err = result; - std::cerr << "lua error: " << err.what() << std::endl; + LOG(ERROR, "Lua error: {}", err.what(), NULL); } } break; @@ -57,12 +62,25 @@ void AI::update() if (!result.valid()) { sol::error err = result; - std::cerr << "lua error: " << err.what() << std::endl; + LOG(ERROR, "Lua error: {}", err.what(), NULL); } } break; } - } + } else if (actor) { + switch (state) + { + case AIState::Idle: + if (idleFunc.valid()) { + auto result = idleFunc(actor, nullptr); + if (!result.valid()) { + sol::error err = result; + LOG(ERROR, "Lua Error: {}", err.what()); + } + } + } + } + // Collect garbage just to be sure. std::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now(); if (curTime - lastGCTime >= GCTimeout) { @@ -71,13 +89,14 @@ void AI::update() } } catch (const std::exception& e) { - std::cerr << "Error during AI update: " << e.what() << std::endl; + LOG(ERROR, "Problem occured during AI update: {}", e.what()); state = AIState::Idle; } } AI::~AI() { + // Just set all of the references to null, given they are smart pointers, they are freed when no longer used. behaviour->lua["raycaster"] = sol::nil; behaviour->lua["ai"] = sol::nil; behaviour->lua["idle"] = sol::nil; diff --git a/YuppleMayham/src/gameplay/camera.cpp b/YuppleMayham/src/gameplay/camera.cpp index bc560b4..9c74bf2 100644 --- a/YuppleMayham/src/gameplay/camera.cpp +++ b/YuppleMayham/src/gameplay/camera.cpp @@ -1,5 +1,6 @@ #include "gameplay/camera.h" +// follow our target set using the setTarget. If there is no target set the camera will not move. void Camera::update(double deltaTime) { if (target == nullptr) @@ -19,6 +20,7 @@ glm::mat4 Camera::getProjectionMatrix() return glm::ortho(0.f, viewPortW, viewPortH, 0.f); } +// The local coordinates are the corrdinates relative to the camera. const glm::vec3 Camera::worldToLocal(const glm::vec3& worldCoordinates) { //return worldCoordinates - position; diff --git a/YuppleMayham/src/gameplay/entity.cpp b/YuppleMayham/src/gameplay/entity.cpp index 4125543..eaf5e55 100644 --- a/YuppleMayham/src/gameplay/entity.cpp +++ b/YuppleMayham/src/gameplay/entity.cpp @@ -32,6 +32,7 @@ void Entity::flip() flipped = !flipped; } +// Add physics component implies more than one can be attached to an entity... void Entity::addPhysicsComponent(const std::shared_ptr& physics) { this->physics = physics; @@ -39,6 +40,8 @@ void Entity::addPhysicsComponent(const std::shared_ptr& physic void Entity::update(double deltaTime) { + // If our entity has a physics component attached and that they're moving, + // we will update the entity position to match the rigidBody position. if (physics && physics->rigidBody.velocity != glm::vec2(0.0f)) { position = glm::vec3(physics->rigidBody.position, 0.f); @@ -47,21 +50,24 @@ void Entity::update(double deltaTime) } else if (!physics) { + // In the case that the entity does not have a physics component we will handle movement on the entity itself. position += deltaPosition * 1.f; updateModelMatrix(); deltaPosition = glm::vec3(0.f); } } +// The entity will only need to update its model matrix and the flipped flag on its attached shader. +// The shader and sprite component will handle the drawing. void Entity::draw() { - //glm::mat4 mvp = camera->getProjectionMatrix() * camera->getViewMatrix() * modelMatrix; editUniform("model", modelMatrix); editUniform("flip", flipped); } void Entity::updateModelMatrix() { + // Quick sanity check to make sure our Z position is zero. Since we are in 2D position.z = 0.f; glm::mat4 rotationMat = (isRotatable) ? glm::rotate(glm::mat4(1.f), glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f)) : glm::mat4(1.0f); glm::mat4 translation = glm::translate(glm::mat4(1.f), position); diff --git a/YuppleMayham/src/gameplay/game.cpp b/YuppleMayham/src/gameplay/game.cpp index 32dfac4..9a0b19e 100644 --- a/YuppleMayham/src/gameplay/game.cpp +++ b/YuppleMayham/src/gameplay/game.cpp @@ -1,15 +1,11 @@ #include "gameplay/game.h" #include "gameplay/input.h" #include "gameplay/scene.h" -/*due for possible removal!*/ -#include "gameplay/gameactor.h" -#include "gameplay/weapons/weapon.h" -/*-------------------------*/ #include "utility/command.h" -#include "utility/resourcemanager.h" #include "utility/ftfont.h" #include "utility/logger.h" +#include "utility/resourcemanager.h" #include "graphics/glwindow.h" @@ -17,122 +13,115 @@ #include #include -#include #include -bool Game::init() -{ - window = std::make_shared("Yupple Mayham", 800, 600); +bool Game::init() { + window = std::make_shared("Yupple Mayham", 1024, 768); - if (!window->Init()) - ERROR_LOG("Failed to init GLWindow: {}", SDL_GetError()); + if (!window->Init()) + ERROR_LOG("Failed to init GLWindow: {}", SDL_GetError()); - if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) - ERROR_LOG("Failed to load GLLoader", NULL); + if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) + ERROR_LOG("Failed to load GLLoader", NULL); #if _DEBUG - LOG_LEVEL(DEBUG); + LOG_LEVEL(DEBUG); #else - LOG_LEVEL(INFO); + LOG_LEVEL(INFO); #endif - SDL_GL_SetSwapInterval(1); - glViewport(0, 0, window->width(), window->height()); - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + SDL_GL_SetSwapInterval(1); + glViewport(0, 0, window->Width(), window->Height()); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // For now we'll init default bindings, but as we move forward controls will be set by the player and saved in controls.xml - inputHandler = std::make_shared(); - inputHandler->bindKeyCommand(SDLK_w, 0, std::make_unique()); - inputHandler->bindKeyCommand(SDLK_a, 0, std::make_unique()); - inputHandler->bindKeyCommand(SDLK_s, 0, std::make_unique()); - inputHandler->bindKeyCommand(SDLK_d, 0, std::make_unique()); + // For now we'll init default bindings, but as we move forward controls will + // be set by the player and saved in controls.xml + inputHandler = std::make_shared(); + inputHandler->bindKeyCommand(SDLK_w, 0, std::make_unique()); + inputHandler->bindKeyCommand(SDLK_a, 0, std::make_unique()); + inputHandler->bindKeyCommand(SDLK_s, 0, std::make_unique()); + inputHandler->bindKeyCommand(SDLK_d, 0, std::make_unique()); - inputHandler->bindMouseCommand(MOUSE_BUTTON_LEFT, 100, std::make_unique()); - inputHandler->bindMouseMotion(std::make_unique()); - inputHandler->bindMouseScroll(std::make_unique()); + inputHandler->bindMouseCommand(MOUSE_BUTTON_LEFT, 100, + std::make_unique()); + inputHandler->bindMouseMotion(std::make_unique()); + inputHandler->bindMouseScroll(std::make_unique()); - game_state |= GAME_RUNNING; - globalEventManager = std::make_shared(); - resourceManager = std::make_shared(); - renderer = std::make_shared(resourceManager); - audioEngine = std::make_shared(resourceManager); - audioEngine->hookEventManager(globalEventManager); - /* Testing */ - audioEngine->pushMusic("music/short_song.ogg"); - audioEngine->pushMusic("music/bright.ogg"); - audioEngine->pushMusic("music/main_song.ogg"); - audioEngine->playMusic(); - /* */ - renderer->hookEventManager(globalEventManager); - textHandler = std::make_shared(); - if (!textHandler->loadFonts("fonts")) - return false; - return true; + game_state |= GAME_RUNNING; + globalEventManager = std::make_shared(); + resourceManager = std::make_shared(); + renderer = std::make_shared(resourceManager, window); + audioEngine = std::make_shared(resourceManager); + camera = std::make_unique(static_cast(window->Width()), + static_cast(window->Height())); + audioEngine->hookEventManager(globalEventManager); + /* Testing */ + audioEngine->pushMusic("music/short_song.ogg"); + audioEngine->pushMusic("music/bright.ogg"); + audioEngine->pushMusic("music/main_song.ogg"); + audioEngine->playMusic(); + /* */ + renderer->hookEventManager(globalEventManager); + textHandler = std::make_shared(); + if (!textHandler->loadFonts("fonts")) + return false; + return true; } -const unsigned Game::getWindowWidth() const { return window->width(); } -const unsigned Game::getWindowHeight() const { return window->height(); } +const unsigned Game::getWindowWidth() const { return window->Width(); } +const unsigned Game::getWindowHeight() const { return window->Height(); } -bool Game::loadDebugScene() -{ - currentScene = std::make_shared(SCENE_SHOOTER, resourceManager, globalEventManager); - currentScene->init(); - audioEngine->hookSceneManager(currentScene->getEventManager()); - if (currentScene->getPlayer() == nullptr) - return false; - inputHandler->setActor(currentScene->getPlayer().get()); - return true; +bool Game::loadDebugScene() { + currentScene = std::make_shared(SCENE_SHOOTER, resourceManager, + globalEventManager); + currentScene->init(); + audioEngine->hookSceneManager(currentScene->getEventManager()); + if (currentScene->getPlayer() == nullptr) + return false; + inputHandler->setActor(currentScene->getPlayer().get()); + camera->setTarget(currentScene->getPlayer().get()); + return true; } -void Game::captureInput(SDL_Event& e) -{ - inputHandler->captureInput(e); +void Game::captureInput(SDL_Event &e) { inputHandler->captureInput(e); } + +void Game::executeInputs() { + inputHandler->handleInput(); + inputHandler->executeCommands(); } -void Game::executeInputs() -{ - inputHandler->handleInput(); - inputHandler->executeCommands(); +void Game::update(double deltaTime) { + if (currentScene) { + currentScene->update(deltaTime); + if (auto player = currentScene->getPlayer()) { + audioEngine->updateListener(player->getPosition()); + player->setLocalPosition(camera->worldToLocal(player->getPosition())); + } + } + camera->update(deltaTime); + audioEngine->poll(); } -void Game::update(double deltaTime) -{ - if (currentScene) { - currentScene->update(deltaTime); - if (auto player = currentScene->getPlayer()) - audioEngine->updateListener(player->getPosition()); - } - audioEngine->poll(); +void Game::render() { + glClearColor(0.05f, 0.25f, 0.05f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + renderer->setProjAndViewMatrix(camera->getProjectionMatrix(), + camera->getViewMatrix()); + + if (currentScene) + currentScene->render(renderer); + + window->swap(); } -void Game::render() -{ - glClearColor(0.05f, 0.25f, 0.05f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); +void Game::quit() { game_state = GAME_QUITTING; } - if (currentScene) - { - currentScene->render(renderer); - /*Debug ammo indicator*/ - textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->getMagazine()), glm::vec2(10, 10), 0.5f); - textHandler->DrawText("comic.ttf", "/", glm::vec2(50, 10), 0.5f); - textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->getAmmo()), glm::vec2(90, 10), 0.5f); - } - - window->swap(); -} - -void Game::quit() -{ - game_state = GAME_QUITTING; -} - -Game::~Game() -{ - if (audioEngine) { - audioEngine->killMusic(); - } - resourceManager->clearResources(); +Game::~Game() { + if (audioEngine) { + audioEngine->killMusic(); + } + resourceManager->clearResources(); } diff --git a/YuppleMayham/src/gameplay/scene.cpp b/YuppleMayham/src/gameplay/scene.cpp index 670a2a2..2081edc 100644 --- a/YuppleMayham/src/gameplay/scene.cpp +++ b/YuppleMayham/src/gameplay/scene.cpp @@ -1,249 +1,238 @@ #include "gameplay/scene.h" -#include "gameplay/camera.h" +#include "gameplay/ai.h" #include "gameplay/gameactor.h" -#include "gameplay/weapons/weapons.h" -#include "gameplay/weapons/bulletmanager.h" #include "gameplay/map.h" #include "gameplay/physics.h" -#include "gameplay/ai.h" +#include "gameplay/weapons/bulletmanager.h" +#include "gameplay/weapons/weapons.h" -#include "graphics/sprite.h" #include "graphics/animation.h" #include "graphics/background.h" +#include "graphics/sprite.h" -#include "utility/script.h" #include "utility/component.h" -#include "utility/ftfont.h" -#include "utility/xmlloader.h" -#include "utility/resourcemanager.h" -#include "utility/events.h" -#include "utility/raycaster.h" #include "utility/debugdraw.h" +#include "utility/events.h" +#include "utility/ftfont.h" +#include "utility/raycaster.h" +#include "utility/resourcemanager.h" +#include "utility/script.h" +#include "utility/xmlloader.h" #include #include -// Scene xml files, should contain a node called that holds the sprite location +// Scene xml files, should contain a node called that holds the sprite +// location /* like this: - - + + */ -Scene::Scene(SceneType sceneType, std::shared_ptr resources, std::weak_ptr globalEvents) - : type(sceneType), resourceManager(resources), globalEventManager(globalEvents) -{ - camera = std::make_shared(800.f, 600.f); - physicsEngine = std::make_shared(); - eventManager = std::make_shared(); +Scene::Scene(SceneType sceneType, std::shared_ptr resources, + std::weak_ptr globalEvents) + : type(sceneType), resourceManager(resources), + globalEventManager(globalEvents) { + physicsEngine = std::make_shared(); + eventManager = std::make_shared(); } -void Scene::init() -{ - physicsEngine->hookEventManager(eventManager); - //if (sceneType == SCENE_SHOOTER) - loadDebugShooterScene(); +void Scene::init() { + physicsEngine->hookEventManager(eventManager); + // if (sceneType == SCENE_SHOOTER) + loadDebugShooterScene(); } -// This function is full of hardcoded values and test sprites, NOT for use with final product -void Scene::loadDebugShooterScene() -{ - hookSceneEvents(); - sceneData = resourceManager->loadScene("000"); - if (!sceneData) - return; - EntityData playerData = sceneData->entities[0]; - auto mapData = sceneData->map; - auto playerShader = resourceManager->loadShader("GL_player", "shaders/GL_player.vert", "shaders/GL_player.frag"); - auto bubbleShader = resourceManager->loadShader("GL_bubble", "shaders/GL_bubble.vert", "shaders/GL_bubble.frag"); - auto weaponShader = resourceManager->loadShader("GL_pistol", "shaders/GL_pistol.vert", "shaders/GL_pistol.frag"); +// This function is full of hardcoded values and test sprites, NOT for use with +// final product +void Scene::loadDebugShooterScene() { + hookSceneEvents(); + sceneData = resourceManager->loadScene("000"); + if (!sceneData) + return; + EntityData playerData = sceneData->entities[0]; + auto mapData = sceneData->map; + auto playerShader = resourceManager->loadShader( + "GL_player", "shaders/GL_player.vert", "shaders/GL_player.frag"); + auto bubbleShader = resourceManager->loadShader( + "GL_bubble", "shaders/GL_bubble.vert", "shaders/GL_bubble.frag"); + auto weaponShader = resourceManager->loadShader( + "GL_pistol", "shaders/GL_pistol.vert", "shaders/GL_pistol.frag"); - if (!sceneData->bgFile.empty()) { - LOG(INFO, "Found background loading '{}'", sceneData->bgFile); - background = resourceManager->loadBackground(sceneData->bgFile); - } + if (!sceneData->bgFile.empty()) { + LOG(INFO, "Found background loading '{}'", sceneData->bgFile); + background = resourceManager->loadBackground(sceneData->bgFile); + } - // creating map from scene - auto tileShader = resourceManager->loadShader("GL_tile", "shaders/GL_tile.vert", "shaders/GL_tile.frag"); - map = std::make_shared(mapData, tileShader, resourceManager); + // creating map from scene + auto tileShader = resourceManager->loadShader( + "GL_tile", "shaders/GL_tile.vert", "shaders/GL_tile.frag"); + map = std::make_shared(mapData, tileShader, resourceManager); - for (EntityData entityData : sceneData->entities) - { - auto entity = std::make_shared(this, playerShader); - // Directional is the kind of sprite sheet we are using, in this case for directional, I have the sprite sheet handle the rotations - // instead of just rotating the object, this makes it look quite a bit better from the end user perspective. - if (entityData.animated) - { - auto entityAnimation = resourceManager->loadAnimationSet(entityData.graphic, entity->getEntityID()); - // because we don't want to have the engine rotate the object based on the entities rotation, - // we set the this value to false so we no longer rotate the object. - if (entityAnimation->getDirectional()) - entity->setRotatable(false); - entity->addComponent(std::make_unique(entityAnimation, eventManager)); - } - else - { - auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic); - entity->addComponent(std::make_unique(entitySprite)); - } - auto defaultWeapon = resourceManager->loadWeapon("gun/pistol", weaponShader, bubbleShader); - auto entityWeapon = resourceManager->loadWeapon(entityData.weapon, weaponShader, bubbleShader); + for (EntityData entityData : sceneData->entities) { + auto entity = std::make_shared(this, playerShader); + // Directional is the kind of sprite sheet we are using, in this case for + // directional, I have the sprite sheet handle the rotations instead of just + // rotating the object, this makes it look quite a bit better from the end + // user perspective. + if (entityData.animated) { + auto entityAnimation = resourceManager->loadAnimationSet( + entityData.graphic, entity->getEntityID()); + // because we don't want to have the engine rotate the object based on the + // entities rotation, we set the this value to false so we no longer + // rotate the object. + if (entityAnimation->getDirectional()) + entity->setRotatable(false); + entity->addComponent( + std::make_unique(entityAnimation, eventManager)); + } else { + auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic); + entity->addComponent(std::make_unique(entitySprite)); + } + auto defaultWeapon = + resourceManager->loadWeapon("gun/pistol", weaponShader, bubbleShader); + auto entityWeapon = resourceManager->loadWeapon(entityData.weapon, + weaponShader, bubbleShader); - entity->pickupWeapon(std::move(defaultWeapon)); - entity->pickupWeapon(std::move(entityWeapon)); - entity->setPosition(glm::vec3(entityData.x * mapData->tileSize, entityData.y * mapData->tileSize, 0.f)); - entity->setScale(glm::vec3(mapData->tileSize, mapData->tileSize, 1.f)); + entity->pickupWeapon(std::move(defaultWeapon)); + entity->pickupWeapon(std::move(entityWeapon)); + entity->setPosition(glm::vec3(entityData.x * mapData->tileSize, + entityData.y * mapData->tileSize, 0.f)); + entity->setScale(glm::vec3(mapData->tileSize, mapData->tileSize, 1.f)); - entity->addPhysicsComponent( - physicsEngine->createObject(entity->getEntityID(), - entity->getPosition(), - 49.0, - PhysicsComponent::Collider::Shape::Circle, - glm::vec3(mapData->tileSize / 2)) - ); + entity->addPhysicsComponent(physicsEngine->createObject( + entity->getEntityID(), entity->getPosition(), 49.0, + PhysicsComponent::Collider::Shape::Circle, + glm::vec3(mapData->tileSize / 2))); - if (entityData.isPlayer) - { - player = entity; - camera->setTarget(entity.get()); - entity->setLocalPosition(camera->worldToLocal(entity->getPosition())); - } - else - { - // attach ai - if (!entityData.script.empty()) - { - auto behaviour = resourceManager->loadAIScript(entityData.script); - auto rayCaster = std::make_unique(40.f, 300.f, map->getCollisionMap(), mapData->tileSize); - auto ai = std::make_shared(entity.get(), std::move(rayCaster)); - ai->setTarget(player.get()); - ai->attachBehaviourScript(std::move(behaviour)); - entity->addComponent(std::make_unique(ai)); - } - } - entities.emplace(entity->getEntityID(), entity); - SDL_Delay(1); // This is to make sure each entity gets a unique ID - } + if (entityData.isPlayer) { + player = entity; + } else { + // attach ai + if (!entityData.script.empty()) { + auto behaviour = resourceManager->loadAIScript(entityData.script); + auto rayCaster = std::make_unique( + 40.f, 300.f, map->getCollisionMap(), mapData->tileSize); + auto ai = std::make_shared(entity.get(), std::move(rayCaster)); + ai->setTarget(player.get()); + ai->attachBehaviourScript(std::move(behaviour)); + entity->addComponent(std::make_unique(ai)); + } + } + entities.emplace(entity->getEntityID(), entity); + SDL_Delay(1); // This is to make sure each entity gets a unique ID + } - physicsEngine->loadCollisionMap(map->getCollisionMap(), mapData->tileSize); + physicsEngine->loadCollisionMap(map->getCollisionMap(), mapData->tileSize); - // Setup map and other entities... + // Setup map and other entities... } -std::shared_ptr Scene::getPlayer() const -{ - return (!player) ? nullptr : player; +std::shared_ptr Scene::getPlayer() const { + return (!player) ? nullptr : player; } -void Scene::update(double deltaTime) -{ +void Scene::update(double deltaTime) { - for (const auto& [id, e] : entities) - { - e->update(deltaTime); - if (camera->getTarget() == e.get()) - e->setLocalPosition(camera->worldToLocal(e->getPosition())); - } - physicsEngine->update(deltaTime); - camera->update(deltaTime); + for (const auto &[id, e] : entities) { + e->update(deltaTime); + } + physicsEngine->update(deltaTime); } -void Scene::render(std::shared_ptr renderer) -{ - renderer->clear(); +void Scene::render(std::shared_ptr renderer) { + renderer->clear(); - renderer->setProjAndViewMatrix(camera->getProjectionMatrix(), camera->getViewMatrix()); - renderer->addDrawable(RenderLayer::Map, map.get()); - if (background) { - renderer->addDrawable(RenderLayer::Background, static_cast(background)); - } - //map->draw(); - for (auto& [id, e] : entities) - { - //e->draw(); - renderer->addDrawable(RenderLayer::GameObjects, e.get()); - if (e->getHeldWeapon()) { - renderer->addDrawable(RenderLayer::GameObjects, e->getHeldWeapon()); - const auto& weapons = e->getAllWeapons(); - for (auto& w : weapons) { - for (auto b : w->getBulletManager()->getBullets()) { - renderer->addDrawable(RenderLayer::GameObjects, b.get()); - } - } - } - } + renderer->addDrawable(RenderLayer::Map, map.get()); + if (background) { + renderer->addDrawable(RenderLayer::Background, + static_cast(background)); + } + // map->draw(); + for (auto &[id, e] : entities) { + // e->draw(); + renderer->addDrawable(RenderLayer::GameObjects, e.get()); + if (e->getHeldWeapon()) { + renderer->addDrawable(RenderLayer::GameObjects, e->getHeldWeapon()); + const auto &weapons = e->getAllWeapons(); + for (auto &w : weapons) { + for (auto b : w->getBulletManager()->getBullets()) { + renderer->addDrawable(RenderLayer::GameObjects, b.get()); + } + } + } + } - renderer->render(); - /* - for (const auto& bullet : player->getHeldWeapon()->getBulletManager()->getBullets()) { - DebugDrawer::getInstance().addLine(player->getCenter(), bullet->getCenter(), glm::vec4(1.f, 0.f, 0.f, 0.f)); - DEBUG_TEXT( - glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, - camera.get()->worldToLocal(bullet->getCenter()).y, 0.f), - glm::vec4(1.f, 0.f, 0.f, 1.f), - 0.2f, - "( {}, {}, {} )", - bullet->getCenter().x, - bullet->getCenter().y, - bullet->getCenter().z - ); - DEBUG_TEXT( - glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, - camera.get()->worldToLocal(bullet->getCenter()).y + 10.f, 0.f), - glm::vec4(1.f, 1.f, 0.f, 1.f), - 0.2f, - "( {}, {} )", - bullet->getPhysicsComponent()->rigidBody.position.x, - bullet->getPhysicsComponent()->rigidBody.position.y - ); - DEBUG_TEXT( - glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, - camera.get()->worldToLocal(bullet->getCenter()).y + 20.f, 0.f), - glm::vec4(0.f, 1.f, 1.f, 1.f), - 0.2f, - "( {}, {} )", - bullet->getPhysicsComponent()->rigidBody.velocity.x, - bullet->getPhysicsComponent()->rigidBody.velocity.y); - } - */ - DebugDrawer::getInstance().draw(camera->getProjectionMatrix() * camera->getViewMatrix()); + renderer->render(); + /* + for (const auto& bullet : + player->getHeldWeapon()->getBulletManager()->getBullets()) { + DebugDrawer::getInstance().addLine(player->getCenter(), + bullet->getCenter(), glm::vec4(1.f, 0.f, 0.f, 0.f)); DEBUG_TEXT( + glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, + camera.get()->worldToLocal(bullet->getCenter()).y, + 0.f), glm::vec4(1.f, 0.f, 0.f, 1.f), 0.2f, + "( {}, {}, {} )", + bullet->getCenter().x, + bullet->getCenter().y, + bullet->getCenter().z + ); + DEBUG_TEXT( + glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, + camera.get()->worldToLocal(bullet->getCenter()).y + + 10.f, 0.f), glm::vec4(1.f, 1.f, 0.f, 1.f), 0.2f, + "( {}, {} )", + bullet->getPhysicsComponent()->rigidBody.position.x, + bullet->getPhysicsComponent()->rigidBody.position.y + ); + DEBUG_TEXT( + glm::vec3(camera.get()->worldToLocal(bullet->getCenter()).x, + camera.get()->worldToLocal(bullet->getCenter()).y + + 20.f, 0.f), glm::vec4(0.f, 1.f, 1.f, 1.f), 0.2f, + "( {}, {} )", + bullet->getPhysicsComponent()->rigidBody.velocity.x, + bullet->getPhysicsComponent()->rigidBody.velocity.y); + } + */ + + DEBUG_TEXT(glm::vec3(10.f, 10.f, 0.f), glm::vec4(0.f, 0.f, 0.f, 1.f), 0.5f, + "{} / {}", getPlayer()->getHeldWeapon()->getMagazine(), + getPlayer()->getHeldWeapon()->getAmmo()); } -void Scene::unloadScene() -{ - //xmlLoader.reset(); +void Scene::unloadScene() { + // xmlLoader.reset(); } -void Scene::hookSceneEvents() -{ - std::weak_ptr weakSelf = shared_from_this(); - eventManager->subscribe([weakSelf](const BulletCollideEvent& e) { - if (auto self = weakSelf.lock()) { - GameActor* shooter = self->getGameActorByID(e.ownerID); - GameActor* target = self->getGameActorByID(e.victimID); - if (shooter && target) - if (auto weapon = shooter->getHeldWeapon()) - weapon->onHitCallback(target, e.bullet.get(), e.normal); - } - }); +void Scene::hookSceneEvents() { + std::weak_ptr weakSelf = shared_from_this(); + eventManager->subscribe( + [weakSelf](const BulletCollideEvent &e) { + if (auto self = weakSelf.lock()) { + GameActor *shooter = self->getGameActorByID(e.ownerID); + GameActor *target = self->getGameActorByID(e.victimID); + if (shooter && target) + if (auto weapon = shooter->getHeldWeapon()) + weapon->onHitCallback(target, e.bullet.get(), e.normal); + } + }); } -GameActor* Scene::getGameActorByID(const unsigned int ID) -{ - auto iterator = entities.find(ID); - if (iterator == entities.end()) - return nullptr; - return iterator->second.get(); +GameActor *Scene::getGameActorByID(const unsigned int ID) { + auto iterator = entities.find(ID); + if (iterator == entities.end()) + return nullptr; + return iterator->second.get(); } -std::span> Scene::getAllEntities() const -{ - entityCache.clear(); - for (const auto& [_, entity] : entities) { - entityCache.push_back(entity); - } - return entityCache; +std::span> Scene::getAllEntities() const { + entityCache.clear(); + for (const auto &[_, entity] : entities) { + entityCache.push_back(entity); + } + return entityCache; } diff --git a/YuppleMayham/src/graphics/glwindow.cpp b/YuppleMayham/src/graphics/glwindow.cpp new file mode 100644 index 0000000..1c3e538 --- /dev/null +++ b/YuppleMayham/src/graphics/glwindow.cpp @@ -0,0 +1,22 @@ +#include "graphics/glwindow.h" +#include + +bool GLWindow::Init() { + window = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL); + if (!window) { + LOG(ERROR, "Failed to create window! {}", SDL_GetError()); + return false; + } + glContext = SDL_GL_CreateContext(window); + if (!glContext) { + LOG(ERROR, "Failed to create opengl context! {}", SDL_GetError()); + return false; + } + return true; +} + +GLWindow::~GLWindow() { + SDL_GL_DeleteContext(glContext); + SDL_DestroyWindow(window); +} diff --git a/YuppleMayham/src/graphics/renderer.cpp b/YuppleMayham/src/graphics/renderer.cpp index 32448a2..58f1364 100644 --- a/YuppleMayham/src/graphics/renderer.cpp +++ b/YuppleMayham/src/graphics/renderer.cpp @@ -1,221 +1,217 @@ #include "graphics/renderer.h" #include "graphics/shader.h" -#include "utility/resourcemanager.h" -#include "utility/logger.h" #include "utility/events.h" +#include "utility/logger.h" +#include "utility/resourcemanager.h" #include #include #include #include -Renderer::Renderer(const std::shared_ptr& r) - : resourceManager(r) -{ - initFrameBuffers(); - initUniformBuffers(); - screenQuad = std::make_unique(); - postProcessor = std::make_unique(r); +Renderer::Renderer(const std::shared_ptr &r, + const std::shared_ptr &w) + : resourceManager(r), glWindow(w) { + initFrameBuffers(); + initUniformBuffers(); + screenQuad = std::make_unique(); + postProcessor = std::make_unique(r); } -void Renderer::hookEventManager(std::weak_ptr eventManager) -{ - if (auto e = eventManager.lock()) { - e->subscribe([this](const ScreenShakeEvent& event) { - postProcessor->ApplyEffect(Postprocessor::SHAKE, - event.intensity, - event.duration - ); - }); - e->subscribe([this](const ScreenBlurEvent& event) { - postProcessor->ApplyEffect(Postprocessor::BLUR, - event.intensity, - event.duration - ); - }); - } +void Renderer::hookEventManager(std::weak_ptr eventManager) { + if (auto e = eventManager.lock()) { + e->subscribe([this](const ScreenShakeEvent &event) { + postProcessor->ApplyEffect(Postprocessor::SHAKE, event.intensity, + event.duration); + }); + e->subscribe([this](const ScreenBlurEvent &event) { + postProcessor->ApplyEffect(Postprocessor::BLUR, event.intensity, + event.duration); + }); + } } -// Initialize the framebuffers used by the renderer to allow for post-processing effects -void Renderer::initFrameBuffers() -{ - glGenFramebuffers(1, &worldBuffer.frame); - glGenFramebuffers(1, &hudBuffer.frame); - glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame); +// Initialize the framebuffers used by the renderer to allow for post-processing +// effects +void Renderer::initFrameBuffers() { + glGenFramebuffers(1, &worldBuffer.frame); + glGenFramebuffers(1, &hudBuffer.frame); + glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame); - // World buffer creation - glGenTextures(1, &worldBuffer.texture); - glBindTexture(GL_TEXTURE_2D, worldBuffer.texture); - // !!! NEED TO CREATE STATIC WINDOW SIZING !!! - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); + // World buffer creation + glGenTextures(1, &worldBuffer.texture); + glBindTexture(GL_TEXTURE_2D, worldBuffer.texture); - //Attaching empty texture as color buffer for framebuffer - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, worldBuffer.texture, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glWindow->Width(), glWindow->Height(), + 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LOG(ERROR, "Failed to complete world framebuffer: {}", glCheckFramebufferStatus(GL_FRAMEBUFFER)); - assert(1 == 0); // force crash - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // Attaching empty texture as color buffer for framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + worldBuffer.texture, 0); - // same thing is done for the hud texture - glBindFramebuffer(GL_FRAMEBUFFER, hudBuffer.frame); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOG(ERROR, "Failed to complete world framebuffer: {}", + glCheckFramebufferStatus(GL_FRAMEBUFFER)); + assert(1 == 0); // force crash + } - glGenTextures(1, &hudBuffer.texture); - glBindTexture(GL_TEXTURE_2D, hudBuffer.texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 600, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hudBuffer.texture, 0); + // same thing is done for the hud texture + glBindFramebuffer(GL_FRAMEBUFFER, hudBuffer.frame); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LOG(ERROR, "Failed to complete hud framebuffer: {}", glCheckFramebufferStatus(GL_FRAMEBUFFER)); - assert(1 == 0); // force crash - } + glGenTextures(1, &hudBuffer.texture); + glBindTexture(GL_TEXTURE_2D, hudBuffer.texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glWindow->Width(), glWindow->Height(), + 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + hudBuffer.texture, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOG(ERROR, "Failed to complete hud framebuffer: {}", + glCheckFramebufferStatus(GL_FRAMEBUFFER)); + assert(1 == 0); // force crash + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void Renderer::initUniformBuffers() -{ - glGenBuffers(1, &uboMatrices); - - glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); - glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); +void Renderer::initUniformBuffers() { + glGenBuffers(1, &uboMatrices); - glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboMatrices); - //glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * sizeof(glm::mat4)); + glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); + glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboMatrices); + // glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * + // sizeof(glm::mat4)); } -void Renderer::setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view) -{ - glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(proj)); - glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view)); - glBindBuffer(GL_UNIFORM_BUFFER, 0); +void Renderer::setProjAndViewMatrix(const glm::mat4 &proj, + const glm::mat4 &view) { + glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), + glm::value_ptr(proj)); + glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), + glm::value_ptr(view)); + glBindBuffer(GL_UNIFORM_BUFFER, 0); } -void Renderer::addDrawable(RenderLayer renderLayer, Drawable *drawable) -{ - if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu) - HUDLayerPool[renderLayer].push_back(drawable); - else - worldLayerPool[renderLayer].push_back(drawable); +void Renderer::addDrawable(RenderLayer renderLayer, Drawable *drawable) { + if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu) + HUDLayerPool[renderLayer].push_back(drawable); + else + worldLayerPool[renderLayer].push_back(drawable); } -void Renderer::removeDrawable(RenderLayer renderLayer, Drawable *drawable) -{ - auto erase = [&](auto& pool) { - pool.erase(std::remove(pool.begin(), pool.end(), drawable), pool.end()); - }; - if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu) { - erase(HUDLayerPool[renderLayer]); +void Renderer::removeDrawable(RenderLayer renderLayer, Drawable *drawable) { + auto erase = [&](auto &pool) { + pool.erase(std::remove(pool.begin(), pool.end(), drawable), pool.end()); + }; + if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu) { + erase(HUDLayerPool[renderLayer]); + } else + erase(worldLayerPool[renderLayer]); +} + +void Renderer::render() { + // Bind the world frame buffer + glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame); + // clear color and depth buffer + glClearColor(1.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + renderPool(worldLayerPool); + + glBindFramebuffer(GL_FRAMEBUFFER, hudBuffer.frame); + glClearColor(0.0f, 1.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + renderPool(HUDLayerPool); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, worldBuffer.texture); + postProcessor->applyPostProcess(0); + screenQuad->draw(); + + glBindTexture(GL_TEXTURE_2D, hudBuffer.texture); + // postProcessor->applyPostProcess(1); + screenQuad->draw(); +} + +void Renderer::renderPool(auto &layerPool) { + sortLayerPool(layerPool); + Shader *curShader = nullptr; + for (const auto &layer : renderingOrder) { + unsigned curShaderID = static_cast(-1); + for (const auto &item : layerPool[layer]) { + if (item->getShaderID() != curShaderID) { + curShaderID = item->getShaderID(); + curShader = resourceManager->getShaderByID(curShaderID); + curShader->use(); + } + if (!item->getOneShotUniforms().empty()) { + uploadUniforms(curShaderID, item->getOneShotUniforms()); + item->clearOneShot(); + } + uploadUniforms(curShaderID, item->getUniforms()); + item->clearUniforms(); + + item->draw(); } - else - erase(worldLayerPool[renderLayer]); + } } -void Renderer::render() -{ - // Bind the world frame buffer - glBindFramebuffer(GL_FRAMEBUFFER, worldBuffer.frame); - // clear color and depth buffer - glClearColor(1.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - renderPool(worldLayerPool); - - glBindFramebuffer(GL_FRAMEBUFFER, hudBuffer.frame); - glClearColor(0.0f, 1.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - renderPool(HUDLayerPool); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, worldBuffer.texture); - postProcessor->applyPostProcess(0); - screenQuad->draw(); - - glBindTexture(GL_TEXTURE_2D, hudBuffer.texture); - postProcessor->applyPostProcess(1); - screenQuad->draw(); +void Renderer::clear() { + worldLayerPool.clear(); + HUDLayerPool.clear(); } -void Renderer::renderPool(auto& layerPool) -{ - sortLayerPool(layerPool); - Shader* curShader = nullptr; - for (const auto& layer : renderingOrder) { - unsigned curShaderID = static_cast(-1); - for (const auto& item : layerPool[layer]) { - if (item->getShaderID() != curShaderID) { - curShaderID = item->getShaderID(); - curShader = resourceManager->getShaderByID(curShaderID); - curShader->use(); - } - if (!item->getOneShotUniforms().empty()) { - uploadUniforms(curShaderID, item->getOneShotUniforms()); - item->clearOneShot(); - } - uploadUniforms(curShaderID, item->getUniforms()); - item->clearUniforms(); - - item->draw(); - } - } +void Renderer::uploadUniforms(const unsigned shaderID, + const std::vector &uniforms) { + Shader *shader = resourceManager->getShaderByID(shaderID); + if (shader == nullptr) { + LOG(ERROR, "No shader found with id {} !", shaderID); + return; + } + for (const auto &uniform : uniforms) { + std::visit( + [&](auto &&arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + shader->setBool(uniform.name, arg); + } else if constexpr (std::is_same_v) { + shader->setInt(uniform.name, arg); + } else if constexpr (std::is_same_v) { + shader->setFloat(uniform.name, arg); + } else if constexpr (std::is_same_v) { + shader->setVec2(uniform.name, glm::value_ptr(arg)); + } else if constexpr (std::is_same_v) { + shader->setMatrix4f(uniform.name, glm::value_ptr(arg)); + } + }, + uniform.value); + } } - -void Renderer::clear() -{ - worldLayerPool.clear(); - HUDLayerPool.clear(); -} - -void Renderer::uploadUniforms(const unsigned shaderID, const std::vector& uniforms) -{ - Shader *shader = resourceManager->getShaderByID(shaderID); - if (shader == nullptr) { - LOG(ERROR, "No shader found with id {} !", shaderID); - return; - } - for (const auto& uniform : uniforms) { - std::visit([&](auto&& arg) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - shader->setBool(uniform.name, arg); - } - else if constexpr (std::is_same_v) { - shader->setInt(uniform.name, arg); - } - else if constexpr (std::is_same_v) { - shader->setFloat(uniform.name, arg); - } - else if constexpr (std::is_same_v) { - shader->setVec2(uniform.name, glm::value_ptr(arg)); - } - else if constexpr (std::is_same_v) { - shader->setMatrix4f(uniform.name, glm::value_ptr(arg)); - } - }, uniform.value); - } -} -void Renderer::sortLayerPool(auto& layerPool) -{ - // Sort by shader id, this works to batch shaders together to avoid shader switching too much - for (auto& [_,pool] : layerPool) { - std::sort(pool.begin(), pool.end(), - [](const Drawable* a, const Drawable* b) { - return a->getShaderID() < b->getShaderID(); - }); - } +void Renderer::sortLayerPool(auto &layerPool) { + // Sort by shader id, this works to batch shaders together to avoid shader + // switching too much + for (auto &[_, pool] : layerPool) { + std::sort(pool.begin(), pool.end(), + [](const Drawable *a, const Drawable *b) { + return a->getShaderID() < b->getShaderID(); + }); + } } diff --git a/YuppleMayham/src/main.cpp b/YuppleMayham/src/main.cpp index b36147e..0662718 100644 --- a/YuppleMayham/src/main.cpp +++ b/YuppleMayham/src/main.cpp @@ -1,28 +1,22 @@ -#undef GLM_FORCE_FAST_MATH -#define GLM_FORCE_PURE -#define GLM_FORCE_CTOR_INIT -#define GLM_FORCE_COLUMN_MAJOR #include #include #include #include -// TODO: Fix circular dependency issues, mostly with input.h needing gameactor.h and command.h #include "gameplay/game.h" - -const float vertices[] = { - 0.0f, 0.5f, 0.0f, - -0.5f, -0.5f, 0.0f, - 0.5f, -0.5f, 0.0f -}; +#include "utility/logger.h" int main(int argc, char* args[]) { - if (SDL_Init(SDL_INIT_VIDEO) < 0) + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + LOG(ERROR, "Failed to initialize SDL!", NULL); return -1; - if (IMG_Init(IMG_INIT_PNG) < 0) + } + if (IMG_Init(IMG_INIT_PNG) < 0) { + LOG(ERROR, "Could not initialize png library", NULL); return -1; + } SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); @@ -31,13 +25,13 @@ int main(int argc, char* args[]) Game* game = new Game(); if (!game->init()) { - std::cout << "Failed to init game!" << std::endl; + LOG(ERROR, "Failed to init game!", NULL); return -1; } if (!game->loadDebugScene()) { - std::cout << "Failed to load debug scene!" << std::endl; + LOG(ERROR, "Failed to load debug scene!", NULL); return -1; }