Added framebuffers for world and hud for postprocessing. Also fixed a nagging NDC issue

This commit is contained in:
Ethan Adams 2025-02-24 21:30:48 -05:00
parent f7f68e500b
commit 5501a13488
29 changed files with 388 additions and 135 deletions

13
.vscode/settings.json vendored
View file

@ -1,5 +1,16 @@
{
"files.associations": {
"memory": "cpp"
"memory": "cpp",
"execution": "cpp",
"algorithm": "cpp",
"iostream": "cpp",
"charconv": "cpp",
"format": "cpp",
"random": "cpp",
"sstream": "cpp",
"xhash": "cpp",
"xlocnum": "cpp",
"xmemory": "cpp",
"cassert": "cpp"
}
}

View file

@ -32,8 +32,8 @@
"scale": 0.75,
"selectedLayer": 2,
"viewCenter": {
"x": 989.3333333333334,
"y": 665.3333333333334
"x": 1440,
"y": 872
}
},
"newmap.tmx": {
@ -41,7 +41,7 @@
"selectedLayer": 1,
"viewCenter": {
"x": 930,
"y": 621
"y": 620
}
},
"shooterWorldOneAtlas.tsx": {

View file

@ -7,5 +7,5 @@ uniform sampler2D sprite;
void main()
{
FragColor = texture(sprite, texCoord) * vec4(1.0, 0.8, 1.0, 1.0);
FragColor = texture(sprite, texCoord);
}

View file

@ -0,0 +1,16 @@
#version 330 core
out vec4 FragColor;
in vec2 texCoord;
uniform sampler2D screenTexture;
void main()
{
//FragColor = texture(screenTexture, texCoord);
vec4 color = texture(screenTexture, texCoord);
if (color.rgb == vec3(0.0, 0.0, 0.0))
FragColor = vec4(0.0, 0.0, 1.0, 1.0);
else
FragColor = color;
}

View file

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main()
{
texCoord = aTexCoord;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}

View file

@ -0,0 +1,12 @@
#version 330 core
out vec4 FragColor;
in vec2 texCoord;
uniform sampler2D world_color;
void main()
{
//FragColor = vec4(0.0, 1.0, 1.0, 1.0);
FragColor = mix(texture(world_color, texCoord), vec4(0.4, 0.2, 0.2, 1.0), 0.2);
}

View file

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 texCoord;
void main()
{
texCoord = aTexCoord;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}

View file

@ -58,6 +58,7 @@ add_executable (YuppleMayham
"include/gameplay/scene.h"
"include/graphics/texture.h"
"src/graphics/quad.cpp"
"include/utility/resourcemanager.h"
"include/utility/xmlloader.h"

View file

@ -7,7 +7,7 @@ class Camera
{
public:
Camera(float viewPortW, float viewPortH) :
position(glm::vec3(0.0f, 0.0f, 1.0f)),
position(glm::vec3(0.0f, 0.0f, 0.0f)),
front(glm::vec3(0.0f, 0.0f, -1.0f)),
up(glm::vec3(0.0f, 1.0f, 0.0f)),
viewPortW(viewPortW),
@ -22,9 +22,9 @@ public:
void unsetTarget() { target = nullptr; }
bool isTargeting() { return (target != nullptr); }
void update(float deltaTime);
void update(double deltaTime);
const glm::vec3 worldToLocal(const glm::vec3& worldCoordinates) const;
const glm::vec3 worldToLocal(const glm::vec3& worldCoordinates);
glm::mat4 getViewMatrix();
glm::mat4 getProjectionMatrix();

View file

@ -39,7 +39,8 @@ public:
const float getRotation() const { return this->rotation; }
const bool isFlipped() const { return flipped; }
const glm::vec2 getFacingDir() const { return glm::vec2(cos(glm::radians(rotation)), sin(glm::radians(rotation))); }
const glm::vec3 getCenter() const { return glm::vec3(position.x + (0.5f * scale.x), position.y + (0.5f * scale.y), 0.0f); }
const glm::vec3 getCenter() const { return glm::vec3(position.x, position.y, 0.0f); }
//const glm::vec3 getCenter() const { return glm::vec3(position.x + (0.5f * scale.x), position.y + (0.5f * scale.y), 0.0f); }
const bool getIsMoving() const { return isMoving; }
const int getEntityID() const { return entityid; }
const std::shared_ptr<PhysicsComponent> getPhysicsComponent() const { return physics; }
@ -59,6 +60,7 @@ protected:
int entityid;
// Should consider move to using unique pointers for this.
std::shared_ptr<PhysicsComponent> physics;
bool isMoving = false;

View file

@ -54,7 +54,7 @@ public:
void loadCollisionMap(const std::vector<std::vector<int>>&, float tileSize);
void addObject(const std::shared_ptr<PhysicsComponent>&);
void removeObject(const std::shared_ptr<PhysicsComponent>&);
void update(float deltaTime);
void update(double deltaTime);
private:
void resolveWorldCollision(const std::shared_ptr<PhysicsComponent>&);
void resolvePossibleCollisions();

View file

@ -45,7 +45,7 @@ private:
std::string animName;
std::string animType;
std::shared_ptr<SpriteAtlas> spriteAtlas;
SpriteAtlas* spriteAtlas;
Uint32 elapsedTime = 0;
Uint32 lastFrameTick = 0;

View file

@ -55,10 +55,10 @@ private:
TextureArray* textures = nullptr;
float vertices[20] = {
// vertex
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
0.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left
};
};

View file

@ -0,0 +1,55 @@
#ifndef _H_QUAD_H
#define _H_QUAD_H
#include <glad/glad.h>
class Quad
{
public:
void draw();
~Quad();
protected:
Quad(const float* vertexData);
private:
unsigned indices[6] = {
0, 1, 2,
3, 2, 0
};
// Vertex Array, Vertex Buffer, Element Buffer
unsigned VAO, VBO, EBO;
float vertices[20];
};
class UnitQuad : public Quad
{
public:
UnitQuad() : Quad(vertices) {}
private:
// simple rectangle. Most scales will be done based on this generic vertex data.
static constexpr float vertices[20] = {
// vertex texturecoords
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left
};
};
class ScreenQuad : public Quad
{
public:
ScreenQuad() : Quad(vertices) {}
private:
// simple rectangle. Most scales will be done based on this generic vertex data.
static constexpr float vertices[20] = {
// vertex texturecoords
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
};
#endif // _H_QUAD_H

View file

@ -8,7 +8,10 @@
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "graphics/quad.h"
class ResourceManager;
class Shader;
enum class RenderLayer {
Background,
@ -64,6 +67,7 @@ class Renderer
{
public:
Renderer(const std::shared_ptr<ResourceManager>&);
void clear();
void setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view);
@ -73,7 +77,8 @@ public:
void render();
private:
std::unordered_map<RenderLayer, std::vector<std::shared_ptr<Drawable>>> layerPool;
std::unordered_map<RenderLayer, std::vector<std::shared_ptr<Drawable>>> worldLayerPool;
std::unordered_map<RenderLayer, std::vector<std::shared_ptr<Drawable>>> HUDLayerPool;
std::vector<RenderLayer> renderingOrder = {
RenderLayer::Background,
RenderLayer::Map,
@ -88,7 +93,23 @@ private:
glm::mat4 projMat;
glm::mat4 viewMat;
union FrameBuffer {
unsigned int frame;
unsigned int texture;
}worldBuffer, hudBuffer;
std::unique_ptr<ScreenQuad> screenQuad;
std::shared_ptr<ResourceManager> resourceManager;
void initFrameBuffers();
void loadPostProcessShaders();
Shader* postProcess_World;
Shader* postProcess_HUD;
void sortLayerPool(auto& layerPool);
void renderPool(auto& layerPool);
};
#endif

View file

@ -15,6 +15,7 @@
enum class TileType;
class Texture;
class EventManager;
class UnitQuad;
class Sprite
{
@ -49,19 +50,7 @@ public:
private:
void setupSprite();
// Vertex Array, Vertex Buffer, Element Buffer
unsigned VAO, VBO, EBO;
// simple rectangle. Most scales will be done based on this generic vertex data.
float vertices[20] = {
// vertex texturecoords
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
0.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
UnitQuad* quad;
};
class SpriteAtlas : public Sprite
@ -74,6 +63,7 @@ public:
SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isDirectional = false);
~SpriteAtlas();
// bind the frame VAO before drawing
void bindFrame(VertexIDs* f);
// draw current frame
void draw() override;
@ -96,8 +86,6 @@ private:
unsigned EBO;
bool isDirectional;
VertexIDs* curFrame;
VertexIDs singleFrame(int index) const {
return (index < 0 || index >= singleIDs.size()) ? singleIDs[0] : singleIDs[index];
}

View file

@ -50,7 +50,7 @@ private:
class SpriteComponent : public Component
{
public:
SpriteComponent(std::shared_ptr<Sprite> sprite) : sprite(sprite), Component(nullptr) {}
SpriteComponent(Sprite* sprite) : sprite(sprite), Component(nullptr) {}
void bind() override {
if (sprite) sprite->bind();
@ -62,12 +62,12 @@ public:
void play() override { /*unused*/ }
void idle() override { /*unused*/ }
std::shared_ptr<Sprite>& getSprite() { return sprite; }
Sprite* getSprite() { return sprite; }
~SpriteComponent() { /*sprite->~Sprite();*/ }
private:
std::shared_ptr<Sprite> sprite;
Sprite* sprite;
};
class AnimationComponent : public Component

View file

@ -7,10 +7,9 @@
#include "utility/xmlloader.h"
#include "graphics/shader.h"
#include "graphics/sprite.h"
#include <cassert>
class Sprite;
class SpriteAtlas;
class Weapon;
class Script;
class AnimationSet;
@ -32,8 +31,8 @@ public:
xmlLoader->loadScenes("scenes");
};
std::shared_ptr<SpriteAtlas> loadSpriteAtlas (const std::string& path, float frameSize, bool isDirectional = false);
std::shared_ptr<Sprite> loadSpriteStatic (const std::string& path);
SpriteAtlas* loadSpriteAtlas (const std::string& path, float frameSize, bool isDirectional = false);
Sprite* loadSpriteStatic (const std::string& path);
std::shared_ptr<AIScript> loadAIScript (const std::string& path);
std::shared_ptr<WeaponScript> loadWeaponScript (const std::string& path);
@ -52,7 +51,7 @@ public:
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::unique_ptr<Sprite>> sprites;
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<TileSetData>>tileSets;

View file

@ -1,12 +1,12 @@
#include "gameplay/camera.h"
void Camera::update(float deltaTime)
void Camera::update(double deltaTime)
{
if (target == nullptr)
return;
float smoothingFactor = 5.0f;
//if (glm::distance(target->getCenter(), getCenterPos()) > 20.f)
position += (target->getCenter() - getCenterPos()) * smoothingFactor * deltaTime;
position += (target->getCenter() - getCenterPos()) * smoothingFactor * static_cast<float>(deltaTime);
}
glm::mat4 Camera::getViewMatrix()
@ -19,7 +19,8 @@ glm::mat4 Camera::getProjectionMatrix()
return glm::ortho(0.f, viewPortW, viewPortH, 0.f);
}
const glm::vec3 Camera::worldToLocal(const glm::vec3& worldCoordinates) const
const glm::vec3 Camera::worldToLocal(const glm::vec3& worldCoordinates)
{
return worldCoordinates - position;
//return worldCoordinates - position;
return glm::vec3(getViewMatrix() * glm::vec4(worldCoordinates, 1.0f));
}

View file

@ -63,12 +63,10 @@ void Entity::draw()
void Entity::updateModelMatrix()
{
glm::mat4 origin = glm::translate(glm::mat4(1.f), -0.5f * scale);
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 + 0.5f * scale);
glm::mat4 translation = glm::translate(glm::mat4(1.f), position);
modelMatrix =
translation *
rotationMat *
origin *
glm::scale(glm::mat4(1.0f), scale);
}

View file

@ -4,6 +4,7 @@
#include "graphics/texture.h"
#include "utility/xmlloader.h"
#include "utility/resourcemanager.h"
#include "utility/logger.h"
#include <glm/gtc/matrix_transform.hpp>
@ -33,7 +34,7 @@ Map::Map(std::shared_ptr<MapData> mapData, const unsigned shaderID, std::shared_
}
}
#include <glm/ext.hpp>
void Map::loadMap()
{
tileData.resize(tileIds.size());
@ -47,7 +48,6 @@ void Map::loadMap()
glm::translate(glm::mat4(1.f), glm::vec3(x * mapData->tileSize, y * mapData->tileSize, 0.0f)) *
glm::scale(glm::mat4(1.f), glm::vec3(mapData->tileSize, mapData->tileSize, 1.0f));
int textureIndex = getTileSetIndex(tileIds[layer][y][x]);
glm::vec2 originalSize = (textureIndex != -1) ?
glm::vec2(tileSetData[textureIndex]->width, tileSetData[textureIndex]->height) :
@ -115,7 +115,7 @@ int Map::getTileSetIndex(int id) const
{
// work from the bottom, break if ID > startID
// If we get a textureIndex of -1 then we are on an empty tile
int tileSetIndex = mapData->tileSets.size() - 1;
size_t tileSetIndex = mapData->tileSets.size() - 1;
for (; tileSetIndex != -1; --tileSetIndex)
{
if (id >= mapData->tileSets[tileSetIndex].startID)

View file

@ -58,8 +58,8 @@ void PhysicsEngine::removeObject(const std::shared_ptr<PhysicsComponent>& compon
int PhysicsEngine::getTileCollider(const glm::vec3& position)
{
int x = static_cast<int>(position.x / tileSize);
int y = static_cast<int>(position.y / tileSize);
int x = static_cast<int>((position.x + 0.5f * tileSize) / tileSize);
int y = static_cast<int>((position.y + 0.5f * tileSize) / tileSize);
if (y >= 0 && y < collisionMap.size())
{
if (x >= 0 && x < collisionMap[y].size())
@ -150,34 +150,32 @@ void PhysicsEngine::resolveWorldCollision(const std::shared_ptr<PhysicsComponent
return;
}
}
int tileY = static_cast<int>((position.y) / tileSize);
int tileX = static_cast<int>((position.x) / tileSize);
if (topTile)
{
//obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y;
int tileY = static_cast<int>((position.y - radius) / tileSize);
obj->rigidBody.position.y = (tileY) * tileSize + radius + obj->collider.offset.y;
obj->rigidBody.position.y = (tileY+1) * tileSize + obj->collider.offset.y;
}
if (bottomTile)
{
//obj->rigidBody.velocity.y = -obj->rigidBody.velocity.y;
int tileY = static_cast<int>((position.y + radius) / tileSize);
obj->rigidBody.position.y = tileY * tileSize - radius - obj->collider.offset.y;
obj->rigidBody.position.y = (tileY) * tileSize - obj->collider.offset.y;
}
if (leftTile)
{
//obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x;
int tileX = static_cast<int>((position.x - radius) / tileSize);
obj->rigidBody.position.x = (tileX) * tileSize + radius + obj->collider.offset.x;
obj->rigidBody.position.x = (tileX + 1) * tileSize + obj->collider.offset.x;
}
if (rightTile)
{
//obj->rigidBody.velocity.x = -obj->rigidBody.velocity.x;
int tileX = static_cast<int>((position.x + radius) / tileSize);
obj->rigidBody.position.x = tileX * tileSize - radius - obj->collider.offset.x;
obj->rigidBody.position.x = (tileX) * tileSize - obj->collider.offset.x;
}
}
}
void PhysicsEngine::update(float deltaTime)
void PhysicsEngine::update(double deltaTime)
{
for (auto& obj : objects)
{
@ -205,7 +203,7 @@ void PhysicsEngine::update(float deltaTime)
// check map collisions
resolveWorldCollision(obj);
}
obj->rigidBody.position += obj->rigidBody.velocity * deltaTime;
obj->rigidBody.position += obj->rigidBody.velocity * static_cast<float>(deltaTime);
}
getPossibleCollisions();
if (!objCollisions.empty())

View file

@ -90,8 +90,7 @@ void Scene::loadDebugShooterScene()
entity->getPosition(),
49.0,
PhysicsComponent::Collider::Shape::Circle,
glm::vec3(mapData->tileSize / 2),
glm::abs(entity->getCenter() - entity->getPosition()))
glm::vec3(mapData->tileSize / 2))
);
if (entityData.isPlayer)
@ -159,9 +158,8 @@ void Scene::render(std::shared_ptr<Renderer> renderer)
}
}
DebugDrawer::getInstance().draw(camera->getProjectionMatrix() * camera->getViewMatrix());
renderer->render();
DebugDrawer::getInstance().draw(camera->getProjectionMatrix() * camera->getViewMatrix());
}
void Scene::unloadScene()

