From 68c53dad0ab4c4bdf0501047b03b1ac7279abc4e Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Thu, 9 Jun 2016 15:49:03 +1000 Subject: [PATCH] Switch to sprite renderer --- Dengine.vcxproj | 4 +- Dengine.vcxproj.filters | 4 +- data/shaders/sprite.vert.glsl | 5 +- src/AssetManager.cpp | 20 +++---- src/Game.cpp | 93 +++++++++++++++++------------- src/Renderer.cpp | 87 ++++++++++++++++++++++++++++ src/Shader.cpp | 35 ++++++++--- src/Sprite.cpp | 76 ------------------------ src/dengine.cpp | 56 +++++------------- src/include/Breakout/Game.h | 9 ++- src/include/Dengine/AssetManager.h | 17 ++---- src/include/Dengine/OpenGL.h | 41 ++++++++++++- src/include/Dengine/Renderer.h | 29 ++++++++++ src/include/Dengine/Shader.h | 11 +++- src/include/Dengine/Sprite.h | 27 --------- src/include/Dengine/Texture.h | 4 +- 16 files changed, 288 insertions(+), 230 deletions(-) create mode 100644 src/Renderer.cpp delete mode 100644 src/Sprite.cpp create mode 100644 src/include/Dengine/Renderer.h delete mode 100644 src/include/Dengine/Sprite.h diff --git a/Dengine.vcxproj b/Dengine.vcxproj index 98c47dd..30572ac 100644 --- a/Dengine.vcxproj +++ b/Dengine.vcxproj @@ -123,8 +123,8 @@ + - @@ -139,8 +139,8 @@ + - diff --git a/Dengine.vcxproj.filters b/Dengine.vcxproj.filters index 813b7cf..aa74647 100644 --- a/Dengine.vcxproj.filters +++ b/Dengine.vcxproj.filters @@ -33,7 +33,7 @@ Source Files - + Source Files @@ -62,7 +62,7 @@ Header Files - + Header Files diff --git a/data/shaders/sprite.vert.glsl b/data/shaders/sprite.vert.glsl index 566851a..c6d079f 100644 --- a/data/shaders/sprite.vert.glsl +++ b/data/shaders/sprite.vert.glsl @@ -3,8 +3,11 @@ layout (location = 0) in vec4 data; // (vec2)pos, (vec2)texCoord out vec2 texCoord; +uniform mat4 model; +uniform mat4 projection; + void main() { - gl_Position = vec4(data.xy, 0.0f, 1.0f); + gl_Position = projection * model * vec4(data.xy, 0.0f, 1.0f); texCoord = data.zw; } diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 8b21673..4927dfe 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -8,15 +8,15 @@ namespace Dengine { -AssetManager::AssetManager() {} -AssetManager::~AssetManager() {} +std::map AssetManager::textures; +std::map AssetManager::shaders; -const Texture *AssetManager::getTexture(const std::string name) +Texture *AssetManager::getTexture(const std::string name) { // NOTE(doyle): Since we're using a map, the count of an object can // only be 1 or 0 - if (mTextures.count(name) == 1) - return &mTextures[name]; + if (textures.count(name) == 1) + return &textures[name]; return nullptr; } @@ -41,14 +41,14 @@ const i32 AssetManager::loadTextureImage(const std::string path, tex.generate(imgWidth, imgHeight, image); stbi_image_free(image); - mTextures[name] = tex; + textures[name] = tex; return 0; } -const Shader *AssetManager::getShader(const std::string name) +Shader *AssetManager::getShader(const std::string name) { - if (mShaders.count(name) == 1) - return &mShaders[name]; + if (shaders.count(name) == 1) + return &shaders[name]; return nullptr; } @@ -112,7 +112,7 @@ const i32 AssetManager::loadShaderFiles(const std::string vertexPath, if (result) return result; - mShaders[name] = shader; + shaders[name] = shader; return 0; } } diff --git a/src/Game.cpp b/src/Game.cpp index 2b15542..43000e9 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,63 +1,74 @@ #include +#include +#include +#include namespace Breakout { -Game::Game(i32 width, i32 height) {} -Game::~Game() {} +Game::Game(i32 width, i32 height) +{ + this->width = width; + this->height = height; + glCheckError(); +} -void Game::init(Dengine::AssetManager *assetManager) +Game::~Game() +{ + delete this->renderer; +} + +void Game::init() { /* Initialise assets */ - i32 result = 0; - result = assetManager->loadShaderFiles("data/shaders/sprite.vert.glsl", - "data/shaders/sprite.frag.glsl", - "sprite"); - if (result) - { - // TODO(doyle): Do something - } + Dengine::AssetManager::loadShaderFiles("data/shaders/sprite.vert.glsl", + "data/shaders/sprite.frag.glsl", + "sprite"); - result = assetManager->loadTextureImage("data/textures/container.jpg", - "container"); - if (result) - { - - } + Dengine::AssetManager::loadTextureImage("data/textures/container.jpg", + "container"); + Dengine::AssetManager::loadTextureImage("data/textures/wall.jpg", "wall"); + Dengine::AssetManager::loadTextureImage("data/textures/awesomeface.png", + "awesomeface"); + Dengine::AssetManager::loadTextureImage("data/textures/plain_terrain.jpg", + "plain_terrain"); + glCheckError(); - result = assetManager->loadTextureImage("data/textures/wall.jpg", - "wall"); - if (result) - { - - } + glm::mat4 projection= glm::ortho(0.0f, 1280.0f, + 720.0f, 0.0f, -1.0f, 1.0f); + glCheckError(); - result = assetManager->loadTextureImage("data/textures/awesomeface.png", - "awesomeface"); - if (result) - { - - } + this->shader = Dengine::AssetManager::getShader("sprite"); + this->shader->use(); + glCheckError(); + //shader->uniformSetMat4fv("projection", projection); + glCheckError(); - result = assetManager->loadTextureImage("data/textures/plain_terrain.png", - "plain_terrain"); - - this->shader = assetManager->getShader("sprite"); - - /* Init player */ - const Dengine::Texture *tex = assetManager->getTexture("plain_terrain"); - this->player = Dengine::Sprite(); - this->player.loadSprite(tex, glm::vec2(0, 0)); + GLuint projectionLoc = glGetUniformLocation(this->shader->id, "projection"); + glCheckError(); + glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); + glCheckError(); /* Init game state */ this->state = GAME_ACTIVE; - + glCheckError(); + this->renderer = new Dengine::Renderer(this->shader); + glCheckError(); } void Game::processInput(const f32 dt) {} void Game::update(const f32 dt) {} void Game::render() { - shader->use(); - this->player.render(shader); + const Dengine::Texture *tex = + Dengine::AssetManager::getTexture("plain_terrain"); + glm::vec2 pos = glm::vec2(200, 200); + glm::vec2 size = glm::vec2(640, 360); + GLfloat rotation = 0; + glm::vec3 color = glm::vec3(1.0f); + this->renderer->drawSprite(tex, pos, size, rotation, color); + + this->renderer->drawSprite(Dengine::AssetManager::getTexture("awesomeface"), + glm::vec2(200, 200), glm::vec2(300, 400), 45.0f, + glm::vec3(0.0f, 1.0f, 0.0f)); } } diff --git a/src/Renderer.cpp b/src/Renderer.cpp new file mode 100644 index 0000000..776ea1f --- /dev/null +++ b/src/Renderer.cpp @@ -0,0 +1,87 @@ +#include +#include + +#include + +namespace Dengine +{ +Renderer::Renderer(Shader *shader) +{ + this->shader = shader; + this->initRenderData(); +} + +Renderer::~Renderer() +{ + glDeleteVertexArrays(1, &this->quadVAO); +} +void Renderer::drawSprite(const Texture *texture, glm::vec2 position, + glm::vec2 size, GLfloat rotate, glm::vec3 color) +{ + this->shader->use(); + glm::mat4 model; + // First translate (transformations are: scale happens first, then rotation + // and then finall translation happens; reversed order) + model = glm::translate(model, glm::vec3(position, 0.0f)); + + // Move origin of rotation to center of quad + model = glm::translate(model, glm::vec3(0.5f * size.x, 0.5f * size.y, 0.0f)); + + // Then rotate + model = glm::rotate(model, rotate, glm::vec3(0.0f, 0.0f, 1.0f)); + + // Move origin back + model = glm::translate(model, glm::vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); + + model = glm::scale(model, glm::vec3(size, 1.0f)); // Last scale + + this->shader->uniformSetMat4fv("model", model); + + // TODO(doyle): Unimplemented + // this->shader->uniformSetVec3f("spriteColor", color); + + glActiveTexture(GL_TEXTURE0); + texture->bind(); + this->shader->uniformSet1i("tex", 0); + + glBindVertexArray(this->quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); +} + +void Renderer::initRenderData() +{ + glm::vec4 vertices[] = { + // x y s t + {+1.0f, +1.0f, 1.0f, 1.0f}, // Top right + {+1.0f, -1.0f, 1.0f, 0.0f}, // Bottom right + {-1.0f, +1.0f, 0.0f, 1.0f}, // Top left + {-1.0f, -1.0f, 0.0f, 0.0f}, // Bottom left + }; + + GLuint VBO; + + /* Create buffers */ + glGenVertexArrays(1, &this->quadVAO); + glGenBuffers(1, &VBO); + + /* Bind buffers */ + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBindVertexArray(this->quadVAO); + + /* Configure VBO */ + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + /* Configure VAO */ + const GLuint numVertexElements = 4; + const GLuint vertexSize = sizeof(glm::vec4); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, numVertexElements, GL_FLOAT, GL_FALSE, vertexSize, + (GLvoid *)0); + + /* Unbind */ + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} +} diff --git a/src/Shader.cpp b/src/Shader.cpp index 7591442..9a3b6c1 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -1,33 +1,36 @@ #include +#include + #include #include namespace Dengine { Shader::Shader() -: program(0) +: id(0) { } Shader::~Shader() {} -i32 Shader::loadProgram(GLuint vertexShader, GLuint fragmentShader) +const i32 Shader::loadProgram(const GLuint vertexShader, + const GLuint fragmentShader) { - this->program = glCreateProgram(); - glAttachShader(this->program, vertexShader); - glAttachShader(this->program, fragmentShader); - glLinkProgram(this->program); + this->id = glCreateProgram(); + glAttachShader(this->id, vertexShader); + glAttachShader(this->id, fragmentShader); + glLinkProgram(this->id); glDeleteShader(fragmentShader); glDeleteShader(vertexShader); GLint success; GLchar infoLog[512]; - glGetProgramiv(this->program, GL_LINK_STATUS, &success); + glGetProgramiv(this->id, GL_LINK_STATUS, &success); if (!success) { - glGetProgramInfoLog(this->program, 512, NULL, infoLog); + glGetProgramInfoLog(this->id, 512, NULL, infoLog); std::cout << "glLinkProgram failed: " << infoLog << std::endl; return -1; } @@ -36,5 +39,19 @@ i32 Shader::loadProgram(GLuint vertexShader, GLuint fragmentShader) } -void Shader::use() const { glUseProgram(this->program); } +void Shader::uniformSet1i(const GLchar *name, const GLuint data) +{ + GLint uniformLoc = glGetUniformLocation(this->id, name); + glUniform1i(uniformLoc, data); +} + +void Shader::uniformSetMat4fv(const GLchar *name, const glm::mat4 data) +{ + GLint uniformLoc = glGetUniformLocation(this->id, name); + glCheckError(); + glUniformMatrix4fv(uniformLoc, 1, GL_FALSE, glm::value_ptr(data)); + glCheckError(); +} + +void Shader::use() const { glUseProgram(this->id); } } diff --git a/src/Sprite.cpp b/src/Sprite.cpp deleted file mode 100644 index 2533343..0000000 --- a/src/Sprite.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include - -namespace Dengine -{ - -Sprite::Sprite() -: pos(0, 0), -tex(nullptr) -{ -} - -Sprite::~Sprite() {} - -const b32 Sprite::loadSprite(const Texture *tex, const glm::vec2 pos) -{ - if (!tex) return -1; - - this->tex = tex; - this->pos = pos; - - // NOTE(doyle): We encode in a vec4 (vec2)pos, (vec2)texCoords - glm::vec4 spriteVertex[] = { - // x y s t - {+0.5f, +0.5f, 1.0f, 1.0f}, // Top right - {+0.5f, -0.5f, 1.0f, 0.0f}, // Bottom right - {-0.5f, +0.5f, 0.0f, 1.0f}, // Top left - {-0.5f, -0.5f, 0.0f, 0.0f}, // Bottom left - }; - - /* Create buffers */ - glGenBuffers(1, &this->vbo); - glGenVertexArrays(1, &this->vao); - - /* Bind buffers */ - glBindVertexArray(this->vao); - glBindBuffer(GL_ARRAY_BUFFER, this->vbo); - - /* Configure VBO */ - glBufferData(GL_ARRAY_BUFFER, sizeof(spriteVertex), spriteVertex, - GL_STATIC_DRAW); - - /* Configure VAO */ - i32 numElementsInVertex = 4; - i32 vertexSize = sizeof(glm::vec4); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, numElementsInVertex, GL_FLOAT, GL_FALSE, - vertexSize, (GLvoid *)(0)); - - /* Unbind */ - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - return 0; -} - -void Sprite::render(const Shader *shader) const -{ - // NOTE(doyle): Associate the VAO with this sprites VBO - glBindVertexArray(this->vao); - - /* Set texture */ - glActiveTexture(GL_TEXTURE0); - this->tex->bind(); - glUniform1i(glGetUniformLocation(shader->program, "tex"), 0); - - /* Render */ - i32 numVerticesToDraw = 4; - glDrawArrays(GL_TRIANGLE_STRIP, 0, numVerticesToDraw); - - // Unbind - glBindVertexArray(0); -} - -} diff --git a/src/dengine.cpp b/src/dengine.cpp index e092fde..417ac74 100644 --- a/src/dengine.cpp +++ b/src/dengine.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include @@ -44,42 +44,6 @@ void scroll_callback(GLFWwindow *window, double xOffset, double yOffset) { } -GLenum glCheckError_(const char *file, int line) -{ - GLenum errorCode; - while ((errorCode = glGetError()) != GL_NO_ERROR) - { - std::string error; - switch (errorCode) - { - case GL_INVALID_ENUM: - error = "INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - error = "INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - error = "INVALID_OPERATION"; - break; - case GL_STACK_OVERFLOW: - error = "STACK_OVERFLOW"; - break; - case GL_STACK_UNDERFLOW: - error = "STACK_UNDERFLOW"; - break; - case GL_OUT_OF_MEMORY: - error = "OUT_OF_MEMORY"; - break; - case GL_INVALID_FRAMEBUFFER_OPERATION: - error = "INVALID_FRAMEBUFFER_OPERATION"; - break; - } - std::cout << error << " | " << file << " (" << line << ")" << std::endl; - } - return errorCode; -} -#define glCheckError() glCheckError_(__FILE__, __LINE__) - int main() { glfwInit(); @@ -88,7 +52,7 @@ int main() glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - glm::ivec2 windowSize = glm::ivec2(800, 600); + glm::ivec2 windowSize = glm::ivec2(1280, 720); GLFWwindow *window = glfwCreateWindow(windowSize.x, windowSize.y, "Breakout", nullptr, nullptr); @@ -115,6 +79,8 @@ int main() // regardless of success. Catch it once by calling glGetError glGetError(); + glCheckError(); + glm::ivec2 frameBufferSize; glfwGetFramebufferSize(window, &frameBufferSize.x, &frameBufferSize.y); glViewport(0, 0, frameBufferSize.x, frameBufferSize.y); @@ -124,16 +90,23 @@ int main() glfwSetScrollCallback(window, scroll_callback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - glEnable(GL_CULL_FACE | GL_BLEND); + glEnable(GL_BLEND); + glCheckError(); + glEnable(GL_CULL_FACE); + glCheckError(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glCheckError(); glCullFace(GL_BACK); + glCheckError(); - Dengine::AssetManager assetManager; Breakout::Game game = Breakout::Game(frameBufferSize.x, frameBufferSize.y); - game.init(&assetManager); + glCheckError(); + game.init(); + glCheckError(); glfwSetWindowUserPointer(window, static_cast(&game)); + glCheckError(); f32 deltaTime = 0.0f; // Time between current frame and last frame f32 lastFrame = 0.0f; // Time of last frame @@ -156,6 +129,7 @@ int main() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); game.render(); + glCheckError(); /* Swap the buffers */ glfwSwapBuffers(window); diff --git a/src/include/Breakout/Game.h b/src/include/Breakout/Game.h index a3d352c..45a6d1d 100644 --- a/src/include/Breakout/Game.h +++ b/src/include/Breakout/Game.h @@ -3,13 +3,12 @@ #include #include -#include +#include #include #include namespace Breakout { - GLOBAL_VAR const i32 NUM_KEYS = 1024; enum GameState @@ -29,14 +28,14 @@ public: Game(i32 width, i32 height); ~Game(); - void init(Dengine::AssetManager *const assetManager); + void init(); void processInput(const f32 dt); void update(const f32 dt); void render(); private: - const Dengine::Shader *shader; - Dengine::Sprite player; + Dengine::Shader *shader; + Dengine::Renderer *renderer; }; } diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index d14ac31..4fc0a2e 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -14,23 +14,18 @@ namespace Dengine class AssetManager { public: - AssetManager(); - // TODO(doyle): Unload all resources in memory - ~AssetManager(); + static std::map textures; + static std::map shaders; /* Texture */ - const Texture *getTexture(const std::string name); - const i32 loadTextureImage(const std::string path, const std::string name); + static Texture *getTexture(const std::string name); + static const i32 loadTextureImage(const std::string path, const std::string name); /* Shaders */ - const Shader *getShader(const std::string name); - const i32 loadShaderFiles(const std::string vertexPath, + static Shader *getShader(const std::string name); + static const i32 loadShaderFiles(const std::string vertexPath, const std::string fragmentPath, const std::string name); - -private: - std::map mTextures; - std::map mShaders; }; } #endif diff --git a/src/include/Dengine/OpenGL.h b/src/include/Dengine/OpenGL.h index 5ae3824..c71aa35 100644 --- a/src/include/Dengine/OpenGL.h +++ b/src/include/Dengine/OpenGL.h @@ -5,4 +5,43 @@ #include #include -#endif \ No newline at end of file +#include +#include + +inline GLenum glCheckError_(const char *file, int line) +{ + GLenum errorCode; + while ((errorCode = glGetError()) != GL_NO_ERROR) + { + std::string error; + switch (errorCode) + { + case GL_INVALID_ENUM: + error = "INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + error = "INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + error = "INVALID_OPERATION"; + break; + case GL_STACK_OVERFLOW: + error = "STACK_OVERFLOW"; + break; + case GL_STACK_UNDERFLOW: + error = "STACK_UNDERFLOW"; + break; + case GL_OUT_OF_MEMORY: + error = "OUT_OF_MEMORY"; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + error = "INVALID_FRAMEBUFFER_OPERATION"; + break; + } + std::cout << error << " | " << file << " (" << line << ")" << std::endl; + } + return errorCode; +} +#define glCheckError() glCheckError_(__FILE__, __LINE__) + +#endif diff --git a/src/include/Dengine/Renderer.h b/src/include/Dengine/Renderer.h new file mode 100644 index 0000000..6d68523 --- /dev/null +++ b/src/include/Dengine/Renderer.h @@ -0,0 +1,29 @@ +#ifndef DENGINE_RENDERER_H +#define DENGINE_RENDERER_H + +#include +#include +#include +#include + +namespace Dengine +{ +class Renderer +{ +public: + Renderer(Shader *shader); + ~Renderer(); + + void drawSprite(const Texture *texture, glm::vec2 position, + glm::vec2 size = glm::vec2(10, 10), GLfloat rotate = 0.0f, + glm::vec3 color = glm::vec3(1.0f)); + +private: + Shader *shader; + GLuint quadVAO; + + void initRenderData(); +}; +} + +#endif diff --git a/src/include/Dengine/Shader.h b/src/include/Dengine/Shader.h index b8d4eb2..5fa1e0b 100644 --- a/src/include/Dengine/Shader.h +++ b/src/include/Dengine/Shader.h @@ -3,6 +3,9 @@ #include #include + +#include + #include namespace Dengine @@ -10,12 +13,16 @@ namespace Dengine class Shader { public: - GLuint program; + GLuint id; Shader(); ~Shader(); - i32 loadProgram(GLuint vertexShader, GLuint fragmentShader); + const i32 loadProgram(const GLuint vertexShader, + const GLuint fragmentShader); + + void uniformSet1i(const GLchar *name, const GLuint data); + void uniformSetMat4fv(const GLchar *name, const glm::mat4 data); void use() const; }; diff --git a/src/include/Dengine/Sprite.h b/src/include/Dengine/Sprite.h deleted file mode 100644 index d06a5fc..0000000 --- a/src/include/Dengine/Sprite.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef DENGINE_SPRITE_H -#define DENGINE_SPRITE_H - -#include -#include -#include -#include - -namespace Dengine { -class Sprite -{ -public: - Sprite(); - ~Sprite(); - - const b32 loadSprite(const Texture *tex, const glm::vec2 pos); - - void render(const Shader *shader) const; -private: - glm::vec2 pos; - const Texture *tex; - GLuint vbo; - GLuint vao; -}; -} - -#endif diff --git a/src/include/Dengine/Texture.h b/src/include/Dengine/Texture.h index 0867174..da7ee47 100644 --- a/src/include/Dengine/Texture.h +++ b/src/include/Dengine/Texture.h @@ -1,8 +1,8 @@ #ifndef DENGINE_TEXTURE_H #define DENGINE_TEXTURE_H -#include -#include +#include +#include namespace Dengine {