Changed the rendering system for layering and less shader switching. Noticable speed improvement

This commit is contained in:
Ethan Adams 2025-01-30 22:17:38 -05:00
parent 169cc6d617
commit 95fa07b183
34 changed files with 377 additions and 90 deletions

View file

@ -1,7 +1,7 @@
# CMakeList.txt : Top-level CMake project file, do global configuration # CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here. # and include sub-projects here.
# #
cmake_minimum_required (VERSION 3.8) cmake_minimum_required (VERSION 3.11)
# Enable Hot Reload for MSVC compilers if supported. # Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141) if (POLICY CMP0141)
@ -9,6 +9,22 @@ if (POLICY CMP0141)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>") set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif() endif()
include(FetchContent)
SET(TRACY_ENABLE 1)
SET(TRACY_ON_DEMAND 1)
SET(TRACY_ONLY_LOCALHOST 1)
FetchContent_Declare(
tracy
GIT_REPOSITORY https://github.com/wolfpld/tracy.git
GIT_TAG v0.11.1
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(tracy)
project ("YuppleMayham") project ("YuppleMayham")
# Include sub-projects. # Include sub-projects.

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<scene type="shooter" id="000"> <scene type="shooter" id="000" bg="backgrounds/blue_sky.png">
<map name="newmap"/> <map name="newmap"/>
<entities> <entities>
<player x="7" y="5" weapon="shotGun"> <player x="7" y="5" weapon="shotGun">

View file

@ -0,0 +1,11 @@
#version 330 core
in vec2 texCoord;
out vec4 FragColor;
uniform sampler2D sprite;
void main()
{
FragColor = texture(sprite, texCoord) * vec4(1.0, 0.8, 1.0, 1.0);
}

View file

@ -0,0 +1,15 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
uniform mat4 projection;
uniform mat4 view;
void main()
{
texCoord = aTexCoord;
gl_Position = projection * vec4(aPos.xyz, 1.0);
}

View file

@ -9,7 +9,7 @@ layout (location = 6) in vec2 aOriginalSize;
layout (location = 7) in mat4 aModel; layout (location = 7) in mat4 aModel;
uniform vec2 uCanvasSize; uniform vec2 uCanvasSize;
uniform mat4 proj; uniform mat4 projection;
uniform mat4 view; uniform mat4 view;
out vec2 texCoord; out vec2 texCoord;
@ -18,7 +18,7 @@ flat out int textureIndex;
void main() void main()
{ {
int tilesPerRow = aTilesPerRow; int tilesPerRow = aTilesPerRow;
gl_Position = proj * view * aModel * vec4(aPos, 1.0); gl_Position = projection * view * aModel * vec4(aPos, 1.0);
textureIndex = aTextureIndex; textureIndex = aTextureIndex;
if (aTileIndex != 0) if (aTileIndex != 0)
{ {

View file

@ -67,7 +67,12 @@ add_executable (YuppleMayham
"include/utility/raycaster.h" "include/utility/raycaster.h"
"include/utility/ftfont.h" "include/utility/ftfont.h"
"include/utility/direction.h" "include/utility/direction.h"
"include/graphics/animation.h" "src/graphics/animation.cpp" "include/utility/logger.h" "src/utility/logger.cpp") "include/graphics/animation.h"
"src/graphics/animation.cpp"
"include/utility/logger.h"
"src/utility/logger.cpp"
"include/graphics/renderer.h"
"src/graphics/renderer.cpp")
add_custom_command(TARGET YuppleMayham PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Resources/ $<TARGET_FILE_DIR:YuppleMayham>) add_custom_command(TARGET YuppleMayham PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Resources/ $<TARGET_FILE_DIR:YuppleMayham>)
@ -75,6 +80,6 @@ if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET YuppleMayham PROPERTY CXX_STANDARD 20) set_property(TARGET YuppleMayham PROPERTY CXX_STANDARD 20)
endif() endif()
target_link_libraries(YuppleMayham SDL2::SDL2main SDL2::SDL2 SDL2_image::SDL2_image tinyxml2 lua_static freetype) target_link_libraries(YuppleMayham SDL2::SDL2main SDL2::SDL2 SDL2_image::SDL2_image tinyxml2 lua_static freetype Tracy::TracyClient)
# TODO: Add tests and install targets if needed. # TODO: Add tests and install targets if needed.

View file

@ -6,23 +6,22 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <SDL_timer.h> #include <SDL_timer.h>
#include "graphics/shader.h" #include "graphics/renderer.h"
class Camera; class Camera;
struct PhysicsComponent; struct PhysicsComponent;
// TODO: Allow speed to be changed and add speed as creation value in XML File! // TODO: Allow speed to be changed and add speed as creation value in XML File!
// TODO: Create Entity System that loads entity types and creates them in scene according to name. // TODO: Create Entity System that loads entity types and creates them in scene according to name.
class Entity class Entity : public Drawable
{ {
public: public:
Entity(const std::shared_ptr<Shader>& shader) : Entity(unsigned shaderID) :
shader(shader),
position(glm::vec3(0.0f)), position(glm::vec3(0.0f)),
scale(glm::vec3(1.0f)), scale(glm::vec3(1.0f)),
rotation(0.0f), rotation(0.0f),
speed(20.0f), speed(20.0f),
entityid(SDL_GetTicks()) entityid(SDL_GetTicks())
{}; { this->shaderID = shaderID; };
virtual ~Entity() {}; virtual ~Entity() {};
void setPosition(const glm::vec3& position); void setPosition(const glm::vec3& position);
@ -44,11 +43,11 @@ public:
const bool getIsMoving() const { return isMoving; } const bool getIsMoving() const { return isMoving; }
const int getEntityID() const { return entityid; } const int getEntityID() const { return entityid; }
const std::shared_ptr<PhysicsComponent> getPhysicsComponent() const { return physics; } const std::shared_ptr<PhysicsComponent> getPhysicsComponent() const { return physics; }
const std::shared_ptr<Shader> getShader() const { return shader; } const unsigned getShaderID() const { return shaderID; }
// TODO: right now there is no default behavior, but eventually the Entity class will be expanded to handle physics // TODO: right now there is no default behavior, but eventually the Entity class will be expanded to handle physics
virtual void update(double deltaTime) = 0; virtual void update(double deltaTime) = 0;
virtual void render(const std::shared_ptr<Camera>& camera) = 0; virtual void draw() = 0;
protected: protected:
glm::vec3 localPosition; glm::vec3 localPosition;
@ -70,8 +69,6 @@ protected:
glm::mat4 modelMatrix; glm::mat4 modelMatrix;
void updateModelMatrix(); void updateModelMatrix();
std::shared_ptr<Shader> shader;
}; };

View file

@ -8,6 +8,7 @@ class InputHandler;
class Scene; class Scene;
class Text; class Text;
class ResourceManager; class ResourceManager;
class Renderer;
class GLWindow; class GLWindow;
enum { enum {
@ -45,6 +46,7 @@ private:
std::shared_ptr<Scene> currentScene; std::shared_ptr<Scene> currentScene;
std::shared_ptr<InputHandler> inputHandler; std::shared_ptr<InputHandler> inputHandler;
std::shared_ptr<ResourceManager> resourceManager; std::shared_ptr<ResourceManager> resourceManager;
std::shared_ptr<Renderer> renderer;
std::shared_ptr<Text> textHandler; std::shared_ptr<Text> textHandler;
}; };

View file

@ -19,16 +19,16 @@ class EventManager;
class GameActor : public Entity class GameActor : public Entity
{ {
public: public:
GameActor(const std::shared_ptr<Shader>& shader) : Entity(shader) {} GameActor(const unsigned shaderID) : Entity(shaderID) {}
~GameActor(); ~GameActor();
void addComponent(std::shared_ptr<Component> component); void addComponent(std::shared_ptr<Component> component);
void pickupWeapon(std::shared_ptr<Weapon> weapon); void pickupWeapon(std::shared_ptr<Weapon> weapon);
void hookEventManager(std::shared_ptr<EventManager> eventManager); void hookEventManager(std::shared_ptr<EventManager> eventManager);
void update(double deltaTime) override; void update(double deltaTime) override;
void render(const std::shared_ptr<Camera>& camera) override; void draw() override;
const std::optional<std::shared_ptr<Weapon>> getHeldWeapon() const; const std::shared_ptr<Weapon> getHeldWeapon() const;
void setRotation(const float& rotation) override; void setRotation(const float& rotation) override;

View file

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include "graphics/instancedraw.h" #include "graphics/instancedraw.h"
#include "graphics/renderer.h"
class Shader; class Shader;
class Camera; class Camera;
@ -12,14 +13,14 @@ class ResourceManager;
struct MapData; struct MapData;
struct TileSetData; struct TileSetData;
class Map class Map : public Drawable
{ {
public: public:
Map(std::shared_ptr<MapData> mapData, const std::shared_ptr<Shader>& shader, std::shared_ptr<ResourceManager> resourceManager); Map(std::shared_ptr<MapData> mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager);
const std::vector<std::vector<int>> getCollisionMap() const { return collisionMap; } const std::vector<std::vector<int>> getCollisionMap() const { return collisionMap; }
void render(const std::shared_ptr<Camera>& camera); void draw() override;
private: private:
void loadMap(); void loadMap();
@ -31,7 +32,6 @@ private:
std::vector<std::shared_ptr<TileSetData>> tileSetData; std::vector<std::shared_ptr<TileSetData>> tileSetData;
std::vector<std::shared_ptr<TileTextureInstance>> instanceHandles; std::vector<std::shared_ptr<TileTextureInstance>> instanceHandles;
std::shared_ptr<Shader> shader;
std::vector<std::vector<std::vector<int>>> tileIds; std::vector<std::vector<std::vector<int>>> tileIds;
std::vector<std::vector<int>> collisionMap; std::vector<std::vector<int>> collisionMap;
std::vector<std::vector<InstanceData>> tileData; std::vector<std::vector<InstanceData>> tileData;

View file

@ -9,10 +9,13 @@ class Entity;
class Camera; class Camera;
class Map; class Map;
class ResourceManager; class ResourceManager;
class Renderer;
class EventManager; class EventManager;
class GameActor; class GameActor;
class Line; class Line;
class PhysicsEngine; class PhysicsEngine;
class Sprite;
class Shader;
struct SceneData; struct SceneData;
@ -27,7 +30,7 @@ public:
Scene(SceneType type, std::shared_ptr<ResourceManager> resources); Scene(SceneType type, std::shared_ptr<ResourceManager> resources);
void update(double deltaTime); void update(double deltaTime);
void render(); void render(std::shared_ptr<Renderer> renderer);
std::shared_ptr<GameActor> getPlayer() const; std::shared_ptr<GameActor> getPlayer() const;

View file

@ -14,14 +14,14 @@ public:
Bullet Bullet
( (
const unsigned int owner, const unsigned int owner,
std::shared_ptr<Shader> shader, unsigned shaderID,
glm::vec3 fireFrom, glm::vec3 fireFrom,
glm::vec2 direction, glm::vec2 direction,
float bulletSpeed, float bulletSpeed,
float bulletDrop, float bulletDrop,
glm::vec2 bulletSize glm::vec2 bulletSize
) : ) :
Entity(shader), Entity(shaderID),
origin(fireFrom), origin(fireFrom),
direction(direction), direction(direction),
bulletSpeed(bulletSpeed), bulletSpeed(bulletSpeed),
@ -36,7 +36,7 @@ public:
void addComponent(std::shared_ptr<Component> component); void addComponent(std::shared_ptr<Component> component);
void update(double deltaTime) override; void update(double deltaTime) override;
void render(const std::shared_ptr<Camera>& camera) override; void draw() override;
float getBulletDrop() const { return bulletDrop; } float getBulletDrop() const { return bulletDrop; }
glm::vec3 getBulletOrigin() const { return origin; } glm::vec3 getBulletOrigin() const { return origin; }

View file

@ -22,14 +22,16 @@ public:
float bulletSpeed, float bulletSpeed,
float bulletDrop, float bulletDrop,
glm::vec2 bulletSize, glm::vec2 bulletSize,
const std::shared_ptr<Shader>& shader, const unsigned& shaderID,
const std::shared_ptr<Component>& sprite); const std::shared_ptr<Component>& sprite);
void update(double deltaTime); void update(double deltaTime);
void render(const std::shared_ptr<Camera>& camera); void draw();
void hookEventManager(const std::shared_ptr<EventManager>& eventManager); void hookEventManager(const std::shared_ptr<EventManager>& eventManager);
const std::vector<std::shared_ptr<Bullet>> getBullets() { return bullets; }
private: private:
std::vector<std::shared_ptr<Bullet>> bullets; std::vector<std::shared_ptr<Bullet>> bullets;
std::shared_ptr<EventManager> eventManager; std::shared_ptr<EventManager> eventManager;

View file

@ -27,7 +27,7 @@ struct WeaponData;
class Weapon : public Entity, public std::enable_shared_from_this<Weapon> class Weapon : public Entity, public std::enable_shared_from_this<Weapon>
{ {
public: public:
Weapon(std::shared_ptr<WeaponData> data, const std::shared_ptr<Shader>& weaponShader, const std::shared_ptr<Shader>& bulletShader, ResourceManager* resourceManager); Weapon(std::shared_ptr<WeaponData> data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager);
void setWielder(const std::shared_ptr<GameActor>& wielder) { this->wielder = wielder; } void setWielder(const std::shared_ptr<GameActor>& wielder) { this->wielder = wielder; }
void toggleInfiniteAmmo() { infiniteAmmo = !infiniteAmmo; } void toggleInfiniteAmmo() { infiniteAmmo = !infiniteAmmo; }
@ -40,7 +40,7 @@ public:
void shoot(); void shoot();
void reload(); void reload();
void update(double deltaTime); void update(double deltaTime);
void render(const std::shared_ptr<Camera>& camera); void draw();
struct BulletData { struct BulletData {
glm::vec3 origin; glm::vec3 origin;
@ -65,6 +65,8 @@ public:
Weapon::BulletData genBulletData (); Weapon::BulletData genBulletData ();
void createBullet (const BulletData& data); void createBullet (const BulletData& data);
const std::shared_ptr<BulletManager>& getBulletManager() { return bulletManager; }
private: private:
void adjustWeapon(); void adjustWeapon();
@ -82,7 +84,7 @@ private:
// in ms // in ms
float fireSpeed; float fireSpeed;
glm::vec2 bulletSize; glm::vec2 bulletSize;
std::shared_ptr<Shader> bulletShader; unsigned bulletShaderID;
std::shared_ptr<Component> bulletSprite; std::shared_ptr<Component> bulletSprite;
std::shared_ptr<BulletManager> bulletManager; std::shared_ptr<BulletManager> bulletManager;
std::shared_ptr<EventManager> eventManager; std::shared_ptr<EventManager> eventManager;

View file

@ -0,0 +1,94 @@
#ifndef _H_RENDERER_H
#define _H_RENDERER_H
#include <unordered_map>
#include <memory>
#include <variant>
#include <string>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
class ResourceManager;
enum class RenderLayer {
Background,
Map,
GameObjects,
Effects,
HUD,
Menu
};
using UniformValue = std::variant<
int,
bool,
float,
double,
glm::mat4,
glm::vec2
>;
struct Uniform {
std::string name;
UniformValue value;
};
class Drawable
{
public:
virtual void draw() = 0;
const unsigned getShaderID() const { return shaderID; }
const std::vector<Uniform>& getUniforms() { return uniforms; }
const std::vector<Uniform>& getOneShotUniforms() { return oneShotUniforms; }
void clearOneShot() { oneShotUniforms.clear(); }
void clearUniforms() { uniforms.clear(); }
protected:
unsigned shaderID;
template <typename T>
void editUniform(const std::string& name, T value)
{
uniforms.emplace_back(Uniform {name, value});
}
template <typename T>
void editUniformOnce(const std::string& name, T value)
{
oneShotUniforms.emplace_back(Uniform {name, value});
}
private:
std::vector<Uniform> uniforms;
std::vector<Uniform> oneShotUniforms;
};
class Renderer
{
public:
Renderer(const std::shared_ptr<ResourceManager>&);
void clear();
void setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view);
void addDrawable(RenderLayer renderLayer, std::shared_ptr<Drawable> drawable);
void removeDrawable(RenderLayer renderLayer, std::shared_ptr<Drawable> drawable);
void render();
private:
std::unordered_map<RenderLayer, std::vector<std::shared_ptr<Drawable>>> layerPool;
std::vector<RenderLayer> renderingOrder = {
RenderLayer::Background,
RenderLayer::Map,
RenderLayer::GameObjects,
RenderLayer::Effects,
RenderLayer::HUD,
RenderLayer::Menu
};
void uploadUniforms(const unsigned shaderID, const std::vector<Uniform>& uniforms);
glm::mat4 projMat;
glm::mat4 viewMat;
std::shared_ptr<ResourceManager> resourceManager;
};
#endif

View file

@ -24,6 +24,8 @@ public:
void bind(); void bind();
virtual void draw() = 0; virtual void draw() = 0;
bool loaded() const;
virtual std::shared_ptr<Sprite> clone() const = 0; virtual std::shared_ptr<Sprite> clone() const = 0;
protected: protected:
Texture* texture = nullptr; Texture* texture = nullptr;

View file

@ -6,11 +6,11 @@
#include <string> #include <string>
#include "utility/xmlloader.h" #include "utility/xmlloader.h"
#include "graphics/shader.h"
#include <cassert> #include <cassert>
class Sprite; class Sprite;
class SpriteAtlas; class SpriteAtlas;
class Shader;
class Weapon; class Weapon;
class Script; class Script;
class AnimationSet; class AnimationSet;
@ -37,19 +37,22 @@ public:
std::shared_ptr<AIScript> loadAIScript (const std::string& path); std::shared_ptr<AIScript> loadAIScript (const std::string& path);
std::shared_ptr<WeaponScript> loadWeaponScript (const std::string& path); std::shared_ptr<WeaponScript> loadWeaponScript (const std::string& path);
std::shared_ptr<Shader> loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath); const unsigned loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath);
std::shared_ptr<Weapon> loadWeapon (const std::string& name, std::shared_ptr<Shader> weaponShader, std::shared_ptr<Shader> bulletShader); std::shared_ptr<Weapon> loadWeapon (const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID);
std::shared_ptr<SceneData> loadScene (const std::string& id); std::shared_ptr<SceneData> loadScene (const std::string& id);
std::shared_ptr<AnimationSet> loadAnimationSet(const std::string& name, int entityid = 0); std::shared_ptr<AnimationSet> loadAnimationSet(const std::string& name, int entityid = 0);
std::shared_ptr<TileSetData> loadTileSet (const std::string& name); std::shared_ptr<TileSetData> loadTileSet (const std::string& name);
Shader* getShaderByID(unsigned int ID);
void clearResources(); void clearResources();
~ResourceManager(); ~ResourceManager();
private: private:
std::unordered_map<std::string, std::unique_ptr<Shader>> shaders;
std::unordered_map<unsigned, Shader*> shaderIDs;
std::unordered_map<std::string, std::shared_ptr<Sprite>> sprites; std::unordered_map<std::string, std::shared_ptr<Sprite>> sprites;
std::unordered_map<std::string, std::shared_ptr<Shader>> shaders;
std::unordered_map<std::string, std::shared_ptr<Weapon>> weapons; std::unordered_map<std::string, std::shared_ptr<Weapon>> weapons;
std::unordered_map<std::string, std::shared_ptr<Script>> scripts; std::unordered_map<std::string, std::shared_ptr<Script>> scripts;
std::unordered_map<std::string, std::shared_ptr<TileSetData>>tileSets; std::unordered_map<std::string, std::shared_ptr<TileSetData>>tileSets;

View file

@ -65,6 +65,7 @@ struct TileSetData {
struct SceneData { struct SceneData {
std::string id; std::string id;
std::string type; std::string type;
std::string bgFile;
std::shared_ptr<MapData> map; std::shared_ptr<MapData> map;
std::vector<EntityData> entities; std::vector<EntityData> entities;

View file

@ -4,6 +4,8 @@
#include "utility/raycaster.h" #include "utility/raycaster.h"
#include "utility/script.h" #include "utility/script.h"
#include <tracy/Tracy.hpp>
AI::AI(const std::shared_ptr<GameActor>& actor, const std::shared_ptr<Raycaster>& raycaster) AI::AI(const std::shared_ptr<GameActor>& actor, const std::shared_ptr<Raycaster>& raycaster)
: actor(actor), raycaster(raycaster), state(AIState::Idle), : actor(actor), raycaster(raycaster), state(AIState::Idle),

View file

@ -54,14 +54,11 @@ void Entity::update(double deltaTime)
} }
} }
void Entity::render(const std::shared_ptr<Camera>& camera) void Entity::draw()
{ {
//glm::mat4 mvp = camera->getProjectionMatrix() * camera->getViewMatrix() * modelMatrix; //glm::mat4 mvp = camera->getProjectionMatrix() * camera->getViewMatrix() * modelMatrix;
shader->use(); editUniform("model", modelMatrix);
shader->setMatrix4f("model", glm::value_ptr(modelMatrix)); editUniform("flip", flipped);
shader->setMatrix4f("projection", glm::value_ptr(camera->getProjectionMatrix()));
shader->setMatrix4f("view", glm::value_ptr(camera->getViewMatrix()));
shader->setBool("flip", flipped);
} }
void Entity::updateModelMatrix() void Entity::updateModelMatrix()

View file

@ -50,6 +50,7 @@ bool Game::init()
game_state |= GAME_RUNNING; game_state |= GAME_RUNNING;
resourceManager = std::make_shared<ResourceManager>(); resourceManager = std::make_shared<ResourceManager>();
renderer = std::make_shared<Renderer>(resourceManager);
textHandler = std::make_shared<Text>(); textHandler = std::make_shared<Text>();
if (!textHandler->loadFonts("fonts")) if (!textHandler->loadFonts("fonts"))
return false; return false;
@ -88,11 +89,11 @@ void Game::render()
if (currentScene) if (currentScene)
{ {
currentScene->render(); currentScene->render(renderer);
/*Debug ammo indicator*/ /*Debug ammo indicator*/
textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->get()->getMagazine()), glm::vec2(10, 10), 0.5f); 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", "/", glm::vec2(50, 10), 0.5f);
textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->get()->getAmmo()), glm::vec2(90, 10), 0.5f); textHandler->DrawText("comic.ttf", std::to_string(currentScene->getPlayer()->getHeldWeapon()->getAmmo()), glm::vec2(90, 10), 0.5f);
} }
window->swap(); window->swap();

View file

@ -14,9 +14,9 @@ void GameActor::addComponent(std::shared_ptr<Component> component)
components.push_back(component); components.push_back(component);
} }
const std::optional<std::shared_ptr<Weapon>> GameActor::getHeldWeapon() const const std::shared_ptr<Weapon> GameActor::getHeldWeapon() const
{ {
return (weapons.empty() || currentWeaponIndex >= weapons.size()) ? std::nullopt : std::make_optional(weapons[currentWeaponIndex]); return (weapons.empty() || currentWeaponIndex >= weapons.size()) ? nullptr : weapons[currentWeaponIndex];
} }
void GameActor::pickupWeapon(std::shared_ptr<Weapon> weapon) void GameActor::pickupWeapon(std::shared_ptr<Weapon> weapon)
@ -24,9 +24,9 @@ void GameActor::pickupWeapon(std::shared_ptr<Weapon> weapon)
weapon->setWielder(std::shared_ptr<GameActor>(this)); weapon->setWielder(std::shared_ptr<GameActor>(this));
weapons.push_back(weapon); weapons.push_back(weapon);
// wield the newly picked up weapon. // wield the newly picked up weapon.
getHeldWeapon().value()->putaway(); getHeldWeapon()->putaway();
currentWeaponIndex = weapons.size() - 1; currentWeaponIndex = weapons.size() - 1;
getHeldWeapon().value()->wield(); getHeldWeapon()->wield();
} }
void GameActor::hookEventManager(std::shared_ptr<EventManager> eventManager) void GameActor::hookEventManager(std::shared_ptr<EventManager> eventManager)
@ -72,9 +72,9 @@ void GameActor::update(double deltaTime)
isMoving = false; isMoving = false;
} }
void GameActor::render(const std::shared_ptr<Camera>& camera) void GameActor::draw()
{ {
Entity::render(camera); Entity::draw();
// regular loop through components, but if the component returns true to kill, we erase it. // regular loop through components, but if the component returns true to kill, we erase it.
// Components are always assumed to be smart pointers! // Components are always assumed to be smart pointers!
@ -83,8 +83,8 @@ void GameActor::render(const std::shared_ptr<Camera>& camera)
component->bind(); component->bind();
component->render(); component->render();
} }
for (auto& weapon : weapons) //for (auto& weapon : weapons)
weapon->render(camera); // weapon->draw();
} }
void GameActor::moveUp() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f,-1.f, 0.f), 1500.25f); isMoving = true; } void GameActor::moveUp() { if (physics) physics->rigidBody.applyForce(glm::vec3( 0.f,-1.f, 0.f), 1500.25f); isMoving = true; }
@ -93,7 +93,7 @@ void GameActor::moveLeft() { if (physics) physics->rigidBody.applyForce(glm::vec
void GameActor::moveRight(){ if (physics) physics->rigidBody.applyForce(glm::vec3( 1.f, 0.f, 0.f), 1500.25f); isMoving = true; } void GameActor::moveRight(){ if (physics) physics->rigidBody.applyForce(glm::vec3( 1.f, 0.f, 0.f), 1500.25f); isMoving = true; }
// top-down shooter mode controls // top-down shooter mode controls
void GameActor::fireWeapon()const { if (auto& weapon = getHeldWeapon()) weapon.value()->shoot(); } void GameActor::fireWeapon()const { if (auto& weapon = getHeldWeapon()) weapon->shoot(); }
void GameActor::cycleUpWeapons() { void GameActor::cycleUpWeapons() {
if (!weapons.empty()) { if (!weapons.empty()) {
weapons[currentWeaponIndex]->putaway(); weapons[currentWeaponIndex]->putaway();

View file

@ -7,11 +7,12 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
Map::Map(std::shared_ptr<MapData> mapData, const std::shared_ptr<Shader>& shader, std::shared_ptr<ResourceManager> resourceManager) : Map::Map(std::shared_ptr<MapData> mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager) :
shader(shader),
mapData(mapData), mapData(mapData),
tileIds(mapData->tiles) tileIds(mapData->tiles)
{ {
this->shaderID = shaderID;
for (auto& tileSet : mapData->tileSets) for (auto& tileSet : mapData->tileSets)
tileSetData.push_back(resourceManager->loadTileSet(tileSet.path)); tileSetData.push_back(resourceManager->loadTileSet(tileSet.path));
@ -61,8 +62,7 @@ void Map::loadMap()
instanceHandles[layer]->updateInstanceData(tileData[layer]); instanceHandles[layer]->updateInstanceData(tileData[layer]);
} }
glm::vec2 canvasSize = glm::vec2(instanceHandles[0]->getTextureArray()->getWidth(), instanceHandles[0]->getTextureArray()->getHeight()); glm::vec2 canvasSize = glm::vec2(instanceHandles[0]->getTextureArray()->getWidth(), instanceHandles[0]->getTextureArray()->getHeight());
shader->use(); editUniformOnce("uCanvasSize", canvasSize);
shader->setVec2("uCanvasSize", glm::value_ptr(canvasSize));
} }
void Map::createCollisionMap() void Map::createCollisionMap()
@ -96,11 +96,8 @@ void Map::createCollisionMap()
} }
} }
void Map::render(const std::shared_ptr<Camera>& camera) void Map::draw()
{ {
shader->use();
shader->setMatrix4f("proj", glm::value_ptr(camera->getProjectionMatrix()));
shader->setMatrix4f("view", glm::value_ptr(camera->getViewMatrix()));
for (int layer = 0; layer < instanceHandles.size(); layer++) for (int layer = 0; layer < instanceHandles.size(); layer++)
{ {
instanceHandles[layer]->draw(); instanceHandles[layer]->draw();

View file

@ -2,6 +2,7 @@
#include "gameplay/camera.h" #include "gameplay/camera.h"
#include "gameplay/gameactor.h" #include "gameplay/gameactor.h"
#include "gameplay/weapons/weapons.h" #include "gameplay/weapons/weapons.h"
#include "gameplay/weapons/bulletmanager.h"
#include "gameplay/map.h" #include "gameplay/map.h"
#include "gameplay/physics.h" #include "gameplay/physics.h"
#include "gameplay/ai.h" #include "gameplay/ai.h"
@ -135,14 +136,28 @@ void Scene::update(double deltaTime)
camera->update(deltaTime); camera->update(deltaTime);
} }
void Scene::render() void Scene::render(std::shared_ptr<Renderer> renderer)
{ {
map->render(camera); renderer->clear();
renderer->setProjAndViewMatrix(camera->getProjectionMatrix(), camera->getViewMatrix());
renderer->addDrawable(RenderLayer::Map, map);
//map->draw();
for (auto& [id, e] : entities) for (auto& [id, e] : entities)
{ {
e->render(camera); //e->draw();
renderer->addDrawable(RenderLayer::GameObjects, e);
if (e->getHeldWeapon()) {
renderer->addDrawable(RenderLayer::GameObjects, e->getHeldWeapon());
for (const auto& bullet : e->getHeldWeapon()->getBulletManager()->getBullets()) {
renderer->addDrawable(RenderLayer::GameObjects, bullet);
} }
}
}
DebugDrawer::getInstance().draw(camera->getProjectionMatrix() * camera->getViewMatrix()); DebugDrawer::getInstance().draw(camera->getProjectionMatrix() * camera->getViewMatrix());
renderer->render();
} }
void Scene::unloadScene() void Scene::unloadScene()
@ -158,7 +173,7 @@ void Scene::hookSceneEvents()
std::shared_ptr<GameActor> target = getGameActorByID(collideEvent->victimID); std::shared_ptr<GameActor> target = getGameActorByID(collideEvent->victimID);
if (shooter && target) if (shooter && target)
if (auto& weapon = shooter->getHeldWeapon()) if (auto& weapon = shooter->getHeldWeapon())
weapon.value()->onHitCallback(target, collideEvent->bullet, collideEvent->normal); weapon->onHitCallback(target, collideEvent->bullet, collideEvent->normal);
}); });
} }

