diff --git a/Engine/Engine.sln b/Engine/Engine.sln new file mode 100644 index 0000000..58502f8 --- /dev/null +++ b/Engine/Engine.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33516.290 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Engine", "Engine\Engine.vcxproj", "{3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Debug|x64.ActiveCfg = Debug|x64 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Debug|x64.Build.0 = Debug|x64 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Debug|x86.ActiveCfg = Debug|Win32 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Debug|x86.Build.0 = Debug|Win32 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Release|x64.ActiveCfg = Release|x64 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Release|x64.Build.0 = Release|x64 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Release|x86.ActiveCfg = Release|Win32 + {3BEE640E-71B2-4D18-9D8C-8B6B85CAE21A}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {25B3C080-617C-4BEA-9F36-818FB47E657F} + EndGlobalSection +EndGlobal diff --git a/Engine/Engine/Engine.vcxproj b/Engine/Engine/Engine.vcxproj new file mode 100644 index 0000000..93be4d1 --- /dev/null +++ b/Engine/Engine/Engine.vcxproj @@ -0,0 +1,158 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3bee640e-71b2-4d18-9d8c-8b6b85cae21a} + Engine + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + T:\Privat\Daniel\Selfmade\libraries\glad\include;T:\Privat\Daniel\Selfmade\libraries\glfw\include;$(IncludePath) + T:\Privat\Daniel\Selfmade\libraries\glfw\lib;$(LibraryPath) + + + C:\Users\Daniel\Documents\SelfmadeProgramme\libraries\glad\include;C:\Users\Daniel\Documents\SelfmadeProgramme\libraries\glfw\include;$(IncludePath) + C:\Users\Daniel\Documents\SelfmadeProgramme\libraries\glfw\lib;$(LibraryPath) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + glfw3.lib;opengl32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + glfw3.lib;opengl32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Engine/Engine/Engine.vcxproj.filters b/Engine/Engine/Engine.vcxproj.filters new file mode 100644 index 0000000..e12aec4 --- /dev/null +++ b/Engine/Engine/Engine.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + \ No newline at end of file diff --git a/Engine/Engine/exceptions/IOException.h b/Engine/Engine/exceptions/IOException.h new file mode 100644 index 0000000..8b70dbc --- /dev/null +++ b/Engine/Engine/exceptions/IOException.h @@ -0,0 +1,22 @@ +#pragma once +#include + +namespace Nebulix +{ + /// + /// This exception will be thrown if there is an error to do with its IO. For example opening the file + /// + class IOException : public std::runtime_error + { + public: + using runtime_error::runtime_error; + + IOException() : runtime_error{ "ERROR::FILE::IO" } {} + /// + /// Overrides the default error message + /// + IOException(std::string message) : runtime_error{ message } {} + + private: + }; +} diff --git a/Engine/Engine/exceptions/shaders/CreateProgramException.h b/Engine/Engine/exceptions/shaders/CreateProgramException.h new file mode 100644 index 0000000..22aaf8c --- /dev/null +++ b/Engine/Engine/exceptions/shaders/CreateProgramException.h @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace Nebulix +{ + class CreateProgramException : public std::runtime_error + { + public: + using runtime_error::runtime_error; + + CreateProgramException(std::string &message) : runtime_error{ "ERROR::SHADER::CREATE_PROGRAM\n" + message } {} + + private: + }; +} diff --git a/Engine/Engine/exceptions/shaders/ShaderCompileException.h b/Engine/Engine/exceptions/shaders/ShaderCompileException.h new file mode 100644 index 0000000..ee5b18a --- /dev/null +++ b/Engine/Engine/exceptions/shaders/ShaderCompileException.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include "../../shaders/Enums.h" + +namespace Nebulix +{ + class ShaderCompileException: public std::exception + { + public: + ShaderCompileException() = delete; + + ShaderCompileException(Nebulix::ShaderType shaderType, std::string compileMessage) + { + std::string shader; + + switch (shaderType) + { + case Nebulix::ShaderType::Vertex: + shader = std::string{"VERTEX"}; + break; + case Nebulix::ShaderType::Fragment: + shader = std::string{ "FRAGMENT" }; + break; + default: + shader = std::string{ "UNKNOWN" }; + break; + } + _message = "ERROR::SHADER::" + shader + "::COMPILATION_FAILED\n Error message -> " + compileMessage; + } + + virtual const char* what() const override + { + return _message.c_str(); + } + + private: + std::string _message; + }; +} diff --git a/Engine/Engine/main.cpp b/Engine/Engine/main.cpp new file mode 100644 index 0000000..9bdaac2 --- /dev/null +++ b/Engine/Engine/main.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include + +#include "shaders/Shader.h" + +// Continue: https://learnopengl.com/Getting-started/Shaders +// Chapter: Not yet started +// + + +// +// HOW TO redirect error output to file +// Maybe it is possible to redirect to another stream object which adds infos like thread id/time etc.? +// +// std::ofstream errorFile("error.log"); +// std::streambuf* originalCerrBuffer = std::cerr.rdbuf(); // Save original buffer +// Redirect cerr to the error file +// std::cerr.rdbuf(errorFile.rdbuf()); + +#define WINDOW_WIDTH 800 +#define WINDOW_HEIGHT 600 + + +void OnWindowResize(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +void ProcessInput(GLFWwindow* window) +{ + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) + glfwSetWindowShouldClose(window, true); +} + +int main() +{ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Henlo worl", nullptr, nullptr); + + if (window == nullptr) + { + std::cerr << "Failed to create GLFW window"; + glfwTerminate(); + + return -1; + } + + glfwMakeContextCurrent(window); + + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cerr << "Failed to initialise GLAD"; + return -1; + } + + OnWindowResize(window, WINDOW_WIDTH, WINDOW_HEIGHT); + glfwSetFramebufferSizeCallback(window, OnWindowResize); + + GLfloat vertices[] = { + 0.5f, 0.5f, 0.0f, // top right + 0.5f, -0.5f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, // bottom left + -0.5f, 0.5f, 0.0f // top left + }; + GLuint indices[]{ + 0, 1, 3, + 1, 2, 3 + }; + + GLuint vertexBufferObject, elementBufferObject, vertexArrayObject; + glGenVertexArrays(1, &vertexArrayObject); + glGenBuffers(1, &vertexBufferObject); + glGenBuffers(1, &elementBufferObject); + + glBindVertexArray(vertexArrayObject); + + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + // I could unbind the VAO, but this is usually not needed because when creating a new VAO we need to bind that to change it anyway, so there shouldn't be a problem + + std::string vertexPath = "shaders/default/default.vert"; + std::string fragmentPath = "shaders/default/default.frag"; + + std::unique_ptr shader; + try + { + shader = std::make_unique(vertexPath, fragmentPath); + } + catch (const std::exception &e) + { + std::cerr << e.what(); + return -1; + } + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // main loop + while(!glfwWindowShouldClose(window)) + { + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + ProcessInput(window); + + shader->Use(); + glBindVertexArray(vertexArrayObject); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional, as we are at the end of the program. + glDeleteVertexArrays(1, &vertexArrayObject); + glDeleteBuffers(1, &elementBufferObject); + + glfwTerminate(); + return 0; +} \ No newline at end of file diff --git a/Engine/Engine/shaders/Enums.h b/Engine/Engine/shaders/Enums.h new file mode 100644 index 0000000..2615192 --- /dev/null +++ b/Engine/Engine/shaders/Enums.h @@ -0,0 +1,12 @@ +#pragma once + +namespace Nebulix +{ + enum class ShaderType + { + Vertex, + Fragment, + Unknown + // TODO: Add compute etc in future + }; +} \ No newline at end of file diff --git a/Engine/Engine/shaders/Shader.cpp b/Engine/Engine/shaders/Shader.cpp new file mode 100644 index 0000000..bf9298f --- /dev/null +++ b/Engine/Engine/shaders/Shader.cpp @@ -0,0 +1,98 @@ +#include +#include +#include "Shader.h" + +#include "../Exceptions/IOException.h" +#include "../Exceptions/Shaders/ShaderCompileException.h" +#include "../exceptions/shaders/CreateProgramException.h" + +namespace Nebulix +{ + + const char* vertexShaderSourceCode = "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; + const char* fragmentShaderSourceCode = "#version 330 core\n" + "out vec4 FragColor;\n" + "void main()\n" + "{\n" + " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + + Shader::Shader(std::string& vertexShaderfile, std::string& fragmentShaderfile): _vertexFile{vertexShaderfile}, _fragmentFile{fragmentShaderfile} + { + std::ifstream vertexShaderSource(vertexShaderfile), fragmentShaderSource(fragmentShaderfile); + GLuint vertexShader = 0, fragmentShader = 0; + + CompileShadercode(vertexShaderSource, vertexShader, ShaderType::Vertex); + CompileShadercode(fragmentShaderSource, fragmentShader, ShaderType::Fragment); + + CreateProgram(vertexShader, fragmentShader); + } + + void Shader::CompileShadercode(std::ifstream& shaderSource, GLuint& shaderObject, ShaderType type) + { + if (!shaderSource.is_open()) + { + throw IOException("ERROR::SHADER::CANNOT_OPEN_FILE"); + } + + const char* shader; + + shaderSource.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + std::stringstream sourceCode; + sourceCode << shaderSource.rdbuf(); + shaderSource.close(); + std::string code = sourceCode.str(); + shader = code.c_str(); + } + catch (const std::exception&) + { + throw Nebulix::IOException("ERROR::SHADER::READ_FILE"); + } + + + if (type == ShaderType::Vertex) + shaderObject = glCreateShader(GL_VERTEX_SHADER); + else if (type == ShaderType::Fragment) + shaderObject = glCreateShader(GL_FRAGMENT_SHADER); + else + throw std::runtime_error("ERROR::SHADER::TYPE \nCannot create shader program with the given shader type '" + std::to_string((int)type) + "'"); + + glShaderSource(shaderObject, 1, &shader, NULL); + glCompileShader(shaderObject); + + int success; + char infoLog[512]; + glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(shaderObject, 512, NULL, infoLog); + throw Nebulix::ShaderCompileException(type, infoLog); + } + } + + void Shader::CreateProgram(GLuint& vertexShader, GLuint& fragmentShader) + { + shaderId = glCreateProgram(); + glAttachShader(shaderId, vertexShader); + glAttachShader(shaderId, fragmentShader); + glLinkProgram(shaderId); + + int success; + char infoLog[512]; + glGetProgramiv(shaderId, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderId, 512, NULL, infoLog); + throw Nebulix::CreateProgramException(infoLog); + } + + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + } +} diff --git a/Engine/Engine/shaders/Shader.h b/Engine/Engine/shaders/Shader.h new file mode 100644 index 0000000..dbb4c0f --- /dev/null +++ b/Engine/Engine/shaders/Shader.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include +#include "Enums.h" + + +namespace Nebulix +{ + class Shader + { + public: + Shader() = delete; + Shader(std::string& vertexShaderfile, std::string& fragmentShaderfile); + ~Shader() + { + glDeleteProgram(shaderId); + } + + /// + /// To actually use and activate the shader, call this. + /// + void Use() { glUseProgram(shaderId); } + + void setBool(const std::string& name, bool value) const + { + glUniform1i(glGetUniformLocation(shaderId, name.c_str()), (int)value); + } + void setInt(const std::string& name, int value) const + { + glUniform1i(glGetUniformLocation(shaderId, name.c_str()), value); + } + void setFloat(const std::string& name, float value) const + { + glUniform1f(glGetUniformLocation(shaderId, name.c_str()), value); + } + + private: + std::string &_vertexFile, &_fragmentFile; + GLuint shaderId; + + void CompileShadercode(std::ifstream& shaderSource, GLuint& shaderId, ShaderType type); + void CreateProgram(GLuint& vertexShader, GLuint& fragmentShader); + }; +} diff --git a/Engine/Engine/shaders/default/default.frag b/Engine/Engine/shaders/default/default.frag new file mode 100644 index 0000000..2ccfb50 --- /dev/null +++ b/Engine/Engine/shaders/default/default.frag @@ -0,0 +1,7 @@ +#version 330 core +out vec4 FragColor; + +void main() +{ + FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); +} \ No newline at end of file diff --git a/Engine/Engine/shaders/default/default.vert b/Engine/Engine/shaders/default/default.vert new file mode 100644 index 0000000..d7bd59a --- /dev/null +++ b/Engine/Engine/shaders/default/default.vert @@ -0,0 +1,7 @@ +#version 330 core +layout (location = 0) in vec3 aPos; + +void main() +{ + gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); +}