Abstract asset loading to asset manager

This commit is contained in:
Doyle Thai 2016-06-04 22:42:22 +10:00
parent d08cc4621b
commit 7295d4712c
10 changed files with 331 additions and 102 deletions

View File

@ -120,17 +120,21 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\AssetManager.cpp" />
<ClCompile Include="src\dengine.cpp" /> <ClCompile Include="src\dengine.cpp" />
<ClCompile Include="src\Shader.cpp" /> <ClCompile Include="src\Shader.cpp" />
<ClCompile Include="src\Texture.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="data\shaders\default.frag.glsl" /> <None Include="data\shaders\default.frag.glsl" />
<None Include="data\shaders\default.vert.glsl" /> <None Include="data\shaders\default.vert.glsl" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\include\Dengine\AssetManager.h" />
<ClInclude Include="src\include\Dengine\Common.h" /> <ClInclude Include="src\include\Dengine\Common.h" />
<ClInclude Include="src\include\Dengine\OpenGL.h" /> <ClInclude Include="src\include\Dengine\OpenGL.h" />
<ClInclude Include="src\include\Dengine\Shader.h" /> <ClInclude Include="src\include\Dengine\Shader.h" />
<ClInclude Include="src\include\Dengine\Texture.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -21,6 +21,12 @@
<ClCompile Include="src\Shader.cpp"> <ClCompile Include="src\Shader.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Texture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\AssetManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="data\shaders\default.vert.glsl" /> <None Include="data\shaders\default.vert.glsl" />
@ -36,5 +42,11 @@
<ClInclude Include="src\include\Dengine\OpenGL.h"> <ClInclude Include="src\include\Dengine\OpenGL.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\include\Dengine\Texture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\Dengine\AssetManager.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

118
src/AssetManager.cpp Normal file
View File

@ -0,0 +1,118 @@
#include <Dengine\AssetManager.h>
#define STBI_FAILURE_USERMSG
#define STB_IMAGE_IMPLEMENTATION
#include <STB/stb_image.h>
#include <fstream>
namespace Dengine
{
AssetManager::AssetManager(){}
AssetManager::~AssetManager(){}
Texture *AssetManager::getTexture(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];
return nullptr;
}
i32 AssetManager::loadTextureImage(std::string path, std::string name)
{
/* Open the texture image */
i32 imgWidth, imgHeight, bytesPerPixel;
stbi_set_flip_vertically_on_load(TRUE);
u8 *image =
stbi_load(path.c_str(), &imgWidth, &imgHeight, &bytesPerPixel, 0);
if (!image)
{
std::cerr << "stdbi_load() failed: " << stbi_failure_reason()
<< std::endl;
return -1;
}
Texture tex;
tex.generate(imgWidth, imgHeight, image);
stbi_image_free(image);
mTextures[name] = tex;
return 0;
}
Shader *AssetManager::getShader(std::string name)
{
if (mShaders.count(name) == 1)
return &mShaders[name];
return nullptr;
}
INTERNAL std::string stringFromFile(const std::string &filename)
{
std::ifstream file;
file.open(filename.c_str(), std::ios::in | std::ios::binary);
std::string output;
std::string line;
if (!file.is_open())
{
std::runtime_error(std::string("Failed to open file: ") + filename);
}
else
{
while (file.good())
{
std::getline(file, line);
output.append(line + "\n");
}
}
file.close();
return output;
}
INTERNAL GLuint createShaderFromPath(std::string path, GLuint shadertype)
{
std::string shaderSource = stringFromFile(path);
const GLchar *source = shaderSource.c_str();
GLuint result = glCreateShader(shadertype);
glShaderSource(result, 1, &source, NULL);
glCompileShader(result);
GLint success;
GLchar infoLog[512];
glGetShaderiv(result, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(result, 512, NULL, infoLog);
std::cout << "glCompileShader failed: " << infoLog << std::endl;
}
return result;
}
i32 AssetManager::loadShaderFiles(std::string vertexPath,
std::string fragmentPath, std::string name)
{
GLuint vertexShader =
createShaderFromPath(vertexPath, GL_VERTEX_SHADER);
GLuint fragmentShader =
createShaderFromPath(fragmentPath, GL_FRAGMENT_SHADER);
Shader shader;
i32 result = shader.loadProgram(vertexShader, fragmentShader);
if (result)
return result;
mShaders[name] = shader;
return 0;
}
}