View file

@ -21,9 +21,9 @@ void Bullet::update(double deltaTime)
component->update(); component->update();
} }
void Bullet::render(const std::shared_ptr<Camera>& camera) void Bullet::draw()
{ {
Entity::render(camera); Entity::draw();
for (auto& component : components) for (auto& component : components)
{ {

View file

@ -30,10 +30,10 @@ void BulletManager::addBullet(const unsigned int owner, const glm::vec3& fireFro
float bulletSpeed, float bulletSpeed,
float bulletDrop, float bulletDrop,
glm::vec2 bulletSize, glm::vec2 bulletSize,
const std::shared_ptr<Shader>& shader, const unsigned& shaderID,
const std::shared_ptr<Component>& sprite) const std::shared_ptr<Component>& sprite)
{ {
auto bullet = std::make_shared<Bullet>(owner, shader, fireFrom, direction, bulletSpeed, bulletDrop, bulletSize); auto bullet = std::make_shared<Bullet>(owner, shaderID, fireFrom, direction, bulletSpeed, bulletDrop, bulletSize);
bullet->addComponent(sprite); bullet->addComponent(sprite);
//bullet->addPhysicsComponent(phy) //bullet->addPhysicsComponent(phy)
bullets.emplace_back(bullet); bullets.emplace_back(bullet);
@ -55,11 +55,11 @@ void BulletManager::update(double deltaTime)
} }
} }
void BulletManager::render(const std::shared_ptr<Camera>& camera) void BulletManager::draw()
{ {
for (auto& bullet : bullets) for (auto& bullet : bullets)
{ {
if (!bullet) continue; if (!bullet) continue;
bullet->render(camera); bullet->draw();
} }
} }

View file

@ -14,10 +14,10 @@
// TODO: Regular clean up, make this mess readable! // TODO: Regular clean up, make this mess readable!
Weapon::Weapon(std::shared_ptr<WeaponData> data, const std::shared_ptr<Shader>& weaponShader, const std::shared_ptr<Shader>& bulletShader, ResourceManager* resourceManager) Weapon::Weapon(std::shared_ptr<WeaponData> data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager)
: :
Entity (weaponShader), Entity (weaponShaderID),
bulletShader (bulletShader), bulletShaderID (bulletShaderID),
weaponSize (glm::vec2(data->sizeX, data->sizeY)), weaponSize (glm::vec2(data->sizeX, data->sizeY)),
weaponOffset (glm::vec2(data->offsetX, data->offsetY)), weaponOffset (glm::vec2(data->offsetX, data->offsetY)),
weaponMagSize (data->clipSize), weaponMagSize (data->clipSize),
@ -169,9 +169,9 @@ void Weapon::update(double deltaTime)
bulletManager->update(deltaTime); bulletManager->update(deltaTime);
} }
void Weapon::render(const std::shared_ptr<Camera>& camera) void Weapon::draw()
{ {
Entity::render(camera); Entity::draw();
if (wielded) if (wielded)
{ {
for (auto& component : components) for (auto& component : components)
@ -181,7 +181,7 @@ void Weapon::render(const std::shared_ptr<Camera>& camera)
component->render(); component->render();
} }
} }
bulletManager->render(camera); //bulletManager->draw();
} }
void Weapon::adjustWeapon() void Weapon::adjustWeapon()
@ -241,7 +241,7 @@ Weapon::BulletData Weapon::genBulletData()
void Weapon::createBullet(const Weapon::BulletData& data) void Weapon::createBullet(const Weapon::BulletData& data)
{ {
auto bullet = std::make_shared<Bullet>(wielder->getEntityID(), bulletShader, data.origin, data.direction, bulletSpeed, bulletDrop, bulletSize); auto bullet = std::make_shared<Bullet>(wielder->getEntityID(), bulletShaderID, data.origin, data.direction, bulletSpeed, bulletDrop, bulletSize);
bullet->addComponent(bulletSprite); bullet->addComponent(bulletSprite);
bullet->addPhysicsComponent(std::make_shared<PhysicsComponent>(PhysicsComponentFactory::makeBullet(wielder->getEntityID(), data.origin, data.mass, bulletSize.x / 2))); bullet->addPhysicsComponent(std::make_shared<PhysicsComponent>(PhysicsComponentFactory::makeBullet(wielder->getEntityID(), data.origin, data.mass, bulletSize.x / 2)));
bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * glm::vec3(data.direction.x, data.direction.y, 0.f) / data.mass; bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * glm::vec3(data.direction.x, data.direction.y, 0.f) / data.mass;

View file

@ -0,0 +1,102 @@
#include "graphics/renderer.h"
#include "graphics/shader.h"
#include "utility/resourcemanager.h"
#include "utility/logger.h"
#include <algorithm>
Renderer::Renderer(const std::shared_ptr<ResourceManager>& r)
: resourceManager(r)
{
projMat = glm::mat4(0.f);
viewMat = glm::mat4(0.f);
}
void Renderer::setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view)
{
projMat = proj;
viewMat = view;
}
void Renderer::addDrawable(RenderLayer renderLayer, std::shared_ptr<Drawable> drawable)
{
layerPool[renderLayer].push_back(drawable);
}
void Renderer::removeDrawable(RenderLayer renderLayer, std::shared_ptr<Drawable> drawable)
{
auto& pool = layerPool[renderLayer];
pool.erase(std::remove(pool.begin(), pool.end(), drawable));
}
void Renderer::render()
{
// 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 std::shared_ptr<Drawable>& a, const std::shared_ptr<Drawable>& b) {
return a->getShaderID() < b->getShaderID();
});
}
Shader* curShader = nullptr;
for (const auto& layer : renderingOrder) {
unsigned curShaderID = static_cast<unsigned>(-1);
for (const auto& item : layerPool[layer]) {
if (item->getShaderID() != curShaderID) {
curShaderID = item->getShaderID();
curShader = resourceManager->getShaderByID(curShaderID);
if (curShader) {
curShader->use();
curShader->setMatrix4f("projection", glm::value_ptr(projMat));
curShader->setMatrix4f("view", glm::value_ptr(viewMat));
} else {
LOG(ERROR, "Shader with ID {} not found!", curShaderID);
continue;
}
}
if (!item->getOneShotUniforms().empty()) {
uploadUniforms(curShaderID, item->getOneShotUniforms());
item->clearOneShot();
}
uploadUniforms(curShaderID, item->getUniforms());
item->clearUniforms();
item->draw();
}
}
}
void Renderer::clear()
{
layerPool.clear();
}
void Renderer::uploadUniforms(const unsigned shaderID, const std::vector<Uniform>& 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<decltype(arg)>;
if constexpr (std::is_same_v<T, bool>) {
shader->setBool(uniform.name, arg);
}
else if constexpr (std::is_same_v<T, int>) {
shader->setInt(uniform.name, arg);
}
else if constexpr (std::is_same_v<T, float>) {
shader->setFloat(uniform.name, arg);
}
else if constexpr (std::is_same_v<T, glm::vec2>) {
shader->setVec2(uniform.name, glm::value_ptr(arg));
}
else if constexpr (std::is_same_v<T, glm::mat4>) {
shader->setMatrix4f(uniform.name, glm::value_ptr(arg));
}
}, uniform.value);
}
}

