diff --git a/src/Application.cpp b/src/Application.cpp index 1eb7448..724e243 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,4 +1,5 @@ #include "Application.h" +#include "util/Log.h" Application::Application() { @@ -14,7 +15,6 @@ void Application::Initialize() { if (SDL_Init(SDL_INIT_VIDEO) < 0) { - std::cout << "Failed to init SDL\n"; printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); return; } @@ -37,13 +37,13 @@ void Application::Initialize() // Set GL Attributes SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GLContext glContext = SDL_GL_CreateContext(m_window); + m_glContext = SDL_GL_CreateContext(m_window); - if(glContext == NULL) + if(m_glContext == NULL) { printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError()); return; @@ -59,20 +59,27 @@ void Application::Initialize() void Application::Run() { m_run = true; + now_ = SDL_GetPerformanceCounter(); + last_ = 0; - while (m_run) + while(m_run) { + last_ = now_; + now_ = SDL_GetPerformanceCounter(); while(SDL_PollEvent(&m_event) != 0) { // Close button is pressed if(m_event.type == SDL_QUIT) { - m_run = false; + Exit(); } } - Render(); + deltaTime_ = ((now_ - last_) / (double)SDL_GetPerformanceFrequency()); + Update(deltaTime_); + Render(); + // Set background color as cornflower blue glClearColor(0.39f, 0.58f, 0.93f, 1.f); @@ -83,17 +90,22 @@ void Application::Run() SDL_GL_SwapWindow(m_window); } - //Destroy window + // After loop exits + + // Destroy window SDL_DestroyWindow(m_window); m_window = NULL; - //Quit SDL subsystems + // Destroy context + SDL_GL_DeleteContext(m_glContext); + + // Quit SDL subsystems SDL_Quit(); } void Application::Update(GLfloat dtime) { - + log_info(std::to_string(dtime)); } void Application::Render() diff --git a/src/Application.h b/src/Application.h index 179541a..df264c2 100644 --- a/src/Application.h +++ b/src/Application.h @@ -1,17 +1,27 @@ #ifndef __APPLICATION_H__ #define __APPLICATION_H__ -#include "Common.h" +#include "util/Common.h" +#include "util/Singleton.h" -class Application +class Application : public Singleton { public: Application(); ~Application(); void Initialize(); + void Exit() { m_run = false; } + + friend class Singleton; private: SDL_Window* m_window; SDL_Event m_event; + SDL_GLContext m_glContext; + + GLuint now_; + GLuint last_; + double deltaTime_; + bool m_run; void Run(); diff --git a/src/Main.cpp b/src/Main.cpp index 5df56f8..8fde13b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -2,7 +2,6 @@ int main(int argc, char const *argv[]) { - Application app; - app.Initialize(); + Application::getInstance().Initialize(); return 0; } diff --git a/src/Shader.cpp b/src/Shader.cpp new file mode 100644 index 0000000..2b373fa --- /dev/null +++ b/src/Shader.cpp @@ -0,0 +1,200 @@ +#include "Shader.h" + +/** Compile a shader from file */ +void Shader::compileShader(const string& filePath, GLuint& id) +{ + // Load shader file + std::ifstream shaderFile(filePath); + if(shaderFile.fail()) + { + fatalError("Failed to open file @"+filePath); + } + + string fileContents = ""; + string line; + + while(std::getline(shaderFile, line)) + { + fileContents += line + "\n"; + } + + shaderFile.close(); + + const char* contentsPointer = fileContents.c_str(); + + // Create the shader with the contents of the file + glShaderSource(id, 1, &contentsPointer, nullptr); + glCompileShader(id); + + GLint isCompiled = 0; + glGetShaderiv(id, GL_COMPILE_STATUS, &isCompiled); + if(isCompiled == GL_FALSE) + { + GLint maxLength = 0; + glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + std::vector errorLog(maxLength); + glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]); + + glDeleteShader(id); + + // Exit with failure. + std::printf("%s\n", &(errorLog[0])); + fatalError("Shader " + filePath + " failed to compile"); + } +} + +/** Create new shader from vertex and fragment files */ +Shader& Shader::createShader(const string& vertexShaderFilePath, const string& fragmentShaderFilePath) +{ + Shader* shader = new Shader(); + + shader->m_programID = glCreateProgram(); + shader->m_vertexShaderID = glCreateShader(GL_VERTEX_SHADER); + if(shader->m_vertexShaderID == 0) + { + fatalError("Vertex shader failed to be created!"); + } + + shader->m_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + if(shader->m_fragmentShaderID == 0) + { + fatalError("Fragment shader failed to be created!"); + } + + Shader::compileShader(vertexShaderFilePath, shader->m_vertexShaderID); + Shader::compileShader(fragmentShaderFilePath, shader->m_fragmentShaderID); + + return *shader; +} + +/** Get uniform location */ +GLuint Shader::getUniformLocation(const string& uniformName) +{ + auto it = m_uniforms.find(uniformName); + if (it == m_uniforms.end()) + { + // Get uniform location + GLint r = glGetUniformLocation(m_programID, uniformName.c_str()); + if ( r == GL_INVALID_OPERATION || r < 0 ) + log_warn("Uniform " + uniformName + " doesn't exist in program."); + + // Add it to the cache + m_uniforms[uniformName] = r; + + return r; + } + else + { + return it->second; + } +} + +/** Link the shaders together */ +void Shader::linkShaders() +{ + // Attach our shaders to our program + glAttachShader(m_programID, m_vertexShaderID); + glAttachShader(m_programID, m_fragmentShaderID); + + // Link our program + glLinkProgram(m_programID); + + // Note the different functions here: glGetProgram* instead of glGetShader*. + GLint isLinked = 0; + glGetProgramiv(m_programID, GL_LINK_STATUS, (int *)&isLinked); + if(isLinked == GL_FALSE) + { + GLint maxLength = 0; + glGetProgramiv(m_programID, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + std::vector infoLog(maxLength); + glGetProgramInfoLog(m_programID, maxLength, &maxLength, &infoLog[0]); + + // We don't need the program anymore. + glDeleteProgram(m_programID); + + // Don't leak shaders either. + glDeleteShader(m_vertexShaderID); + glDeleteShader(m_fragmentShaderID); + + fatalError("Shader linking failed!"); + std::printf("%s\n", &(infoLog[0])); + } + + // Always detach shaders after a successful link. + glDetachShader(m_programID, m_vertexShaderID); + glDetachShader(m_programID, m_fragmentShaderID); + glDeleteShader(m_vertexShaderID); + glDeleteShader(m_fragmentShaderID); +} + +/** Bind attribute location */ +void Shader::addAttribute(const string& attribName) +{ + glBindAttribLocation(m_programID, m_attributes++, attribName.c_str()); +} + +/** Bind the shader for usage */ +void Shader::start() +{ + glUseProgram(m_programID); +} + +/** Unbind the shader */ +void Shader::stop() +{ + glUseProgram(0); +} + +void Shader::setUniform(const string& name, float x, float y, float z) +{ + glUniform3f(getUniformLocation(name), x, y, z); +} + +void Shader::setUniform(const string& name, const vec3& v) +{ + glUniform3fv(getUniformLocation(name), 1, value_ptr(v)); +} + +void Shader::setUniform(const string& name, const dvec3& v) +{ + glUniform3dv(getUniformLocation(name), 1, value_ptr(v)); +} + +void Shader::setUniform(const string& name, const vec4& v) +{ + glUniform4fv(getUniformLocation(name), 1, value_ptr(v)); +} + +void Shader::setUniform(const string& name, const dvec4& v) +{ + glUniform4dv(getUniformLocation(name), 1, value_ptr(v)); +} + +void Shader::setUniform(const string& name, const dmat4& m) +{ + glUniformMatrix4dv(getUniformLocation(name), 1, GL_FALSE, value_ptr(m)); +} + +void Shader::setUniform(const string& name, const mat4& m) +{ + glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, value_ptr(m)); +} + +void Shader::setUniform(const string& name, const mat3& m) +{ + glUniformMatrix3fv(getUniformLocation(name), 1, GL_FALSE, value_ptr(m)); +} + +void Shader::setUniform(const string& name, float val) +{ + glUniform1f(getUniformLocation(name), val); +} + +void Shader::setUniform(const string& name, int val) +{ + glUniform1i(getUniformLocation(name), val); +} diff --git a/src/Shader.h b/src/Shader.h new file mode 100644 index 0000000..96dc929 --- /dev/null +++ b/src/Shader.h @@ -0,0 +1,45 @@ +#ifndef __SHADER_H__ +#define __SHADER_H__ +#include +#include + +#include "util/Common.h" +#include "util/Log.h" + +class Shader +{ +public: + static Shader& createShader(const string& vertexShaderFilePath, const string& fragmentShaderFilePath); + + void linkShaders(); + + void addAttribute(const string& attribName); + + GLuint getUniformLocation(const string& uniformName); + + void setUniform(const string& name, float x, float y, float z); + void setUniform(const string& name, const vec3& v); + void setUniform(const string& name, const dvec3& v); + void setUniform(const string& name, const vec4& v); + void setUniform(const string& name, const dvec4& v); + void setUniform(const string& name, const dmat4& m); + void setUniform(const string& name, const mat4& m); + void setUniform(const string& name, const mat3& m); + void setUniform(const string& name, float val); + void setUniform(const string& name, int val); + + void start(); + void stop(); +private: + int m_attributes; + + GLuint m_programID; + GLuint m_vertexShaderID; + GLuint m_fragmentShaderID; + + map m_uniforms; + + static void compileShader(const string& filePath, GLuint& id); +}; + +#endif // __SHADER_H__ diff --git a/src/Common.h b/src/util/Common.h similarity index 90% rename from src/Common.h rename to src/util/Common.h index a335733..71e87be 100644 --- a/src/Common.h +++ b/src/util/Common.h @@ -13,6 +13,8 @@ #include #include +#include "util/Math3D.h" + using namespace std; #endif // __COMMON_H__ diff --git a/src/util/Log.h b/src/util/Log.h new file mode 100644 index 0000000..adbcf0a --- /dev/null +++ b/src/util/Log.h @@ -0,0 +1,31 @@ +#ifndef __LOG_H__ +#define __LOG_H__ + +#include "Application.h" + +#include +#include + +#define FPRNT(io,tag,message) fprintf(io, "[%s] %s\n", tag, message.c_str()); + +inline void fatalError(const std::string message) +{ + FPRNT(stderr, "FATAL ERROR", message); + Application::getInstance().Exit(); +} + +inline void log_info(const std::string& message) +{ + FPRNT(stdout, "Info", message); +} + +inline void log_warn(const std::string& message) +{ + FPRNT(stdout, "Warning", message); +} + +inline void log_error(const std::string& message) +{ + FPRNT(stdout, "Error", message); +} +#endif // __LOG_H__ diff --git a/src/util/Math3D.h b/src/util/Math3D.h new file mode 100644 index 0000000..3199265 --- /dev/null +++ b/src/util/Math3D.h @@ -0,0 +1,12 @@ +#ifndef __MATH_H__ +#define __MATH_H__ +// TODO: Write custom math class +// Using GLM for now + +#include +#include +#include + +using namespace glm; + +#endif // __MATH_H__ diff --git a/src/util/Singleton.h b/src/util/Singleton.h new file mode 100644 index 0000000..64a32d4 --- /dev/null +++ b/src/util/Singleton.h @@ -0,0 +1,32 @@ +#ifndef __SINGLETON_H__ +#define __SINGLETON_H__ + +/** + * @brief Abstract class for singleton pattern +**/ +template +class Singleton { + public: + /** + * I think this could be could be set as private without + * any harm... + * @return The instance of C + **/ + inline static C& getInstance() { + // Being declared as static, I will be consistant over the getInstance() calls + // and destroyed at the end of the program. + static C I; + return I; + } + + protected: + // Prevents construction... + Singleton() {} + // ...as well as copy construction... + Singleton(const C&) {} + Singleton& operator=(const C&) {} + // ...or premature destruction. + virtual ~Singleton() {} + +}; +#endif // __SINGLETON_H__