View File

@ -5,63 +5,23 @@
namespace Dengine namespace Dengine
{ {
INTERNAL std::string stringFromFile(const std::string &filename) Shader::Shader()
: mProgram(0)
{ {
std::ifstream file;
file.open(filename.c_str(), std::ios::in | std::ios::binary);
std::string output;
std::string line;
if (!file.is_open())
{
std::runtime_error(std::string("Failed to open file: ") + filename);
}
else
{
while (file.good())
{
std::getline(file, line);
output.append(line + "\n");
}
}
file.close();
return output;
} }
INTERNAL GLuint createShaderFromPath(std::string path, GLuint shadertype) Shader::~Shader() {}
i32 Shader::loadProgram(GLuint vertexShader, GLuint fragmentShader)
{ {
std::string shaderSource = stringFromFile(path);
const GLchar *source = shaderSource.c_str();
GLuint result = glCreateShader(shadertype);
glShaderSource(result, 1, &source, NULL);
glCompileShader(result);
GLint success;
GLchar infoLog[512];
glGetShaderiv(result, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(result, 512, NULL, infoLog);
std::cout << "glCompileShader failed: " << infoLog << std::endl;
}
return result;
}
Shader::Shader(std::string vertexPath, std::string fragmentPath)
{
GLuint vertexShader = createShaderFromPath(vertexPath, GL_VERTEX_SHADER);
GLuint fragmentShader =
createShaderFromPath(fragmentPath, GL_FRAGMENT_SHADER);
mProgram = glCreateProgram(); mProgram = glCreateProgram();
glAttachShader(mProgram, vertexShader); glAttachShader(mProgram, vertexShader);
glAttachShader(mProgram, fragmentShader); glAttachShader(mProgram, fragmentShader);
glLinkProgram(mProgram); glLinkProgram(mProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
GLint success; GLint success;
GLchar infoLog[512]; GLchar infoLog[512];
glGetProgramiv(mProgram, GL_LINK_STATUS, &success); glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
@ -69,13 +29,12 @@ Shader::Shader(std::string vertexPath, std::string fragmentPath)
{ {
glGetProgramInfoLog(mProgram, 512, NULL, infoLog); glGetProgramInfoLog(mProgram, 512, NULL, infoLog);
std::cout << "glLinkProgram failed: " << infoLog << std::endl; std::cout << "glLinkProgram failed: " << infoLog << std::endl;
return -1;
} }
glDeleteShader(fragmentShader); return 0;
glDeleteShader(vertexShader);
}
Shader::~Shader() {} }
void Shader::use() { glUseProgram(mProgram); } void Shader::use() { glUseProgram(mProgram); }
} }

42
src/Texture.cpp Normal file
View File

@ -0,0 +1,42 @@
#include <Dengine\Texture.h>
namespace Dengine
{
Texture::Texture()
: mId(0)
, mWidth(0)
, mHeight(0)
, mInternalFormat(GL_RGB)
, mImageFormat(GL_RGB)
, mWrapS(GL_REPEAT)
, mWrapT(GL_REPEAT)
, mFilterMinification(GL_LINEAR)
, mFilterMagnification(GL_LINEAR)
{
glGenTextures(1, &mId);
}
void Texture::generate(GLuint width, GLuint height, u8 *image)
{
mWidth = width;
mHeight = height;
glBindTexture(GL_TEXTURE_2D, mId);
/* Load image into texture */
glTexImage2D(GL_TEXTURE_2D, 0, mInternalFormat, mWidth, mHeight, 0,
mImageFormat, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
/* Set parameter of currently bound texture */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mWrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mWrapT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mFilterMinification);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mFilterMagnification);
/* Unbind and clean up */
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::bind() const { glBindTexture(GL_TEXTURE_2D, mId); }
}

View File

@ -18,8 +18,9 @@ set includeFlags=/I ..\src\include /I %GLEW%\include /I %GLFW%\include /I %STB%\
REM Link libraries REM Link libraries
set linkLibraries=/link opengl32.lib %GLFW%\lib-vc2015\glfw3.lib %GLEW%\lib\Release\Win32\glew32s.lib gdi32.lib user32.lib shell32.lib set linkLibraries=/link opengl32.lib %GLFW%\lib-vc2015\glfw3.lib %GLEW%\lib\Release\Win32\glew32s.lib gdi32.lib user32.lib shell32.lib
set ignoreLibraries=/NODEFAULTLIB:"libc.lib" /NODEFAULTLIB:"libcmt.lib" /NODEFAULTLIB:"libcd.lib" /NODEFAULTLIB:"libcmtd.lib" /NODEFAULTLIB:"msvcrtd.lib"
cl %compileFlags% ..\src\*.cpp %includeFlags% %linkLibraries% cl %compileFlags% ..\src\*.cpp %includeFlags% %linkLibraries% %ignoreLibraries% /OUT:"Dengine.exe"
REM /SUBSYSTEM:CONSOLE REM /SUBSYSTEM:CONSOLE
popd popd

View File

@ -1,10 +1,8 @@
#include <Dengine/OpenGL.h> #include <Dengine/OpenGL.h>
#include <Dengine/Common.h> #include <Dengine/Common.h>
#include <Dengine/Shader.h> #include <Dengine/Shader.h>
#include <Dengine/AssetManager.h>
#define STBI_FAILURE_USERMSG
#define STB_IMAGE_IMPLEMENTATION
#include <STB/stb_image.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
@ -130,6 +128,42 @@ void scroll_callback(GLFWwindow *window, double xOffset, double yOffset)
fov = 45.0f; fov = 45.0f;
} }
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() int main()
{ {
glfwInit(); glfwInit();
@ -173,41 +207,22 @@ int main()
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
/* Initialise shaders */ /* Initialise shaders */
Dengine::Shader shader = Dengine::Shader("data/shaders/default.vert.glsl", Dengine::AssetManager assetManager;
"data/shaders/default.frag.glsl"); i32 result = 0;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// Set texture wrapping parameters result = assetManager.loadShaderFiles("data/shaders/default.vert.glsl",
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); "data/shaders/default.frag.glsl",
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); "default");
if (result) return result;
// Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* Load a texture */ /* Load a texture */
i32 imgWidth, imgHeight, bytesPerPixel; result = assetManager.loadTextureImage("data/textures/container.jpg",
stbi_set_flip_vertically_on_load(TRUE); "container");
u8 *image = stbi_load("data/textures/container.jpg", &imgWidth, &imgHeight, if (result) return result;
&bytesPerPixel, 0);
if (!image) Dengine::Texture *containerTex = assetManager.getTexture("container");
{ Dengine::Shader *shader = assetManager.getShader("default");
std::cerr << "stdbi_load() failed: " << stbi_failure_reason() //if (!containerTex) return -1;
<< std::endl;
}
glTexImage2D(GL_TEXTURE_2D, 0,
getGLFormat((BytesPerPixel)bytesPerPixel, FALSE), imgWidth,
imgHeight, 0, getGLFormat((BytesPerPixel)bytesPerPixel, FALSE),
GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
// Unbind texture
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
/* Create OGL Vertex objects */ /* Create OGL Vertex objects */
GLfloat vertices[] = { GLfloat vertices[] = {
@ -275,11 +290,11 @@ int main()
-0.5f, -0.5f, +0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom left -0.5f, -0.5f, +0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom left
-0.5f, +0.5f, +0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top left -0.5f, +0.5f, +0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top left
}; };
#endif
GLuint indices[] = { GLuint indices[] = {
0, 1, 3, // First triangle 0, 1, 3, // First triangle
1, 2, 3, // First triangle 1, 2, 3, // First triangle
}; };
#endif
GLuint vbo, vao; GLuint vbo, vao;
@ -355,10 +370,10 @@ int main()
/* Bind textures */ /* Bind textures */
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, containerTex->mId);
glUniform1i(glGetUniformLocation(shader.mProgram, "ourTexture"), 0); glUniform1i(glGetUniformLocation(shader->mProgram, "ourTexture"), 0);
shader.use(); shader->use();
/* Camera/View transformation */ /* Camera/View transformation */
glm::mat4 view; glm::mat4 view;
@ -372,9 +387,9 @@ int main()
0.1f, 100.0f); 0.1f, 100.0f);
/* Get shader uniform locations */ /* Get shader uniform locations */
GLuint modelLoc = glGetUniformLocation(shader.mProgram, "model"); GLuint modelLoc = glGetUniformLocation(shader->mProgram, "model");
GLuint viewLoc = glGetUniformLocation(shader.mProgram, "view"); GLuint viewLoc = glGetUniformLocation(shader->mProgram, "view");
GLuint projectionLoc = glGetUniformLocation(shader.mProgram, "projection"); GLuint projectionLoc = glGetUniformLocation(shader->mProgram, "projection");
/* Pass matrices to the shader */ /* Pass matrices to the shader */
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));