View file

@ -3,6 +3,8 @@
#include "util.h" #include "util.h"
#include "utility/events.h" #include "utility/events.h"
bool Sprite::loaded() const { return (texture != nullptr); }
SpriteStatic::SpriteStatic(const char* texturePath) SpriteStatic::SpriteStatic(const char* texturePath)
{ {
EBO = 0, VBO = 0, VAO = 0; EBO = 0, VBO = 0, VAO = 0;
@ -10,6 +12,8 @@ SpriteStatic::SpriteStatic(const char* texturePath)
texture->loadTexture(texturePath); texture->loadTexture(texturePath);
if (texture) if (texture)
setupSprite(); setupSprite();
else
delete texture;
} }
void SpriteStatic::setupSprite() void SpriteStatic::setupSprite()
@ -71,6 +75,8 @@ SpriteAtlas::SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isD
else else
SetupDirectional(frameSize); SetupDirectional(frameSize);
} }
else
delete texture;
} }
void SpriteAtlas::Setup(float frameSize) void SpriteAtlas::Setup(float frameSize)

View file

@ -1,7 +1,6 @@
#include <SDL.h> #include <SDL.h>
#include <SDL_image.h> #include <SDL_image.h>
#include <iostream> #include <iostream>
// TODO: Fix circular dependency issues, mostly with input.h needing gameactor.h and command.h // TODO: Fix circular dependency issues, mostly with input.h needing gameactor.h and command.h

