diff --git a/.gitignore b/.gitignore index 646cd13..813ec0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ objs/ oglpg +*.trace +*~ diff --git a/Makefile b/Makefile index 4a447bd..559ff6c 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ CXX=g++ -CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++11 +CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -std=c++11 LDOPTS=-flto -LIBS=-lGL -lSDL2 -CXXSRCS=main.cc +LIBS=-lGL -lSDL2 -lSDL2_image -lobj +CXXSRCS=main.cc objectParser.cc OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o)) objs/%.o: %.cc diff --git a/common.hh b/common.hh new file mode 100644 index 0000000..cbadf60 --- /dev/null +++ b/common.hh @@ -0,0 +1,121 @@ +#ifndef __OPENGLPLAYGROUND_COMMON_HH__ +#define __OPENGLPLAYGROUND_COMMON_HH__ + +#include +#include +#include +#include + +#define GL_GLEXT_PROTOTYPES +#include + +#include + +class Exception { +public: + Exception() { + } + + virtual ~Exception() {} + + virtual std::string toString() const = 0; +}; + +class POSIXException : public Exception { +public: + POSIXException(int err): Exception(), _err(err) { + } + + virtual ~POSIXException() {} + + int getErr() const {return _err;} + + virtual std::string toString() const { + return std::string("POSIXException: ") + std::strerror(_err); + } + +private: + int _err; +}; + +class GLException : public Exception { +public: + GLException(GLenum err) : Exception(), _err(err) { + } + + virtual ~GLException() {} + + GLenum 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 SDLException : public Exception { +public: + SDLException() : Exception(), _msg(SDL_GetError()) { + } + + virtual ~SDLException() {} + + virtual std::string toString() const { + return "SDLException: " + _msg; + } + +private: + std::string _msg; +}; + +static void checkGlError() { + GLenum err; + if ((err = glGetError()) != GL_NO_ERROR) + throw GLException(err); +} + +static std::string fileToString(std::string const& name) { + std::FILE *file = std::fopen(name.c_str(), "r"); + if (!file) { + throw POSIXException(errno); + } + + std::string ret; + char buf[512]; + std::size_t p; + while((p = std::fread(buf, 1, 511, file)) > 0) { + buf[p] = '\0'; + ret.append(buf); + } + if (!std::feof(file)) { + std::fclose(file); + throw POSIXException(errno); + } + + std::fclose(file); + return ret; +} + +#endif diff --git a/main.cc b/main.cc index 3afca9f..262825d 100644 --- a/main.cc +++ b/main.cc @@ -1,11 +1,12 @@ #include #include #include +#include #include +#include #define GL_GLEXT_PROTOTYPES #include -//#include #define GLM_FORCE_RADIANS #include @@ -13,29 +14,59 @@ #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"; +#include "common.hh" +#include "shaders.hh" +#include "texture.hh" +#include "objectParser.hh" -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 cubeVertexData[][5] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, 0.0f ,0.0f, 1.0f}, + {1.0f, 1.0f, 0.0f, 1.0f, 1.0f}, + + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, -1.0f, 1.0f, 0.0f}, + {1.0f, 1.0f, 0.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, -1.0f, 1.0f, 1.0f}, + + {1.0f, 0.0f, -1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, -1.0f, 1.0f, 0.0f}, + {1.0f, 1.0f, -1.0f, 0.0f, 1.0f}, + {0.0f, 1.0f, -1.0f, 1.0f, 1.0f}, + + {0.0f, 0.0f, -1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, -1.0f, 0.0f, 1.0f}, + {0.0f, 1.0f, 0.0f, 1.0f, 1.0f}, + + {0.0f, 0.0f, -1.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, -1.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, 0.0f, 1.0f, 1.0f}, + + {0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, + {1.0f, 1.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, -1.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, -1.0f, 1.0f, 1.0f}}; + +const uint8_t cubeIndices[] = {0, 1, 2, + 1, 2, 3, + + 4, 5, 6, + 5, 6, 7, + + 8, 9, 10, + 9, 10, 11, + + 12, 13, 14, + 13, 14, 15, + + 16, 17, 18, + 17, 18, 19, + + 20, 21, 22, + 21, 22, 23}; const float vertices[][3] = {{0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, @@ -66,6 +97,21 @@ const float colors[][3] = {{1.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}}; +const float texcoords[][2] = {{0.0f, 0.0f}, + {1.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 1.0f}, + + {1.0f, 1.0f}, + {1.0f, 0.0f}, + {0.0f, 1.0f}, + {0.0f, 0.0f}, + + {0.0f, 0.0f}, + {0.0f, 0.0f}, + {0.0f, 0.0f}, + {0.0f, 0.0f}}; + const unsigned indices[] = {0, 2, 1, 2, 3, 1, @@ -90,236 +136,20 @@ const unsigned indicesPyramid[] = {8, 10, 9, 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); + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + std::printf("Could not init SDL: %s\n", SDL_GetError()); + return 1; + } + if (IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) == 0) { + std::printf("Could not init SDL_image: %s\n", SDL_GetError()); + SDL_Quit(); + return 1; + } SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); @@ -327,7 +157,7 @@ int main(int argc, char *argv[]) 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_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); @@ -337,7 +167,7 @@ int main(int argc, char *argv[]) SDL_WINDOWPOS_UNDEFINED, 640, 480, - /*SDL_WINDOW_FULLSCREEN_DESKTOP |*/ SDL_WINDOW_OPENGL); + SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_OPENGL); if (!window) { std::printf("Could not create window: %s\n", SDL_GetError()); @@ -374,9 +204,7 @@ int main(int argc, char *argv[]) 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)); - + glm::vec3(0, 1, 0)); // sf::Font font; // if (!font.loadFromFile("DejaVuSans.ttf")) { // std::printf("Error loading font\n"); @@ -391,16 +219,29 @@ int main(int argc, char *argv[]) // sf::Clock clock; // sf::Time last = clock.getElapsedTime(); - checkGlError(); + Texture2D cubeTex("textures/Wood_Box_Texture.jpg"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic")) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4.0f); + else + std::printf("Warning: extension GL_EXT_texture_filter_anisotropic not supported\n"); + + auto box = readObject("objects/woodbox.obj"); - VertexShader vs{vertexShader}; - FragmentShader fs{fragShader}; + VertexShader vs{fileToString("shaders/textured.vs")}; + FragmentShader fs{fileToString("shaders/textured.fs")}; Program prog(vs, fs); checkGlError(); - + prog.use(); glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE, glm::value_ptr(proj)); + glUniform1i(prog.getUniformLocation("texBase"), 0); + + int vertexAL = prog.getAttribLocation("vertex"); + //int vertexColorAL = prog.getAttribLocation("vertexColor"); + int vertexTCAL = prog.getAttribLocation("vertexTC"); + checkGlError(); GLuint buf; @@ -408,13 +249,35 @@ int main(int argc, char *argv[]) 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]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*24*5, NULL, GL_STATIC_DRAW); + //glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*24*5, (void*)cubeVertexData[0]); + + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(objVertexAttribs)*std::get<0>(box).size(), + (void*)std::get<0>(box).data()); - GLuint arr; - glGenVertexArrays(1, &arr); - glBindVertexArray(arr); + // glBufferData(GL_ARRAY_BUFFER, sizeof(float)*(2*3*12+2*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]); + // glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*3*12, sizeof(float)*2*12, (void*)texcoords[0]); + + GLuint arr[2]; + glGenVertexArrays(2, arr); + checkGlError(); + + // glBindVertexArray(arr[0]); + // glEnableVertexAttribArray(vertexAL); + // glEnableVertexAttribArray(vertexColorAL); + // glEnableVertexAttribArray(vertexTCAL); + // glVertexAttribPointer(vertexAL, 3, GL_FLOAT, GL_FALSE, 0, 0); + // glVertexAttribPointer(vertexColorAL, 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float)*3*12)); + // glVertexAttribPointer(vertexTCAL, 2, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float)*2*3*12)); + + glBindVertexArray(arr[0]); + glEnableVertexAttribArray(vertexAL); + glEnableVertexAttribArray(vertexTCAL); + glVertexAttribPointer(vertexAL, 3, GL_FLOAT, GL_FALSE, sizeof(objVertexAttribs), offsetof(objVertexAttribs, vertex)); + glVertexAttribPointer(vertexTCAL, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(objVertexAttribs), + (void*)offsetof(objVertexAttribs, texCoords)); checkGlError(); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -440,26 +303,19 @@ int main(int argc, char *argv[]) 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)); + // glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, indices); + glDrawElements(GL_TRIANGLES, std::get<1>(box).size(), GL_UNSIGNED_SHORT, std::get<1>(box).data()); 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(); + // glUniformMatrix4fv(prog.getUniformLocation("modelview_matrix"), 1, GL_FALSE, + // glm::value_ptr(view)); + // glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, indicesPyramid); + // checkGlError(); // glUseProgram(0); // sf::Time now = clock.getElapsedTime(); @@ -471,7 +327,7 @@ int main(int argc, char *argv[]) SDL_GL_SwapWindow(window); } - }catch(GLException &ex) { + }catch(Exception &ex) { std::printf("%s\n", ex.toString().c_str()); retcode = 1; } diff --git a/objectParser.cc b/objectParser.cc new file mode 100644 index 0000000..82415ef --- /dev/null +++ b/objectParser.cc @@ -0,0 +1,281 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "objectParser.hh" + +using namespace obj; + +using std::tr1::placeholders::_1; +using std::tr1::placeholders::_2; +using std::tr1::placeholders::_3; +using std::tr1::placeholders::_4; + + +class ObjectParser { +private: + void texture_vertex_callback(obj::float_type u, obj::float_type v) + { + if ((u > 1.0f) || (u < 0.0f)) + std::cout << "Warning: Clamping texture coordinate U to [0.0, 1.0]" << std::endl; + uint16_t c_u = static_cast(fminf(1.0f, fmaxf(0.0f, u))*65535.0); + if ((v > 1.0f) || (v < 0.0f)) + std::cout << "Warning: Clamping texture coordinate V to [0.0, 1.0]" << std::endl; + uint16_t c_v = static_cast(fminf(1.0f, fmaxf(0.0f, v))*65535.0); + _texCoords.emplace_back(c_u, c_v); + std::cout << "vt " << c_u << " " << c_v << "\n"; + } + + void geometric_vertex_callback(obj::float_type x, obj::float_type y, obj::float_type z) + { + _vertices.emplace_back(x, y, z); + std::cout << "v " << x << " " << y << " " << z << "\n"; + } + + void vertex_normal_callback(obj::float_type x, obj::float_type y, obj::float_type z) + { + union { + struct { + signed :2; + signed z:10; + signed y:10; + signed x:10; + } bits; + uint32_t all; + } pack_10; + if ((x > 1.0f) || (x < -1.0f)) + std::cout << "Warning: Clamping normal X to [-1.0, 1.0]" << std::endl; + pack_10.bits.x = static_cast(fminf(1.0f, fmaxf(-1.0f, x))*511.0); + if ((y > 1.0f) || (y < -1.0f)) + std::cout << "Warning: Clamping normal Y to [-1.0, 1.0]" << std::endl; + pack_10.bits.y = static_cast(fminf(1.0f, fmaxf(-1.0f, y))*511.0); + if ((z > 1.0f) || (z < -1.0f)) + std::cout << "Warning: Clamping normal Z to [-1.0, 1.0]" << std::endl; + pack_10.bits.z = static_cast(fminf(1.0f, fmaxf(-1.0f, z))*511.0); + _normals.push_back(pack_10.all); + std::cout << "vn " << pack_10.bits.x << " " << pack_10.bits.y << " " << pack_10.bits.z << "\n"; + } + + void triangular_face_geometric_vertices_callback(index_type a, index_type b, index_type c) + { + } + + size_t _find_vertex_tc_pair(index_2_tuple_type const& a) + { + auto pair_it = _vertex_tc_pairs_map.find(std::tuple(std::tr1::get<0>(a), std::tr1::get<1>(a))); + size_t pair_pos; + if (pair_it != _vertex_tc_pairs_map.end()) + pair_pos = pair_it->second; + else { + _vertex_tc_pairs.emplace_back(std::get<0>(_vertices[std::tr1::get<0>(a)-1]), + std::get<1>(_vertices[std::tr1::get<0>(a)-1]), + std::get<2>(_vertices[std::tr1::get<0>(a)-1]), + std::get<0>(_texCoords[std::tr1::get<1>(a)-1]), + std::get<1>(_texCoords[std::tr1::get<1>(a)-1])); + pair_pos = _vertex_tc_pairs.size()-1; + _vertex_tc_pairs_map.emplace(std::tuple(std::tr1::get<0>(a), std::tr1::get<1>(a)), + pair_pos); + } + return pair_pos; + } + + void triangular_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c) + { + if ((_vertices.size() < std::tr1::get<0>(a)) || + (_vertices.size() < std::tr1::get<0>(b)) || + (_vertices.size() < std::tr1::get<0>(c))) + throw ParseException("Vertex Index out of range"); + if ((_texCoords.size() < std::tr1::get<1>(a)) || + (_texCoords.size() < std::tr1::get<1>(b)) || + (_texCoords.size() < std::tr1::get<1>(c))) + throw ParseException("Texture Coordinate Index out of range"); + + std::cout << "f (" << std::tr1::get<0>(a) << ", " << std::tr1::get<1>(a) << ")" << + " (" << std::tr1::get<0>(b) << ", " << std::tr1::get<1>(b) << ")" << + " (" << std::tr1::get<0>(c) << ", " << std::tr1::get<1>(c) << ")\n"; + + size_t a_pos = _find_vertex_tc_pair(a); + size_t b_pos = _find_vertex_tc_pair(b); + size_t c_pos = _find_vertex_tc_pair(c); + _faces.emplace_back(a_pos, b_pos, c_pos); + + std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n"; + } + + void triangular_face_geometric_vertices_vertex_normals_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c) + { + } + + void triangular_face_geometric_vertices_texture_vertices_vertex_normals_callback(index_3_tuple_type a, index_3_tuple_type b, + index_3_tuple_type c) + { + } + + void quadrilateral_face_geometric_vertices_callback(index_type a, index_type b, index_type c, index_type d) + { + assert(false); + } + + void quadrilateral_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b, + index_2_tuple_type c, index_2_tuple_type d) + { + assert(false); + } + + void quadrilateral_face_geometric_vertices_vertex_normals_callback(index_2_tuple_type a, index_2_tuple_type b, + index_2_tuple_type c, index_2_tuple_type d) + { + assert(false); + } + + void quadrilateral_face_geometric_vertices_texture_vertices_vertex_normals_callback(index_3_tuple_type a, index_3_tuple_type b, + index_3_tuple_type c, index_3_tuple_type d) + { + assert(false); + } + + void polygonal_face_geometric_vertices_begin_callback(index_type a, index_type b, index_type c) + { + assert(false); + } + + void polygonal_face_geometric_vertices_vertex_callback(index_type a) + { + assert(false); + } + + void polygonal_face_geometric_vertices_end_callback() + { + assert(false); + } + + void polygonal_face_geometric_vertices_texture_vertices_begin_callback(index_2_tuple_type a, index_2_tuple_type b, + index_2_tuple_type c) + { + assert(false); + } + + void polygonal_face_geometric_vertices_texture_vertices_vertex_callback(index_2_tuple_type a) + { + assert(false); + } + + void polygonal_face_geometric_vertices_texture_vertices_end_callback() + { + assert(false); + } + + void polygonal_face_geometric_vertices_vertex_normals_begin_callback(index_2_tuple_type a, index_2_tuple_type b, + index_2_tuple_type c) + { + assert(false); + } + + void polygonal_face_geometric_vertices_vertex_normals_vertex_callback(index_2_tuple_type a) + { + assert(false); + } + + void polygonal_face_geometric_vertices_vertex_normals_end_callback() + { + assert(false); + } + + void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_begin_callback(index_3_tuple_type a, index_3_tuple_type b, + index_3_tuple_type c) + { + assert(false); + } + + void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_vertex_callback(index_3_tuple_type a) + { + assert(false); + } + + void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_end_callback() + { + assert(false); + } + + std::vector > _vertices; + std::vector > _texCoords; + std::vector _normals; + + std::map, std::size_t > _vertex_tc_pairs_map; + std::vector > _vertex_tc_pairs; + std::vector > _faces; + +public: + ObjectParser() { + } + + ~ObjectParser() { + } + + void parse(std::string const& filename) + { + obj::obj_parser obj_parser(obj::obj_parser::triangulate_faces | obj::obj_parser::translate_negative_indices); + obj_parser.geometric_vertex_callback(std::tr1::bind(&ObjectParser::geometric_vertex_callback, this, _1, _2, _3)); + obj_parser.texture_vertex_callback(std::tr1::bind(&ObjectParser::texture_vertex_callback, this, _1, _2)); + obj_parser.vertex_normal_callback(std::tr1::bind(&ObjectParser::vertex_normal_callback, this, _1, _2, _3)); + obj_parser.face_callbacks + (std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_texture_vertices_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_vertex_normals_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_texture_vertices_vertex_normals_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_callback, this, _1, _2, _3, _4), + std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_texture_vertices_callback, this, _1, _2, _3, _4), + std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_vertex_normals_callback, this, _1, _2, _3, _4), + std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_texture_vertices_vertex_normals_callback, this, _1, _2, _3, _4), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_begin_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_callback, this, _1), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_end_callback, this), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_begin_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_callback, this, _1), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_end_callback, this), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_begin_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_vertex_callback, this, _1), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_end_callback, this), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_begin_callback, this, _1, _2, _3), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_vertex_callback, this, _1), + std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_end_callback, this)); + obj_parser.parse(filename); + } + + std::vector buildVA() + { + std::vector ret; + for (auto const& ent : _vertex_tc_pairs) { + objVertexAttribs tmp; + tmp.vertex[0] = std::get<0>(ent); + tmp.vertex[1] = std::get<1>(ent); + tmp.vertex[2] = std::get<2>(ent); + tmp.texCoords[0] = std::get<3>(ent); + tmp.texCoords[1] = std::get<4>(ent); + ret.push_back(tmp); + } + return ret; + } + + std::vector buildIndices() const + { + std::vector ret; + for (auto const& ent : _faces) { + ret.push_back(std::get<0>(ent)); + ret.push_back(std::get<1>(ent)); + ret.push_back(std::get<2>(ent)); + } + return ret; + } +}; + +std::tuple, std::vector > readObject(std::string const& filename) +{ + ObjectParser parser; + parser.parse(filename); + return std::tuple, std::vector >(parser.buildVA(), parser.buildIndices()); +} diff --git a/objectParser.hh b/objectParser.hh new file mode 100644 index 0000000..4e46de0 --- /dev/null +++ b/objectParser.hh @@ -0,0 +1,34 @@ +#ifndef __OPENGLPLAYGROUND_OBJECTPARSER_HH__ +#define __OPENGLPLAYGROUND_OBJECTPARSER_HH__ + +#include +#include + +#include "common.hh" + +class ParseException : public Exception { +public: + ParseException(std::string const& msg) : Exception(), _msg(msg) { + } + + virtual ~ParseException() {} + + std::string const& getMsg() const {return _msg;} + + virtual std::string toString() const { + return "ParseException: " + _msg; + } + +private: + std::string _msg; +}; + +struct objVertexAttribs { + float vertex[3]; + uint16_t texCoords[2]; +} __attribute__((__packed__)); + + +std::tuple, std::vector > readObject(std::string const& filename); + +#endif diff --git a/objects/woodbox.obj b/objects/woodbox.obj new file mode 100644 index 0000000..8086aaf --- /dev/null +++ b/objects/woodbox.obj @@ -0,0 +1,33 @@ +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 0.0 1.0 0.0 +v 1.0 1.0 0.0 + +v 0.0 0.0 -1.0 +v 1.0 0.0 -1.0 +v 0.0 1.0 -1.0 +v 1.0 1.0 -1.0 + +vt 0.0 0.0 +vt 1.0 0.0 +vt 0.0 1.0 +vt 1.0 1.0 + +vn 0.0 0.0 1.0 +vn 1.0 0.0 0.0 +vn 0.0 0.0 -1.0 +vn -1.0 0.0 0.0 +vn 0.0 1.0 0.0 +vn 0.0 -1.0 0.0 + +f 1/1 3/3 4/4 2/2 + +f 2/1 4/3 8/4 6/2 + +f 6/1 8/3 7/4 5/2 + +f 5/1 7/3 3/4 1/2 + +f 5/1 1/3 2/4 6/2 + +f 3/1 7/3 8/4 4/2 diff --git a/shaders.hh b/shaders.hh new file mode 100644 index 0000000..1dbebec --- /dev/null +++ b/shaders.hh @@ -0,0 +1,205 @@ +#ifndef __OPENGLPLAYGROUND_SHADERS_HH__ +#define __OPENGLPLAYGROUND_SHADERS_HH__ + +#include +#include + +#define GL_GLEXT_PROTOTYPES +#include + +#include "common.hh" + +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 { + auto search = _uniformLocCache.find(name); + if (search != _uniformLocCache.end()) + return search->second; + + int ret = glGetUniformLocation(_progID, name.c_str()); + if (ret == -1) + throw GLException(glGetError()); + _uniformLocCache.emplace(name, ret); + return ret; + } + + int getAttribLocation(std::string const& name) const { + auto search = _attribLocCache.find(name); + if (search != _attribLocCache.end()) + return search->second; + + int ret = glGetAttribLocation(_progID, name.c_str()); + if (ret == -1) + throw GLException(glGetError()); + _attribLocCache.emplace(name, ret); + return ret; + } + +private: + GeometryShader* _geom; + VertexShader& _vertex; + FragmentShader& _frag; + unsigned _progID; + + mutable std::unordered_map _uniformLocCache, _attribLocCache; +}; + +#endif diff --git a/shaders/color.fs b/shaders/color.fs new file mode 100644 index 0000000..e96466d --- /dev/null +++ b/shaders/color.fs @@ -0,0 +1,9 @@ +#version 330 core + +in vec3 fragColor; + +out vec4 color; + +void main(void) { + color = vec4(fragColor, 1.0); +} diff --git a/shaders/color.vs b/shaders/color.vs new file mode 100644 index 0000000..f34a49e --- /dev/null +++ b/shaders/color.vs @@ -0,0 +1,14 @@ +#version 330 core + +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; + +in vec3 vertex; +in vec3 vertecColor; + +out vec3 fragColor; + +void main(void) { + gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0); + fragColor = vertexColor; +} diff --git a/shaders/textured.fs b/shaders/textured.fs new file mode 100644 index 0000000..5dc5bcb --- /dev/null +++ b/shaders/textured.fs @@ -0,0 +1,11 @@ +#version 330 core + +uniform sampler2D texBase; + +in vec2 fragTC; + +out vec4 color; + +void main(void) { + color = texture(texBase, fragTC); +} diff --git a/shaders/textured.vs b/shaders/textured.vs new file mode 100644 index 0000000..6c2fec4 --- /dev/null +++ b/shaders/textured.vs @@ -0,0 +1,14 @@ +#version 330 core + +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; + +in vec3 vertex; +in vec2 vertexTC; + +out vec2 fragTC; + +void main(void) { + gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0); + fragTC = vertexTC; +} diff --git a/texture.hh b/texture.hh new file mode 100644 index 0000000..fdf2535 --- /dev/null +++ b/texture.hh @@ -0,0 +1,95 @@ +#ifndef __OPENGLPLAYGROUND_TEXTURE_HH__ +#define __OPENGLPLAYGROUND_TEXTURE_HH__ + +#include +#include +#include +#include + +#include +#include + +#define GL_GLEXT_PROTOTYPES +#include + +#include "common.hh" + +static unsigned ilog2(unsigned in) +{ + unsigned ret = 0u; + while (in >>= 1) ++ret; + return ret; +} + +class Texture2D { +public: + Texture2D(unsigned width, unsigned height) { + _glCreate(width, height); + } + + Texture2D(std::string const& file) { + SDL_Surface *surf = IMG_Load(file.c_str()); + if (!surf) + throw SDLException(); + + try { + _glCreate(surf->w, surf->h); + try { + assert(surf->format->format == SDL_PIXELFORMAT_RGB24); // TODO: Proper support of many formats + if (SDL_MUSTLOCK(surf)) + SDL_LockSurface(surf); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels); + glGenerateMipmap(GL_TEXTURE_2D); + checkGlError(); + } catch(...) { + glDeleteTextures(1, &_texID); + throw; + } + } + catch(...) { + SDL_FreeSurface(surf); + throw; + } + SDL_FreeSurface(surf); + } + + ~Texture2D() { + glDeleteTextures(1, &_texID); + } + + void bind() { + glBindTexture(GL_TEXTURE_2D, _texID); + checkGlError(); + } + +private: + + void _glCreate(unsigned width, unsigned height) { + glGenTextures(1, &_texID); + checkGlError(); + try { + glBindTexture(GL_TEXTURE_2D, _texID); + unsigned logWidth = ilog2(width), logHeight = ilog2(height); + unsigned levels = std::max(logWidth,logHeight)+1u; + if(SDL_GL_ExtensionSupported("GL_ARB_texture_storage")) + glTexStorage2D(GL_TEXTURE_2D, levels, GL_RGB8, width, height); + else { + std::printf("Warning: extension GL_ARB_texture_storage not supported!\n"); + for (unsigned i = 0u; i < levels; ++i) + { + glTexImage2D(GL_TEXTURE_2D, i, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + width = std::max(1u, (width / 2u)); + height = std::max(1u, (height / 2u)); + } + } + checkGlError(); + } catch(...) { + glDeleteTextures(1, &_texID); + } + } + + GLuint _texID; +}; + + +#endif diff --git a/textures/Wood_Box_Texture.jpg b/textures/Wood_Box_Texture.jpg new file mode 100644 index 0000000..d4ba40d Binary files /dev/null and b/textures/Wood_Box_Texture.jpg differ diff --git a/textures/Wood_Box_Texture_NRM.png b/textures/Wood_Box_Texture_NRM.png new file mode 100644 index 0000000..631e29c Binary files /dev/null and b/textures/Wood_Box_Texture_NRM.png differ