View File

@ -0,0 +1,34 @@
#ifndef DENGINE_ASSET_MANAGER_H
#define DENGINE_ASSET_MANAGER_H
#include <Dengine\Common.h>
#include <Dengine\Texture.h>
#include <Dengine\Shader.h>
#include <map>
#include <string>
#include <iostream>
namespace Dengine
{
class AssetManager
{
public:
AssetManager();
~AssetManager();
/* Texture */
Texture *getTexture(std::string name);
i32 loadTextureImage(std::string path, std::string name);
/* Shaders */
Shader *getShader(std::string name);
i32 loadShaderFiles(std::string vertexPath, std::string fragmentPath,
std::string name);
private:
std::map<std::string, Texture> mTextures;
std::map<std::string, Shader> mShaders;
};
}
#endif

View File

@ -12,11 +12,12 @@ namespace Dengine
public: public:
GLuint mProgram; GLuint mProgram;
Shader(std::string vertexPath, std::string fragmentPath); Shader();
~Shader(); ~Shader();
void use(); i32 loadProgram(GLuint vertexShader, GLuint fragmentShader);
void use();
}; };
} }

View File

@ -0,0 +1,43 @@
#ifndef DENGINE_TEXTURE_H
#define DENGINE_TEXTURE_H
#include <Dengine\OpenGL.h>
#include <Dengine\Common.h>
namespace Dengine
{
class Texture
{
public:
// Holds the ID of the texture object, used for all texture operations to
// reference to this particlar texture
GLuint mId;
// Texture image dimensions
GLuint mWidth;
GLuint mHeight;
// Texture Format
GLuint mInternalFormat; // Format of texture object
GLuint mImageFormat; // Format of loaded image
// Texture configuration
GLuint mWrapS; // Wrapping mode on S axis
GLuint mWrapT; // Wrapping mode on T axis
// Filtering mode if texture pixels < screen pixels
GLuint mFilterMinification;
// Filtering mode if texture pixels > screen pixels
GLuint mFilterMagnification;
// Constructor (sets default texture modes)
Texture();
// Generates texture from image data
void generate(GLuint width, GLuint height, unsigned char *data);
// Binds the texture as the current active GL_TEXTURE_2D texture object
void bind() const;
};
}
#endif