diff --git a/Makefile b/Makefile index 559ff6c..83f2215 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CXX=g++ CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -std=c++11 LDOPTS=-flto -LIBS=-lGL -lSDL2 -lSDL2_image -lobj +LIBS=-lglbinding -lSDL2 -lSDL2_image -lobj CXXSRCS=main.cc objectParser.cc OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o)) diff --git a/Object.hh b/Object.hh new file mode 100644 index 0000000..e40bbf8 --- /dev/null +++ b/Object.hh @@ -0,0 +1,70 @@ +#ifndef __OPENGLPLAYGROUND_OBJECT_HH__ +#define __OPENGLPLAYGROUND_OBJECT_HH__ + +#include + +#include "objectParser.hh" +#include "VBOManager.hh" + +class Object { +public: + Object(VBOManager& vboManager, std::vector const& vas, std::vector const& indices, + Program& prog) + : _vboManager(vboManager), _prog(prog), _indices(indices) { + construct(vas); + } + + Object(VBOManager& vboManager, std::string const& filename, Program& prog) + : _vboManager(vboManager), _prog(prog) { + auto tmp = readObject(filename); + _indices = std::get<1>(tmp); + construct(std::get<0>(tmp)); + } + + ~Object() { + } + + void draw(glm::mat4 const& modelview) const { + glBindVertexArray(_vaID); + _prog.use(); + glUniformMatrix4fv(_prog.getUniformLocation("model_matrix"), 1, GL_FALSE, + glm::value_ptr(modelview)); + glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_SHORT, _indices.data()); + } + +private: + void construct(std::vector const& vas) { + _vbo = _vboManager.alloc(sizeof(objVertexAttribs)*vas.size()); + glBindBuffer(GL_ARRAY_BUFFER, _vbo.getVBOId()); + glBufferSubData(GL_ARRAY_BUFFER, _vbo.getOfs(), sizeof(objVertexAttribs)*vas.size(), + (void*)vas.data()); + + glGenVertexArrays(1, &_vaID); + glBindVertexArray(_vaID); + + GLint al; + if((al = _prog.getAttribLocation("vertex")) != -1) { + glEnableVertexAttribArray(al); + glVertexAttribPointer(al, 3, GL_FLOAT, GL_FALSE, sizeof(objVertexAttribs), + (void*)(_vbo.getOfs()+offsetof(objVertexAttribs, vertex))); + } + if((al = _prog.getAttribLocation("vertexTC")) != -1) { + glEnableVertexAttribArray(al); + glVertexAttribPointer(al, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(objVertexAttribs), + (void*)(_vbo.getOfs()+offsetof(objVertexAttribs, texCoords))); + } + if((al = _prog.getAttribLocation("vertexNorm")) != -1) { + glEnableVertexAttribArray(al); + glVertexAttribPointer(al, 4, GL_INT_2_10_10_10_REV, GL_TRUE, sizeof(objVertexAttribs), + (void*)(_vbo.getOfs()+offsetof(objVertexAttribs, normal))); + } + } + + VBOManager& _vboManager; + VBOManager::VBOAlloc _vbo; + Program& _prog; + std::vector _indices; + GLuint _vaID; +}; + +#endif diff --git a/VBOManager.hh b/VBOManager.hh new file mode 100644 index 0000000..feedfb1 --- /dev/null +++ b/VBOManager.hh @@ -0,0 +1,181 @@ +#ifndef __OPENGLPLAYGROUND_VBOMANAGER_HH__ +#define __OPENGLPLAYGROUND_VBOMANAGER_HH__ + +#include +#include +#include +#include + +#include + +using namespace gl; + +class VBOManager { +public: + VBOManager() { + } + + ~VBOManager() { + } + +private: + + class VBO; + + static const size_t default_size = 1048576; + static const size_t alignment = 8; + + class AllocFailed {}; + +public: + class VBOAlloc { + public: + ~VBOAlloc() { + if(_vbo) + _vbo->free(*this); + _vbo = nullptr; + } + + VBOAlloc(VBOAlloc&& move) : _vbo(move._vbo), _ofs(move._ofs), _size(move._size) { + move._vbo = nullptr; + } + + VBOAlloc& operator=(VBOAlloc&& move) { + _vbo = move._vbo; + _ofs = move._ofs; + _size = move._size; + move._vbo = nullptr; + return *this; + } + + VBOAlloc() : _vbo(nullptr), _ofs(0), _size(0) { + } + + size_t getOfs() const { + assert(_vbo); + return _ofs; + } + + size_t getSize() const { + assert(_vbo); + return _size; + } + + GLuint getVBOId() const { + assert(_vbo); + return _vbo->getID(); + } + + private: + VBOAlloc(VBO &vbo, size_t ofs, size_t size) : _vbo(&vbo), _ofs(ofs), _size(size) { + } + + friend class VBOManager; + friend class VBO; + + VBO *_vbo; + size_t _ofs, _size; + }; + + VBOAlloc alloc(size_t size, GLenum type = GL_STATIC_DRAW) { + for(auto& vbo : _vbos[type]) { + try { + return vbo.alloc(size); + } catch (AllocFailed &ex) { + continue; + } + } + + _vbos[type].emplace_back((size>default_size)?size:default_size, type); + + return _vbos[type].back().alloc(size); + } + +private: + + class VBO { + public: + VBO(size_t size = default_size, GLenum type = GL_STATIC_DRAW) : _bufID(0) { + glGenBuffers(1, &_bufID); + glBindBuffer(GL_ARRAY_BUFFER, _bufID); + glBufferData(GL_ARRAY_BUFFER, size, NULL, type); + _allocs.emplace_back(_Entry{size, false}); + } + + VBO(VBO const& copy) = delete; + + VBO(VBO&& move) : _bufID(move._bufID), _allocs(move._allocs) { + move._bufID = 0; + } + + ~VBO() { + for (auto ent : _allocs) { + assert(!ent.used); + } + if (_bufID) + glDeleteBuffers(1, &_bufID); + _bufID = 0; + } + + VBOAlloc alloc(size_t size) { + if (size%alignment != 0) + size += (alignment - (size%alignment)); + + size_t pos = 0; + for (auto it = _allocs.begin();it != _allocs.end();++it) { + if (!it->used && (it->size >= size)) { + size_t leftover = it->size - size; + it->used = true; + it->size = size; + if (leftover > 0) + _allocs.insert(++it, _Entry{leftover, false}); + printf("DEBUG: VBO: Allocated %lu @ %lu in %u\n", size, pos, _bufID); + return VBOAlloc(*this, pos, size); + } + pos += it->size; + } + + throw AllocFailed(); + } + + void free(VBOAlloc& alloc) { + size_t pos = 0; + for (auto it = _allocs.begin();it != _allocs.end();++it) { + if (pos == alloc._ofs) { + assert(it->size == alloc._size); + printf("DEBUG: VBO: Freed %lu @ %lu in %u\n", alloc._size, pos, _bufID); + it->used = false; + if ((std::next(it) != _allocs.end()) && + !std::next(it)->used) { + it->size += std::next(it)->size; + _allocs.erase(std::next(it)); + } + if ((it != _allocs.begin()) && + !std::prev(it)->used) { + it->size += std::prev(it)->size; + _allocs.erase(std::prev(it)); + } + } + pos += it->size; + } + } + + GLuint getID() const { + return _bufID; + } + + private: + GLuint _bufID; + + struct _Entry { + size_t size; + bool used; + }; + std::list<_Entry> _allocs; + + }; + + std::map > _vbos; +}; + +#endif diff --git a/common.hh b/common.hh index cbadf60..f2df923 100644 --- a/common.hh +++ b/common.hh @@ -6,11 +6,12 @@ #include #include -#define GL_GLEXT_PROTOTYPES -#include +#include #include +using namespace gl; + class Exception { public: Exception() { @@ -68,7 +69,7 @@ public: } virtual std::string toString() const { - return "GLException: " + errToString() + "(" + std::to_string(_err) + ")"; + return "GLException: " + errToString() + "(" + std::to_string(static_cast(_err)) + ")"; } private: @@ -118,4 +119,11 @@ static std::string fileToString(std::string const& name) { return ret; } +enum class VAFormats { + Vertex, + VertexTexcoord, + VertexNormal, + VertexNormalTexcoord + }; + #endif diff --git a/main.cc b/main.cc index 8ab0c3c..a4b8166 100644 --- a/main.cc +++ b/main.cc @@ -5,8 +5,9 @@ #include #include -#define GL_GLEXT_PROTOTYPES -#include +#include +#include +#include #define GLM_FORCE_RADIANS #include @@ -17,13 +18,28 @@ #include "common.hh" #include "shaders.hh" #include "texture.hh" +#include "VBOManager.hh" #include "objectParser.hh" +#include "Object.hh" + +using namespace gl; + +void glAfterCallback(glbinding::FunctionCall const& fc) +{ + glbinding::setCallbackMask(glbinding::CallbackMask::None); + GLenum error = glGetError(); + glbinding::setCallbackMask(glbinding::CallbackMask::After); + if (error != GL_NO_ERROR) + throw GLException(error); +} int main(int argc, char *argv[]) { SDL_Window *window; int retcode = 0; + glbinding::Binding::initialize(); + if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::printf("Could not init SDL: %s\n", SDL_GetError()); return 1; @@ -49,7 +65,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()); @@ -64,9 +80,13 @@ int main(int argc, char *argv[]) SDL_Quit(); return 1; } - + + // Clear GL errors + while(glGetError() != GL_NO_ERROR); + try { - while(glGetError() != GL_NO_ERROR); + glbinding::setCallbackMask(glbinding::CallbackMask::After); + glbinding::setAfterCallback(glAfterCallback); { int depth, stencil, aa, major, minor; @@ -84,8 +104,8 @@ int main(int argc, char *argv[]) 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::mat4 view = glm::lookAt(glm::vec3(2.0f, 2.0f, 10), + glm::vec3(0.0f, 0.0f, 0), glm::vec3(0, 1, 0)); // sf::Font font; // if (!font.loadFromFile("DejaVuSans.ttf")) { @@ -101,55 +121,33 @@ int main(int argc, char *argv[]) // sf::Clock clock; // sf::Time last = clock.getElapsedTime(); + VBOManager vboManager; + Texture2D cubeTex("textures/Wood_Box_Texture.jpg"); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast(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"); + Texture2D redTex("textures/red.png"); + Texture2D whiteTex("textures/white.png"); 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)); + glUniformMatrix4fv(prog.getUniformLocation("view_matrix"), 1, GL_FALSE, + glm::value_ptr(view)); glUniform1i(prog.getUniformLocation("texBase"), 0); - - int vertexAL = prog.getAttribLocation("vertex"); - int vertexTCAL = prog.getAttribLocation("vertexTC"); - - checkGlError(); - GLuint buf; - glGenBuffers(1, &buf); - glBindBuffer(GL_ARRAY_BUFFER, buf); - checkGlError(); - - glBufferData(GL_ARRAY_BUFFER, sizeof(objVertexAttribs)*std::get<0>(box).size(), NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(objVertexAttribs)*std::get<0>(box).size(), - (void*)std::get<0>(box).data()); - - GLuint arr[2]; - glGenVertexArrays(2, arr); - checkGlError(); - - glBindVertexArray(arr[0]); - glEnableVertexAttribArray(vertexAL); - glEnableVertexAttribArray(vertexTCAL); - glVertexAttribPointer(vertexAL, 3, GL_FLOAT, GL_FALSE, sizeof(objVertexAttribs), - (void*)offsetof(objVertexAttribs, vertex)); - glVertexAttribPointer(vertexTCAL, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(objVertexAttribs), - (void*)offsetof(objVertexAttribs, texCoords)); - checkGlError(); + Object box(vboManager, "objects/woodbox.obj", prog); + Object pyramid(vboManager, "objects/pyramid.obj", prog); + Object plane(vboManager, "objects/plane.obj", prog); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glEnable(GL_DEPTH_TEST); - checkGlError(); bool close = false; @@ -169,15 +167,19 @@ int main(int argc, char *argv[]) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); - checkGlError(); + glEnable(GL_CULL_FACE); + + glm::mat4 model = glm::translate(glm::vec3(0.5f, 0.5f, -0.5f)) * + glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f)) * + glm::translate(glm::vec3(-0.5f, -0.5f, 0.5f)); + cubeTex.bind(); + box.draw(model); + whiteTex.bind(); + plane.draw(glm::translate(glm::vec3(2.0f, -2.5f, 0.0f))* + glm::rotate(0.35f, glm::vec3(0.0f, 1.0f, 0.0f))); + redTex.bind(); + pyramid.draw(glm::translate(glm::vec3(-2.0f, 0.0f, 0.0f))); - 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, std::get<1>(box).size(), GL_UNSIGNED_SHORT, std::get<1>(box).data()); - checkGlError(); - // glUseProgram(0); // sf::Time now = clock.getElapsedTime(); // sf::Time elapsed = now - last; diff --git a/objectParser.cc b/objectParser.cc index 82415ef..494f9a5 100644 --- a/objectParser.cc +++ b/objectParser.cc @@ -5,6 +5,9 @@ #include #include #include +#define GLM_FORCE_RADIANS +#include +#include #include "objectParser.hh" @@ -20,68 +23,134 @@ class ObjectParser { private: void texture_vertex_callback(obj::float_type u, obj::float_type v) { + assert(!_addedGenerated); 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); + uint16_t c_u = glm::packUnorm1x16(u); 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); + uint16_t c_v = glm::packUnorm1x16(v); + _texCoords.emplace_back(glm::u16vec2(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); + _vertices.emplace_back(glm::vec3(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) { + assert(!_addedGenerated); union { struct { - signed :2; - signed z:10; - signed y:10; signed x:10; + signed y:10; + signed z:10; + // 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); + pack_10.all = glm::packSnorm3x10_1x2(glm::vec4(x, y, z, 0.0f)); _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_norm(size_t vert, size_t tc, size_t norm) { - } - - 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))); + auto pair_it = _vertex_tc_norm_map.find(std::tuple(vert, tc, norm)); size_t pair_pos; - if (pair_it != _vertex_tc_pairs_map.end()) + if (pair_it != _vertex_tc_norm_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)), + _vertex_tc_norm.emplace_back(_vertices[vert], + _texCoords[tc], + _normals[norm]); + pair_pos = _vertex_tc_norm.size()-1; + _vertex_tc_norm_map.emplace(std::tuple(vert, tc, norm), pair_pos); } return pair_pos; } + + glm::vec3 _calculateNormal(glm::vec3 const& a, glm::vec3 const& b, glm::vec3 const& c) + { + return glm::normalize(glm::cross(b-a, c-a)); + } + + size_t _generateNormal(glm::vec3 const& a, glm::vec3 const& b, glm::vec3 const& c) + { + glm::vec3 normal = _calculateNormal(a, b, c); + uint32_t norm32 = glm::packSnorm3x10_1x2(glm::vec4(normal, 0.0f)); + + size_t pos = 0; + for(auto& ent : _normals) { + if (ent == norm32) + return pos; + ++pos; + } + + _addedGenerated = true; + _normals.push_back(norm32); + return _normals.size()-1; + } + + size_t _generateTC() + { + glm::u16vec2 tc(0, 0); + + size_t pos = 0; + for(auto& ent : _texCoords) { + if (ent == tc) + return pos; + ++pos; + } + + _addedGenerated = true; + _texCoords.push_back(tc); + return _texCoords.size()-1; + } + + + void triangular_face_geometric_vertices_callback(index_type a, index_type b, index_type c) + { + if ((_vertices.size() < a) || + (_vertices.size() < b) || + (_vertices.size() < c)) + throw ParseException("Vertex Index out of range"); + + size_t norm = _generateNormal(_vertices[a-1], + _vertices[b-1], + _vertices[c-1]); + size_t tc = _generateTC(); + + std::cout << "f (" << a << ", " << tc << ", " << norm << ")" << + " (" << b << ", " << tc << ", " << norm << ")" << + " (" << c << ", " << tc << ", " << norm << ")\n"; + + size_t a_pos = _find_vertex_tc_norm(a-1, + tc, + norm); + size_t b_pos = _find_vertex_tc_norm(b-1, + tc, + norm); + size_t c_pos = _find_vertex_tc_norm(c-1, + tc, + norm); + _faces.emplace_back(a_pos, b_pos, c_pos); + + std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n"; + } void triangular_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c) { @@ -93,14 +162,24 @@ private: (_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 norm = _generateNormal(_vertices[std::tr1::get<0>(a)-1], + _vertices[std::tr1::get<0>(b)-1], + _vertices[std::tr1::get<0>(c)-1]); - 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); + std::cout << "f (" << std::tr1::get<0>(a) << ", " << std::tr1::get<1>(a) << ", " << norm << ")" << + " (" << std::tr1::get<0>(b) << ", " << std::tr1::get<1>(b) << ", " << norm << ")" << + " (" << std::tr1::get<0>(c) << ", " << std::tr1::get<1>(c) << ", " << norm << ")\n"; + + size_t a_pos = _find_vertex_tc_norm(std::tr1::get<0>(a)-1, + std::tr1::get<1>(a)-1, + norm); + size_t b_pos = _find_vertex_tc_norm(std::tr1::get<0>(b)-1, + std::tr1::get<1>(b)-1, + norm); + size_t c_pos = _find_vertex_tc_norm(std::tr1::get<0>(c)-1, + std::tr1::get<1>(c)-1, + norm); _faces.emplace_back(a_pos, b_pos, c_pos); std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n"; @@ -108,11 +187,67 @@ private: void triangular_face_geometric_vertices_vertex_normals_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 ((_normals.size() < std::tr1::get<1>(a)) || + (_normals.size() < std::tr1::get<1>(b)) || + (_normals.size() < std::tr1::get<1>(c))) + throw ParseException("Normal Index out of range"); + + size_t tc = _generateTC(); + + std::cout << "f (" << std::tr1::get<0>(a) << ", " << tc << ", " << std::tr1::get<1>(a) << ")" << + " (" << std::tr1::get<0>(b) << ", " << tc << "," << std::tr1::get<1>(b) << ")" << + " (" << std::tr1::get<0>(c) << ", " << tc << ", " << std::tr1::get<1>(c) << ")\n"; + + size_t a_pos = _find_vertex_tc_norm(std::tr1::get<0>(a)-1, + tc, + std::tr1::get<1>(a)-1); + size_t b_pos = _find_vertex_tc_norm(std::tr1::get<0>(b)-1, + tc, + std::tr1::get<1>(b)-1); + size_t c_pos = _find_vertex_tc_norm(std::tr1::get<0>(c)-1, + tc, + std::tr1::get<1>(c)-1); + _faces.emplace_back(a_pos, b_pos, c_pos); + + std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n"; } 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) { + 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"); + if ((_normals.size() < std::tr1::get<2>(a)) || + (_normals.size() < std::tr1::get<2>(b)) || + (_normals.size() < std::tr1::get<2>(c))) + throw ParseException("Normal Index out of range"); + + std::cout << "f (" << std::tr1::get<0>(a) << ", " << std::tr1::get<1>(a) << ", " << std::tr1::get<2>(a) << ")" << + " (" << std::tr1::get<0>(b) << ", " << std::tr1::get<1>(b) << ", " << std::tr1::get<2>(b) << ")" << + " (" << std::tr1::get<0>(c) << ", " << std::tr1::get<1>(c) << ", " << std::tr1::get<2>(c) << ")\n"; + + size_t a_pos = _find_vertex_tc_norm(std::tr1::get<0>(a)-1, + std::tr1::get<1>(a)-1, + std::tr1::get<2>(a)-1); + size_t b_pos = _find_vertex_tc_norm(std::tr1::get<0>(b)-1, + std::tr1::get<1>(b)-1, + std::tr1::get<2>(b)-1); + size_t c_pos = _find_vertex_tc_norm(std::tr1::get<0>(c)-1, + std::tr1::get<1>(c)-1, + std::tr1::get<2>(c)-1); + _faces.emplace_back(a_pos, b_pos, c_pos); + + std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n"; } void quadrilateral_face_geometric_vertices_callback(index_type a, index_type b, index_type c, index_type d) @@ -201,16 +336,19 @@ private: assert(false); } - std::vector > _vertices; - std::vector > _texCoords; + bool _addedGenerated; + + std::vector _vertices; + std::vector _texCoords; std::vector _normals; - std::map, std::size_t > _vertex_tc_pairs_map; - std::vector > _vertex_tc_pairs; + std::map, std::size_t > _vertex_tc_norm_map; + std::vector > _vertex_tc_norm; + std::vector > _faces; public: - ObjectParser() { + ObjectParser() : _addedGenerated(false) { } ~ObjectParser() { @@ -249,13 +387,14 @@ public: std::vector buildVA() { std::vector ret; - for (auto const& ent : _vertex_tc_pairs) { + for (auto const& ent : _vertex_tc_norm) { 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); + tmp.vertex[0] = std::get<0>(ent).x; + tmp.vertex[1] = std::get<0>(ent).y; + tmp.vertex[2] = std::get<0>(ent).z; + tmp.texCoords[0] = std::get<1>(ent).x; + tmp.texCoords[1] = std::get<1>(ent).y; + tmp.normal = std::get<2>(ent); ret.push_back(tmp); } return ret; diff --git a/objectParser.hh b/objectParser.hh index 4e46de0..2579240 100644 --- a/objectParser.hh +++ b/objectParser.hh @@ -26,6 +26,7 @@ private: struct objVertexAttribs { float vertex[3]; uint16_t texCoords[2]; + uint32_t normal; } __attribute__((__packed__)); diff --git a/objects/plane.obj b/objects/plane.obj new file mode 100644 index 0000000..cfe297f --- /dev/null +++ b/objects/plane.obj @@ -0,0 +1,11 @@ +v 0.0 0.0 0.0 +v 0.0 5.0 0.0 +v 0.0 0.0 -50.0 +v 0.0 5.0 -50.0 + +vt 0.0 0.0 +vt 1.0 0.0 +vt 0.0 1.0 +vt 1.0 1.0 + +f 1/1 2/3 4/4 3/2 \ No newline at end of file diff --git a/objects/pyramid.obj b/objects/pyramid.obj new file mode 100644 index 0000000..21f71f5 --- /dev/null +++ b/objects/pyramid.obj @@ -0,0 +1,17 @@ +v 0.0 0.0 0.0 +v 0.5 1.0 0.5 +v -0.5 1.0 0.5 +v 0.0 1.0 -0.707 + +#vt 0.0 0.0 +#vt 1.0 0.0 +#vt 0.0 1.0 +#vt 1.0 1.0 + +#f 1/1 2/2 3/3 +#f 1/1 3/2 4/3 +#f 1/1 4/2 2/3 + +f 1 2 3 +f 1 3 4 +f 1 4 2 \ No newline at end of file diff --git a/objects/woodbox.obj b/objects/woodbox.obj index 8086aaf..64cbf1d 100644 --- a/objects/woodbox.obj +++ b/objects/woodbox.obj @@ -13,21 +13,9 @@ 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 +f 2/1 4/3 3/4 1/2 +f 1/1 3/3 7/4 5/2 +f 5/1 7/3 8/4 6/2 +f 6/1 8/3 4/4 2/2 +f 6/1 2/3 1/4 5/2 +f 4/1 8/3 7/4 3/2 diff --git a/shaders.hh b/shaders.hh index 1dbebec..7e14ccd 100644 --- a/shaders.hh +++ b/shaders.hh @@ -4,11 +4,12 @@ #include #include -#define GL_GLEXT_PROTOTYPES -#include +#include #include "common.hh" +using namespace gl; + class ShaderException : public GLException { public: ShaderException(std::string const& msg) : GLException(glGetError()), _msg(msg) { @@ -169,27 +170,25 @@ public: glUseProgram(_progID); } - int getUniformLocation(std::string const& name) const { + GLint 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); + GLint ret = glGetUniformLocation(_progID, name.c_str()); + if (ret != -1) + _uniformLocCache.emplace(name, ret); return ret; } - int getAttribLocation(std::string const& name) const { + GLint 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); + GLint ret = glGetAttribLocation(_progID, name.c_str()); + if (ret != -1) + _attribLocCache.emplace(name, ret); return ret; } diff --git a/shaders/textured.fs b/shaders/textured.fs index 5dc5bcb..c5eed25 100644 --- a/shaders/textured.fs +++ b/shaders/textured.fs @@ -3,9 +3,14 @@ uniform sampler2D texBase; in vec2 fragTC; +//in vec3 fragNorm; +//in vec3 light0Vect; +in vec3 light; out vec4 color; void main(void) { - color = texture(texBase, fragTC); + vec4 texColor = texture(texBase, fragTC); + + color = texColor*vec4(light, 1.0)+texColor*0.05; } diff --git a/shaders/textured.vs b/shaders/textured.vs index 6c2fec4..c176fae 100644 --- a/shaders/textured.vs +++ b/shaders/textured.vs @@ -1,14 +1,39 @@ #version 330 core +#extension GL_ARB_shading_language_420pack : enable uniform mat4 projection_matrix; -uniform mat4 modelview_matrix; +uniform mat4 view_matrix; +uniform mat4 model_matrix; -in vec3 vertex; -in vec2 vertexTC; +const uint lights = 2u; + +const vec3 lightPos[lights] = {vec3(2.0, -2.0, 10.0), + vec3(2.0, 2.0, 10.0)}; +const vec3 lightColor[lights] = {vec3(1.0, 0.9, 0.8), + vec3(0.0, 1.0, 0.0)}; +const float lightIntensity[lights] = {75.0, 25.0}; + + +layout(location = 0) in vec3 vertex; +layout(location = 1) in vec2 vertexTC; +layout(location = 2) in vec3 vertexNorm; out vec2 fragTC; +out vec3 light; void main(void) { - gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0); + vec4 vertex_Pos = model_matrix * vec4(vertex, 1.0); + gl_Position = projection_matrix * view_matrix * vertex_Pos; + fragTC = vertexTC; + + vec3 vertexNorm_trans = (model_matrix*vec4(vertexNorm, 0.0)).xyz; + light = vec3(0.0, 0.0, 0.0); + for (uint i = 0u;i < lights;++i) { + vec3 lightVec = lightPos[i]-vertex_Pos.xyz; + vec3 lightNorm = normalize(lightVec); + float lightDist = length(lightVec); + light += lightColor[i]*clamp(dot(vertexNorm_trans, lightNorm), 0.0, 1.0)* + clamp(lightIntensity[i]/(lightDist*lightDist), 0.0, 1.0); + } } diff --git a/texture.hh b/texture.hh index fdf2535..9c72e93 100644 --- a/texture.hh +++ b/texture.hh @@ -9,11 +9,12 @@ #include #include -#define GL_GLEXT_PROTOTYPES -#include +#include #include "common.hh" +using namespace gl; + static unsigned ilog2(unsigned in) { unsigned ret = 0u; @@ -40,7 +41,6 @@ public: 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; @@ -59,14 +59,12 @@ public: 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); @@ -77,12 +75,11 @@ private: 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); + glTexImage2D(GL_TEXTURE_2D, i, static_cast(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); } diff --git a/textures/red.png b/textures/red.png new file mode 100644 index 0000000..a53a267 Binary files /dev/null and b/textures/red.png differ diff --git a/textures/white.png b/textures/white.png new file mode 100644 index 0000000..394347b Binary files /dev/null and b/textures/white.png differ