Switch to sprite renderer

This commit is contained in:
Doyle Thai 2016-06-09 15:49:03 +10:00
parent 60fcecab0e
commit 68c53dad0a
16 changed files with 288 additions and 230 deletions

View File

@ -123,8 +123,8 @@
<ClCompile Include="src\AssetManager.cpp" />
<ClCompile Include="src\dengine.cpp" />
<ClCompile Include="src\Game.cpp" />
<ClCompile Include="src\Renderer.cpp" />
<ClCompile Include="src\Shader.cpp" />
<ClCompile Include="src\Sprite.cpp" />
<ClCompile Include="src\Texture.cpp" />
<ClCompile Include="src\Tutorial.cpp" />
</ItemGroup>
@ -139,8 +139,8 @@
<ClInclude Include="src\include\Dengine\Common.h" />
<ClInclude Include="src\include\Breakout\Game.h" />
<ClInclude Include="src\include\Dengine\OpenGL.h" />
<ClInclude Include="src\include\Dengine\Renderer.h" />
<ClInclude Include="src\include\Dengine\Shader.h" />
<ClInclude Include="src\include\Dengine\Sprite.h" />
<ClInclude Include="src\include\Dengine\Texture.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -33,7 +33,7 @@
<ClCompile Include="src\Tutorial.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Sprite.cpp">
<ClCompile Include="src\Renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
@ -62,7 +62,7 @@
<ClInclude Include="src\include\Breakout\Game.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\Dengine\Sprite.h">
<ClInclude Include="src\include\Dengine\Renderer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>

View File

@ -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;
}

View File

@ -8,15 +8,15 @@
namespace Dengine
{
AssetManager::AssetManager() {}
AssetManager::~AssetManager() {}
std::map<std::string, Texture> AssetManager::textures;
std::map<std::string, Shader> 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;
}
}

View File

@ -1,63 +1,74 @@
#include <Breakout\Game.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
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",
Dengine::AssetManager::loadShaderFiles("data/shaders/sprite.vert.glsl",
"data/shaders/sprite.frag.glsl",
"sprite");
if (result)
{
// TODO(doyle): Do something
}
result = assetManager->loadTextureImage("data/textures/container.jpg",
Dengine::AssetManager::loadTextureImage("data/textures/container.jpg",
"container");
if (result)
{
}
result = assetManager->loadTextureImage("data/textures/wall.jpg",
"wall");
if (result)
{
}
result = assetManager->loadTextureImage("data/textures/awesomeface.png",
Dengine::AssetManager::loadTextureImage("data/textures/wall.jpg", "wall");
Dengine::AssetManager::loadTextureImage("data/textures/awesomeface.png",
"awesomeface");
if (result)
{
}
result = assetManager->loadTextureImage("data/textures/plain_terrain.png",
Dengine::AssetManager::loadTextureImage("data/textures/plain_terrain.jpg",
"plain_terrain");
glCheckError();
this->shader = assetManager->getShader("sprite");
glm::mat4 projection= glm::ortho(0.0f, 1280.0f,
720.0f, 0.0f, -1.0f, 1.0f);
glCheckError();
/* Init player */
const Dengine::Texture *tex = assetManager->getTexture("plain_terrain");
this->player = Dengine::Sprite();
this->player.loadSprite(tex, glm::vec2(0, 0));
this->shader = Dengine::AssetManager::getShader("sprite");
this->shader->use();
glCheckError();
//shader->uniformSetMat4fv("projection", projection);
glCheckError();
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));
}
}

87
src/Renderer.cpp Normal file
View File

@ -0,0 +1,87 @@
#include <Dengine/Renderer.h>
#include <Dengine/OpenGL.h>
#include <glm/gtc/matrix_transform.hpp>
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);
}
}

View File

@ -1,33 +1,36 @@
#include <Dengine\Shader.h>
#include <glm/gtc/type_ptr.hpp>
#include <fstream>
#include <iostream>
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); }
}

View File

@ -1,76 +0,0 @@
#include <Dengine\Sprite.h>
#include <Dengine\OpenGL.h>
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);
}
}

View File

@ -3,7 +3,7 @@
#include <Dengine/Common.h>
#include <Dengine/Shader.h>
#include <Dengine/AssetManager.h>
#include <Dengine/Sprite.h>
#include <Dengine/Renderer.h>
#include <Breakout/Game.h>
@ -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<void *>(&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);

View File

@ -3,13 +3,12 @@
#include <Dengine/OpenGL.h>
#include <Dengine/Common.h>
#include <Dengine/Sprite.h>
#include <Dengine/Renderer.h>
#include <Dengine/Shader.h>
#include <Dengine/AssetManager.h>
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;
};
}

View File

@ -14,23 +14,18 @@ namespace Dengine
class AssetManager
{
public:
AssetManager();
// TODO(doyle): Unload all resources in memory
~AssetManager();
static std::map<std::string, Texture> textures;
static std::map<std::string, Shader> 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<std::string, Texture> mTextures;
std::map<std::string, Shader> mShaders;
};
}
#endif

View File

@ -5,4 +5,43 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string>
#include <iostream>
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

View File

@ -0,0 +1,29 @@
#ifndef DENGINE_RENDERER_H
#define DENGINE_RENDERER_H
#include <Dengine/Common.h>
#include <Dengine/Texture.h>
#include <Dengine/Shader.h>
#include <GLM/glm.hpp>
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

View File

@ -3,6 +3,9 @@
#include <Dengine/Common.h>
#include <Dengine/OpenGL.h>
#include <glm/glm.hpp>
#include <string>
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;
};

View File

@ -1,27 +0,0 @@
#ifndef DENGINE_SPRITE_H
#define DENGINE_SPRITE_H
#include <Dengine\Common.h>
#include <Dengine\Texture.h>
#include <Dengine\Shader.h>
#include <GLM\glm.hpp>
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

View File

@ -1,8 +1,8 @@
#ifndef DENGINE_TEXTURE_H
#define DENGINE_TEXTURE_H
#include <Dengine\OpenGL.h>
#include <Dengine\Common.h>
#include <Dengine/OpenGL.h>
#include <Dengine/Common.h>
namespace Dengine
{