View file

@ -194,8 +194,8 @@ void Weapon::adjustWeapon()
0.0f
);
glm::vec3 origin = wielder->getCenter() + offset;
origin.x -= (weaponSize.x) * 0.5f;
origin.y -= (weaponSize.y) * 0.5f;
//origin.x += (weaponSize.x) * 0.25f;
//origin.y += (weaponSize.y) * 0.25f;
// Flip the texture if the weapon is facing upwards or downwards
Direction d = getDirectionFromRotation(glm::degrees(rotation));

View file

@ -0,0 +1,46 @@
#include "graphics/quad.h"
#include <memory>
Quad::Quad(const float* vertexData)
{
std::memcpy(vertices, vertexData, sizeof(vertices));
VAO = 0, VBO = 0, EBO = 0;
// Assigning vertex data
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
// Texture Coordinates
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Quad::draw()
{
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
Quad::~Quad()
{
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteVertexArrays(1, &VAO);
}

View file

@ -10,6 +10,74 @@ Renderer::Renderer(const std::shared_ptr<ResourceManager>& r)
{
projMat = glm::mat4(0.f);
viewMat = glm::mat4(0.f);
initFrameBuffers();
loadPostProcessShaders();
screenQuad = std::make_unique<ScreenQuad>();
}
// 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);
//Attaching empty texture as color buffer for framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, worldBuffer.texture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG(ERROR, "Failed to complete world framebuffer: {}", glCheckFramebufferStatus(GL_FRAMEBUFFER));
assert(1 == 0); // force crash
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// same thing is done for the hud texture
glBindFramebuffer(GL_FRAMEBUFFER, hudBuffer.frame);
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);
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::loadPostProcessShaders()
{
postProcess_World = resourceManager->getShaderByID(resourceManager->loadShader("GL_pp_world-DEFAULT", "shaders/GL_pp_world.vert", "shaders/GL_pp_world.frag"));
if (postProcess_World == nullptr) {
LOG(ERROR, "Failed to load world shader: GL_pp_world!");
assert(1 == 0); // force crash
}
postProcess_HUD = resourceManager->getShaderByID(resourceManager->loadShader("GL_pp_hud-DEFAULT", "shaders/GL_pp_hud.vert", "shaders/GL_pp_hud.frag"));
if (postProcess_HUD == nullptr) {
LOG(ERROR, "Failed to load hud shader: GL_pp_hud!");
assert(1 == 0); // force crash
}
}
void Renderer::setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view)
@ -20,24 +88,52 @@ void Renderer::setProjAndViewMatrix(const glm::mat4& proj, const glm::mat4& view
void Renderer::addDrawable(RenderLayer renderLayer, std::shared_ptr<Drawable> drawable)
{
layerPool[renderLayer].push_back(drawable);
if (renderLayer == RenderLayer::HUD || renderLayer == RenderLayer::Menu)
HUDLayerPool[renderLayer].push_back(drawable);
else
worldLayerPool[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));
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()
{
// 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();
});
}
// 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);
postProcess_World->use();
screenQuad->draw();
glBindTexture(GL_TEXTURE_2D, hudBuffer.texture);
postProcess_HUD->use();
screenQuad->draw();
}
void Renderer::renderPool(auto& layerPool)
{
sortLayerPool(layerPool);
Shader* curShader = nullptr;
for (const auto& layer : renderingOrder) {
unsigned curShaderID = static_cast<unsigned>(-1);
@ -69,7 +165,8 @@ void Renderer::render()
void Renderer::clear()
{
layerPool.clear();
worldLayerPool.clear();
HUDLayerPool.clear();
}
void Renderer::uploadUniforms(const unsigned shaderID, const std::vector<Uniform>& uniforms)
@ -100,3 +197,13 @@ void Renderer::uploadUniforms(const unsigned shaderID, const std::vector<Uniform
}, 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 std::shared_ptr<Drawable>& a, const std::shared_ptr<Drawable>& b) {
return a->getShaderID() < b->getShaderID();
});
}
}

