From 0be3e0a50e2292d8b2a56fd7b180fc11afd6e0a5 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Fri, 14 Nov 2014 14:16:52 +0100 Subject: [PATCH] Initial import --- .gitignore | 2 + Makefile | 20 +++ main.cc | 487 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 509 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 main.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..646cd13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +objs/ +oglpg diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4a447bd --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +CXX=g++ +CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++11 +LDOPTS=-flto +LIBS=-lGL -lSDL2 +CXXSRCS=main.cc +OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o)) + +objs/%.o: %.cc + $(CXX) $(CXXOPTS) -c -MMD -MP -o $@ $< + @cp objs/$*.d objs/$*.P; rm -f objs/$*.d + +oglpg: $(OBJS) + $(CXX) $(CXXOPTS) $(LDOPTS) -o $@ $(OBJS) $(LIBS) + +clean: + rm -f oglpg $(OBJS) $(addprefix objs/,$(CXXSRCS:.cc=.P)) + +.PHONY: clean + +-include $(addprefix objs/,$(CXXSRCS:.cc=.P)) diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..3afca9f --- /dev/null +++ b/main.cc @@ -0,0 +1,487 @@ +#include +#include +#include +#include + +#define GL_GLEXT_PROTOTYPES +#include +//#include + +#define GLM_FORCE_RADIANS +#include +#include +#include +#include + +const char vertexShader[] = "#version 330 core\n" + "uniform mat4 projection_matrix;\n" + "uniform mat4 modelview_matrix;\n" + "\n" + "in vec3 vertex;\n" + "in vec3 vertexColor;\n" + "\n" + "out vec3 fragColor;\n" + "\n" + "void main(void) {\n" + "\tgl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);\n" + "\tfragColor = vertexColor;\n" + "}\n"; + +const char fragShader[] = "#version 330 core\n" + "in vec3 fragColor;\n" + "\n" + "out vec3 color;\n" + "\n" + "void main(void) {\n" + "\tcolor = fragColor;\n" + //"\tgl_FragDepth = gl_FragCoord.z;\n" + "}\n"; + +const float vertices[][3] = {{0.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {1.0f, 1.0f, 0.0f}, + + {0.0f, 0.0f, -1.0f}, + {1.0f, 0.0f, -1.0f}, + {0.0f, 1.0f, -1.0f}, + {1.0f, 1.0f, -1.0f}, + + {-1.0f, -2.0f, -5.0f}, + {-1.5f, -1.0f, -4.5f}, + {-0.5f, -1.0f, -4.5f}, + {-1.0f, -1.0f, -5.5f}}; + +const float colors[][3] = {{1.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, 1.0f}, + + {1.0f, 1.0f, 1.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, 1.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}}; + +const unsigned indices[] = {0, 2, 1, + 2, 3, 1, + + 0, 4, 1, + 1, 4, 5, + + 1, 7, 3, + 1, 5, 7, + + 2, 3, 7, + 2, 7, 6, + + 4, 6, 0, + 0, 6, 2, + + 4, 5, 6, + 5, 7, 6 +}; + +const unsigned indicesPyramid[] = {8, 10, 9, + 8, 11, 10, + 8, 9, 11, + 9, 10, 11}; + +class GLException{ +public: + GLException(GLenum err) : _err(err) { + } + + virtual ~GLException() {} + + int getErr() const {return _err;} + + std::string errToString() const { + std::string ret; + if (_err == GL_INVALID_ENUM) + ret += "GL_INVALID_ENUM "; + if (_err == GL_INVALID_VALUE) + ret += "GL_INVALID_VALUE "; + if (_err == GL_INVALID_OPERATION) + ret += "GL_INVALID_OPERATION "; + if (_err == GL_INVALID_FRAMEBUFFER_OPERATION) + ret += "GL_INVALID_FRAMEBUFFER_OPERATION "; + if (_err == GL_OUT_OF_MEMORY) + ret += "GL_OUT_OF_MEMORY "; + if (_err == GL_STACK_UNDERFLOW) + ret += "GL_STACK_UNDERFLOW "; + if (_err == GL_STACK_OVERFLOW) + ret += "GL_STACK_OVERFLOW "; + + return ret; + } + + virtual std::string toString() const { + return "GLException: " + errToString() + "(" + std::to_string(_err) + ")"; + } + +private: + GLenum _err; +}; + +class ShaderException : public GLException { +public: + ShaderException(std::string const& msg) : GLException(glGetError()), _msg(msg) { + } + + virtual ~ShaderException() {} + + std::string const& getMsg() const {return _msg;} + + virtual std::string toString() const { + return "ShaderException: " + _msg; + } + +private: + std::string _msg; +}; + +class Program; + +class Shader { +public: + Shader() : _shaderID(0) { + } + + Shader(std::string const& program, GLenum type) { + _shaderID = glCreateShader(type); + const char* const arr[] = {program.c_str()}; + glShaderSource(_shaderID, 1, arr, NULL); + glCompileShader(_shaderID); + + int state; + glGetShaderiv(_shaderID, GL_COMPILE_STATUS, &state); + + if (!state) { + int logLength; + glGetShaderiv(_shaderID, GL_INFO_LOG_LENGTH, &logLength); + + char *log = new char[logLength]; + glGetShaderInfoLog(_shaderID, logLength, NULL, log); + std::string msg(log); + delete[] log; + + glDeleteShader(_shaderID); + + throw ShaderException(msg); + } + } + + virtual ~Shader() { + glDeleteShader(_shaderID); + } + +protected: + unsigned getID() const { + return _shaderID; + } + + friend class Program; + + unsigned int _shaderID; +}; + + +class VertexShader : public Shader { +public: + VertexShader(std::string const& program) : Shader(program, GL_VERTEX_SHADER) { + } + + virtual ~VertexShader() { + } +}; + +class FragmentShader : public Shader { +public: + FragmentShader(std::string const& program) : Shader(program, GL_FRAGMENT_SHADER) { + } + + virtual ~FragmentShader() { + } +}; + +class GeometryShader : public Shader { +public: + GeometryShader(std::string const& program) : Shader(program, GL_GEOMETRY_SHADER) { + } + + virtual ~GeometryShader() { + } +}; + +class Program { +public: + Program(VertexShader& vertex, FragmentShader& frag) : _geom(nullptr), _vertex(vertex), _frag(frag) { + _progID = glCreateProgram(); + + glAttachShader(_progID, _vertex.getID()); + glAttachShader(_progID, _frag.getID()); + + glLinkProgram(_progID); + + int state; + glGetProgramiv(_progID, GL_LINK_STATUS, &state); + + if (!state) { + int logLength; + glGetProgramiv(_progID, GL_INFO_LOG_LENGTH, &logLength); + + char *log = new char[logLength]; + glGetProgramInfoLog(_progID, logLength, NULL, log); + std::string msg(log); + delete[] log; + + glDeleteProgram(_progID); + + throw ShaderException(msg); + } + + glDetachShader(_progID, _vertex.getID()); + glDetachShader(_progID, _frag.getID()); + } + + Program(GeometryShader& geom, VertexShader& vertex, FragmentShader& frag) : _geom(&geom), _vertex(vertex), _frag(frag) { + _progID = glCreateProgram(); + + glAttachShader(_progID, _geom->getID()); + glAttachShader(_progID, _vertex.getID()); + glAttachShader(_progID, _frag.getID()); + + glLinkProgram(_progID); + + int state; + glGetProgramiv(_progID, GL_LINK_STATUS, &state); + + if (!state) { + int logLength; + glGetProgramiv(_progID, GL_INFO_LOG_LENGTH, &logLength); + + char *log = new char[logLength]; + glGetProgramInfoLog(_progID, logLength, NULL, log); + std::string msg(log); + delete[] log; + + glDeleteProgram(_progID); + + throw ShaderException(msg); + } + + glDetachShader(_progID, _geom->getID()); + glDetachShader(_progID, _vertex.getID()); + glDetachShader(_progID, _frag.getID()); + } + + ~Program() { + glDeleteProgram(_progID); + } + + void use() const { + glUseProgram(_progID); + } + + int getUniformLocation(std::string const& name) const { + int ret = glGetUniformLocation(_progID, name.c_str()); + if (ret == -1) + throw GLException(glGetError()); + return ret; + } + + int getAttribLocation(std::string const& name) const { + int ret = glGetAttribLocation(_progID, name.c_str()); + if (ret == -1) + throw GLException(glGetError()); + return ret; + } + +private: + GeometryShader* _geom; + VertexShader& _vertex; + FragmentShader& _frag; + unsigned _progID; +}; + +void checkGlError() { + GLenum err; + if ((err = glGetError()) != GL_NO_ERROR) + throw GLException(err); +} + +int main(int argc, char *argv[]) +{ + SDL_Window *window; + int retcode = 0; + + SDL_Init(SDL_INIT_VIDEO); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + + window = SDL_CreateWindow("SDL2 Test", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 640, + 480, + /*SDL_WINDOW_FULLSCREEN_DESKTOP |*/ SDL_WINDOW_OPENGL); + + if (!window) { + std::printf("Could not create window: %s\n", SDL_GetError()); + SDL_Quit(); + return 1; + } + + SDL_GLContext glcontext = SDL_GL_CreateContext(window); + if (!glcontext) { + std::printf("Could not create GL context: %s\n", SDL_GetError()); + SDL_DestroyWindow(window); + SDL_Quit(); + return 1; + } + + try { + while(glGetError() != GL_NO_ERROR); + + { + int depth, stencil, aa, major, minor; + SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth); + SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil); + SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &aa); + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); + + std::printf("Depth: %d, Stencil: %d, AA: %d, GL %d.%d\n", + depth, stencil, aa, major, minor); + } + + int width, height; + SDL_GetWindowSize(window, &width, &height); + glm::mat4 proj = glm::perspectiveFov(75.0f, static_cast(width), static_cast(height), + 0.1f, 100.0f); + glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 10), + glm::vec3(0, 0, 0), + glm::vec3(0, 1, 0)); + // glm::mat4 model = glm::rotate(0.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + + // sf::Font font; + // if (!font.loadFromFile("DejaVuSans.ttf")) { + // std::printf("Error loading font\n"); + // return 1; + // } + + // sf::Text fpsText{"0", font, 12}; + // fpsText.setPosition({200, 200}); + + // window.setFramerateLimit(60); + + // sf::Clock clock; + // sf::Time last = clock.getElapsedTime(); + + checkGlError(); + + VertexShader vs{vertexShader}; + FragmentShader fs{fragShader}; + Program prog(vs, fs); + checkGlError(); + + prog.use(); + glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE, + glm::value_ptr(proj)); + checkGlError(); + + GLuint buf; + glGenBuffers(1, &buf); + glBindBuffer(GL_ARRAY_BUFFER, buf); + checkGlError(); + + glBufferData(GL_ARRAY_BUFFER, 2*sizeof(float)*3*12, NULL, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*12, (void*)vertices[0]); + glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*12, sizeof(float)*3*12, (void*)colors[0]); + + GLuint arr; + glGenVertexArrays(1, &arr); + glBindVertexArray(arr); + checkGlError(); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glEnable(GL_DEPTH_TEST); + checkGlError(); + + bool close = false; + + while (!close) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_KEYDOWN: + close = true; + break; + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_CLOSE) + close = true; + break; + } + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + checkGlError(); + prog.use(); + glm::mat4 model = glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)); + glUniformMatrix4fv(prog.getUniformLocation("modelview_matrix"), 1, GL_FALSE, + glm::value_ptr(view*model)); + checkGlError(); + glEnableVertexAttribArray(prog.getAttribLocation("vertex")); + glEnableVertexAttribArray(prog.getAttribLocation("vertexColor")); + checkGlError(); + glVertexAttribPointer(prog.getAttribLocation("vertex"), 3, GL_FLOAT, GL_FALSE, 0, 0); + checkGlError(); + glVertexAttribPointer(prog.getAttribLocation("vertexColor"), 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float)*3*12)); + checkGlError(); + glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, indices); + checkGlError(); + glUniformMatrix4fv(prog.getUniformLocation("modelview_matrix"), 1, GL_FALSE, + glm::value_ptr(view)); + checkGlError(); + glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, indicesPyramid); + + checkGlError(); + + // glUseProgram(0); + // sf::Time now = clock.getElapsedTime(); + // sf::Time elapsed = now - last; + // last = now; + // fpsText.setString(std::to_string(static_cast(std::roundf(1.0f/elapsed.asSeconds())))); + // fpsText.setPosition({1680-fpsText.getLocalBounds().width, 0}); + // window.draw(fpsText); + + SDL_GL_SwapWindow(window); + } + }catch(GLException &ex) { + std::printf("%s\n", ex.toString().c_str()); + retcode = 1; + } + + SDL_GL_DeleteContext(glcontext); + + SDL_DestroyWindow(window); + + // Clean up + SDL_Quit(); + + return retcode; +}