View file

@ -22,6 +22,8 @@ std::shared_ptr<Sprite> ResourceManager::loadSpriteStatic(const std::string& pat
if (iterator != sprites.end()) if (iterator != sprites.end())
return iterator->second; return iterator->second;
auto sprite = std::make_shared<SpriteStatic>(path.c_str()); auto sprite = std::make_shared<SpriteStatic>(path.c_str());
if (!sprite->loaded())
return nullptr;
sprites[path] = sprite; sprites[path] = sprite;
return sprite; return sprite;
} }
@ -41,22 +43,30 @@ std::shared_ptr<TileSetData> ResourceManager::loadTileSet(const std::string& nam
return xmlLoader->getTileSetData(name); return xmlLoader->getTileSetData(name);
} }
std::shared_ptr<Shader> ResourceManager::loadShader(const std::string& name, const std::string& vertexPath, const std::string& fragPath) const unsigned ResourceManager::loadShader(const std::string& name, const std::string& vertexPath, const std::string& fragPath)
{ {
auto iterator = shaders.find(name); auto iterator = shaders.find(name);
if (iterator != shaders.end()) if (iterator != shaders.end())
return iterator->second; return iterator->second->ID;
auto shader = std::make_shared<Shader>(vertexPath.c_str(), fragPath.c_str()); auto shader = std::make_unique<Shader>(vertexPath.c_str(), fragPath.c_str());
shaders[name] = shader; unsigned id = shader->ID;
return shader; shaderIDs[shader->ID] = shader.get();
shaders[name] = std::move(shader);
return id;
}
Shader* ResourceManager::getShaderByID(unsigned int ID)
{
auto iterator = shaderIDs.find(ID);
return (iterator != shaderIDs.end() ? iterator->second : nullptr);
} }
// We attach our script after we create our weapon because we are passing a reference to the weapon into the script and we don't want to pass an // We attach our script after we create our weapon because we are passing a reference to the weapon into the script and we don't want to pass an
// incomplete reference to our script. // incomplete reference to our script.
std::shared_ptr<Weapon> ResourceManager::loadWeapon(const std::string& name, std::shared_ptr<Shader> weaponShader, std::shared_ptr<Shader> shader) std::shared_ptr<Weapon> ResourceManager::loadWeapon(const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID)
{ {
std::shared_ptr<WeaponData> data = xmlLoader->getWeaponData(name); std::shared_ptr<WeaponData> data = xmlLoader->getWeaponData(name);
auto weapon = std::make_shared<Weapon>(data, weaponShader, shader, this); auto weapon = std::make_shared<Weapon>(data, weaponShaderID, bulletShaderID, this);
if (!data->script.empty()) if (!data->script.empty())
weapon->attachScript(loadWeaponScript(data->script)); weapon->attachScript(loadWeaponScript(data->script));
return weapon; return weapon;
@ -92,6 +102,7 @@ void ResourceManager::clearResources()
{ {
sprites.clear(); sprites.clear();
shaders.clear(); shaders.clear();
shaderIDs.clear();
weapons.clear(); weapons.clear();
tileSets.clear(); tileSets.clear();
} }

View file

@ -33,13 +33,17 @@ bool XMLLoader::loadXmlScene(const char* xmlFile, SceneData* out)
ERROR_LOG("Failed to load file: {}", xmlFile); ERROR_LOG("Failed to load file: {}", xmlFile);
tinyxml2::XMLElement* scene = doc.FirstChildElement("scene"); tinyxml2::XMLElement* scene = doc.FirstChildElement("scene");
const char* type, * id, * mapName; const char* type, * id, * mapName, * bgFile;
if (scene->QueryStringAttribute("type", &type) != tinyxml2::XML_SUCCESS || if (scene->QueryStringAttribute("type", &type) != tinyxml2::XML_SUCCESS ||
scene->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS) scene->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS)
ERROR_LOG("Could not read type or id tag in file: {}", xmlFile); ERROR_LOG("Could not read type or id tag in file: {}", xmlFile);
out->type = type; out->type = type;
out->id = id; out->id = id;
if (scene->QueryStringAttribute("bg", &bgFile) != tinyxml2::XML_SUCCESS)
LOG(WARN, "No background set! attribute 'bg' is empty");
else
out->bgFile = bgFile;
tinyxml2::XMLElement* map = scene->FirstChildElement("map"); tinyxml2::XMLElement* map = scene->FirstChildElement("map");
if (map == NULL) if (map == NULL)