View file

@ -1,5 +1,8 @@
#include "graphics/shader.h"
#include "utility/logger.h"
#include <cassert>
Shader::Shader(const char* vertexPath, const char* fragmentPath)
{
std::string vertexSource;
@ -27,8 +30,8 @@ Shader::Shader(const char* vertexPath, const char* fragmentPath)
}
catch(std::exception e)
{
std::cout << "failed to open shader files " << e.what() << std::endl;
return;
LOG(ERROR, "failed to open shader files '{}', '{}' error: {}", vertexPath, fragmentPath, e.what());
assert(1 == 0); // force crash
}
const char* vSource = vertexSource.c_str();
const char* fSource = fragmentSource.c_str();
@ -46,7 +49,7 @@ Shader::Shader(const char* vertexPath, const char* fragmentPath)
if (!success)
{
glGetShaderInfoLog(vertexid, 512, NULL, infoLog);
std::cout << "VERTEX SHADER COMPILE ERROR\n" << infoLog << std::endl;
LOG(ERROR, "VERTEX SHADER '{}' COMPILE ERROR\n{}", vertexPath, infoLog);
}
//compile fragment shader
@ -58,7 +61,7 @@ Shader::Shader(const char* vertexPath, const char* fragmentPath)
if (!success)
{
glGetShaderInfoLog(fragmentid, 512, NULL, infoLog);
std::cout << "FRAGMENT SHADER COMPILE ERROR\n" << infoLog << std::endl;
LOG(ERROR, "FRAGMENT SHADER '{}' COMPILE ERROR\n{}", fragmentPath, infoLog);
}
//create and link program with compiled shaders
@ -71,7 +74,7 @@ Shader::Shader(const char* vertexPath, const char* fragmentPath)
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "PROGRAM LINKER ERROR\n" << infoLog << std::endl;
LOG(ERROR, "PROGRAM LINKER ERROR\n{}", infoLog);
}
glDeleteShader(vertexid);

View file

@ -1,5 +1,6 @@
#include "graphics/sprite.h"
#include "graphics/texture.h"
#include "graphics/quad.h"
#include "util.h"
#include "utility/events.h"
@ -7,7 +8,6 @@ bool Sprite::loaded() const { return (texture != nullptr); }
SpriteStatic::SpriteStatic(const char* texturePath)
{
EBO = 0, VBO = 0, VAO = 0;
texture = new Texture();
texture->loadTexture(texturePath);
if (texture)
@ -18,28 +18,7 @@ SpriteStatic::SpriteStatic(const char* texturePath)
void SpriteStatic::setupSprite()
{
// Assigning vertex data
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
// Texture Coordinates
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
quad = new UnitQuad();
}
void Sprite::bind()
@ -50,20 +29,16 @@ void Sprite::bind()
void SpriteStatic::draw()
{
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
quad->draw();
}
SpriteStatic::~SpriteStatic()
{
delete texture;
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteVertexArrays(1, &VAO);
delete quad;
}
SpriteAtlas::SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isDirectional) : isDirectional(isDirectional), curFrame(nullptr)
SpriteAtlas::SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isDirectional) : isDirectional(isDirectional)
{
EBO = 0;
texture = new Texture();
@ -97,10 +72,10 @@ void SpriteAtlas::Setup(float frameSize)
float bottom = (row) * (frameSize / height);
float top = (row + 1) * (frameSize / height);
float vertices[] = {
0.0f, 0.0f, 0.0f, left, bottom, // bottom left
1.0f, 0.0f, 0.0f, right, bottom, // bottom right
1.0f, 1.0f, 0.0f, right, top, // top right
0.0f, 1.0f, 0.0f, left, top // top left
-0.5f, -0.5f, 0.0f, left, bottom, // bottom left
0.5f, -0.5f, 0.0f, right, bottom, // bottom right
0.5f, 0.5f, 0.0f, right, top, // top right
-0.5f, 0.5f, 0.0f, left, top // top left
};
unsigned VAO, VBO;
@ -128,12 +103,11 @@ void SpriteAtlas::Setup(float frameSize)
void SpriteAtlas::bindFrame(VertexIDs* f)
{
curFrame = f;
glBindVertexArray(f->VAO);
}
void SpriteAtlas::draw()
{
glBindVertexArray(curFrame->VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
@ -162,8 +136,8 @@ void SpriteAtlas::SetupDirectional(float frameSize)
{
int width = texture->getWidth();
int height = texture->getHeight();
int frameRows = height / frameSize;
int frameCols = width / frameSize;
int frameRows = static_cast<int>(height / frameSize);
int frameCols = static_cast<int>(width / frameSize);
glGenBuffers(1, &EBO);
@ -182,10 +156,10 @@ void SpriteAtlas::SetupDirectional(float frameSize)
float bottom = (row) * (frameSize / height);
float top = (row + 1) * (frameSize / height);
float vertices[] = {
0.0f, 0.0f, 0.0f, left, bottom, // bottom left
1.0f, 0.0f, 0.0f, right, bottom, // bottom right
1.0f, 1.0f, 0.0f, right, top, // top right
0.0f, 1.0f, 0.0f, left, top // top left
-0.5f, -0.5f, 0.0f, left, bottom, // bottom left
0.5f, -0.5f, 0.0f, right, bottom, // bottom right
0.5f, 0.5f, 0.0f, right, top, // top right
-0.5f, 0.5f, 0.0f, left, top // top left
};
unsigned VAO, VBO;

View file

@ -6,26 +6,27 @@
#include "graphics/animation.h"
#include "gameplay/weapons/weapons.h"
std::shared_ptr<SpriteAtlas> ResourceManager::loadSpriteAtlas(const std::string& path, float frameSize, bool isDirectional)
SpriteAtlas* ResourceManager::loadSpriteAtlas(const std::string& path, float frameSize, bool isDirectional)
{
auto iterator = sprites.find(path);
if (iterator != sprites.end())
return std::dynamic_pointer_cast<SpriteAtlas>(iterator->second);
auto sprite = std::make_shared<SpriteAtlas>(path.c_str(), frameSize, isDirectional);
sprites[path] = sprite;
return sprite;
return static_cast<SpriteAtlas*>(iterator->second.get());
auto sprite = std::make_unique<SpriteAtlas>(path.c_str(), frameSize, isDirectional);
sprites[path] = std::move(sprite);
SpriteAtlas& l = static_cast<SpriteAtlas&>(*sprites[path].get());
return static_cast<SpriteAtlas*>(sprites[path].get());
}
std::shared_ptr<Sprite> ResourceManager::loadSpriteStatic(const std::string& path)
Sprite* ResourceManager::loadSpriteStatic(const std::string& path)
{
auto iterator = sprites.find(path);
if (iterator != sprites.end())
return iterator->second;
auto sprite = std::make_shared<SpriteStatic>(path.c_str());
return iterator->second.get();
auto sprite = std::make_unique<SpriteStatic>(path.c_str());
if (!sprite->loaded())
return nullptr;
sprites[path] = sprite;
return sprite;
sprites[path] = std::move(sprite);
return sprites[path].get();
}
std::shared_ptr<AIScript> ResourceManager::loadAIScript(const std::string& path)