diff --git a/DejaVuSans.ttf b/DejaVuSans.ttf new file mode 100644 index 0000000..9d40c32 Binary files /dev/null and b/DejaVuSans.ttf differ diff --git a/Makefile b/Makefile index f81198e..84eed84 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ CXX=g++ -CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -Wno-sign-compare -std=c++11 -flto -LDOPTS=-flto -LIBS=-lglbinding -lSDL2 -lSDL2_image -lobj -CXXSRCS=main.cc objectParser.cc +CXXOPTS=-O2 -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -Wno-sign-compare -std=c++14 -flto +LDOPTS= +LIBS=-lglbinding -lSDL2 -lSDL2_image -lobj -lSDL2_ttf +CXXSRCS=main.cc objectParser.cc shaders.cc Object.cc VBOManager.cc texture.cc font.cc Overlay.cc OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o)) objs/%.o: %.cc diff --git a/Object.cc b/Object.cc new file mode 100644 index 0000000..0b0ec91 --- /dev/null +++ b/Object.cc @@ -0,0 +1,77 @@ +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include +#include + +#include "shaders.hh" +#include "Object.hh" + +using namespace gl; + +Object::Object(VBOManager& vboManager, std::vector const& vas, + std::vector indices, Program& prog) + : _vboManager(vboManager), _prog(prog), _indices(std::move(indices)), _vaID(0) +{ + construct(vas); +} + +Object::Object(VBOManager& vboManager, std::string const& filename, + Program& prog) + : _vboManager(vboManager), _prog(prog), _vaID(0) +{ + auto tmp = readObject(filename); + _indices = std::get<1>(tmp); + construct(std::get<0>(tmp)); +} + +Object::~Object() +{ + glDeleteVertexArrays(1, &_vaID); +} + +void Object::draw(glm::mat4 const& modelview, Program *override) const +{ + glBindVertexArray(_vaID); + if (override) + override->use(); + else + _prog.use(); + glUniformMatrix4fv(_prog.getUniformLocation("model_matrix"), 1, GL_FALSE, + glm::value_ptr(modelview)); + glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_SHORT, + _indices.data()); +} + +void Object::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))); + } +} diff --git a/Object.hh b/Object.hh index 77c7e4f..c5541d5 100644 --- a/Object.hh +++ b/Object.hh @@ -1,78 +1,37 @@ #ifndef __OPENGLPLAYGROUND_OBJECT_HH__ #define __OPENGLPLAYGROUND_OBJECT_HH__ -#include +#include +#include #include "objectParser.hh" #include "VBOManager.hh" +class Program; + class Object { public: - Object(VBOManager& vboManager, std::vector const& vas, std::vector const& indices, - Program& prog) - : _vboManager(vboManager), _prog(prog), _indices(indices), _vaID(0) { - construct(vas); - } + Object(VBOManager& vboManager, std::vector const& vas, + std::vector indices, Program& prog); - Object(VBOManager& vboManager, std::string const& filename, Program& prog) - : _vboManager(vboManager), _prog(prog), _vaID(0) { - auto tmp = readObject(filename); - _indices = std::get<1>(tmp); - construct(std::get<0>(tmp)); - } + Object(VBOManager& vboManager, std::string const& filename, Program& prog); Object(Object const& copy) = delete; - ~Object() { - glDeleteVertexArrays(1, &_vaID); - } + ~Object(); Object& operator=(Object const& copy) = delete; - void draw(glm::mat4 const& modelview, Program *override = nullptr) const { - glBindVertexArray(_vaID); - if (override) - override->use(); - else - _prog.use(); - glUniformMatrix4fv(_prog.getUniformLocation("model_matrix"), 1, GL_FALSE, - glm::value_ptr(modelview)); - glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_SHORT, _indices.data()); - } + void draw(glm::mat4 const& modelview, Program *override = nullptr) const; 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))); - } - } + void construct(std::vector const& vas); VBOManager& _vboManager; VBOManager::VBOAlloc _vbo; Program& _prog; std::vector _indices; - GLuint _vaID; + gl::GLuint _vaID; }; #endif diff --git a/Overlay.cc b/Overlay.cc new file mode 100644 index 0000000..0ae2bb9 --- /dev/null +++ b/Overlay.cc @@ -0,0 +1,53 @@ +#include +#include + +#include "shaders.hh" +#include "Overlay.hh" + +using namespace gl; + +Overlay::Overlay(VBOManager& vboManager, std::vector const& vas, + Program& prog) + : vboManager_(vboManager), vbo_(vboManager_.alloc(sizeof(ovlVertexAttribs)*vas.size())), + prog_(prog), vaID_(0), vertices_(vas.size()) +{ + glBindBuffer(GL_ARRAY_BUFFER, vbo_.getVBOId()); + glBufferSubData(GL_ARRAY_BUFFER, vbo_.getOfs(), + sizeof(ovlVertexAttribs)*vas.size(), + static_cast(vas.data())); + + glGenVertexArrays(1, &vaID_); + try { + glBindVertexArray(vaID_); + GLint al; + if((al = prog_.getAttribLocation("vertex")) != -1) { + glEnableVertexAttribArray(al); + glVertexAttribPointer(al, 2, GL_SHORT, GL_TRUE, sizeof(ovlVertexAttribs), + (void*)(vbo_.getOfs()+offsetof(ovlVertexAttribs, vertex))); + } + if((al = prog_.getAttribLocation("vertexTC")) != -1) { + glEnableVertexAttribArray(al); + glVertexAttribPointer(al, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(ovlVertexAttribs), + (void*)(vbo_.getOfs()+offsetof(ovlVertexAttribs, texCoords))); + } + } catch(...) { + glDeleteVertexArrays(1, &vaID_); + throw; + } +} + +Overlay::~Overlay() +{ + glDeleteVertexArrays(1, &vaID_); +} + +void Overlay::draw(Program *override) const +{ + glBindVertexArray(vaID_); + if (override) + override->use(); + else + prog_.use(); + glDrawArrays(GL_TRIANGLES, 0, vertices_); +} diff --git a/Overlay.hh b/Overlay.hh new file mode 100644 index 0000000..bd43f8b --- /dev/null +++ b/Overlay.hh @@ -0,0 +1,36 @@ +#ifndef __OPENGLPLAYGROUND_OVERLAY_HH__ +#define __OPENGLPLAYGROUND_OVERLAY_HH__ + +#include +#include + +#include "VBOManager.hh" + +class Program; + +struct ovlVertexAttribs { + uint16_t vertex[2]; + uint16_t texCoords[2]; +} __attribute__((__packed__)); + +class Overlay { +public: + Overlay(VBOManager& vboManager, std::vector const& vas, + Program& prog); + + Overlay(Overlay const& copy) = delete; + Overlay& operator=(Overlay const& copy) = delete; + + ~Overlay(); + + void draw(Program *override = nullptr) const; + +private: + VBOManager& vboManager_; + VBOManager::VBOAlloc vbo_; + Program& prog_; + gl::GLuint vaID_; + size_t vertices_; +}; + +#endif diff --git a/VBOManager.cc b/VBOManager.cc new file mode 100644 index 0000000..a994a83 --- /dev/null +++ b/VBOManager.cc @@ -0,0 +1,145 @@ +#include +#include + +#include "VBOManager.hh" + +using namespace gl; + +VBOManager::VBOManager() +{ +} + +VBOManager::~VBOManager() +{ +} + +VBOManager::VBOAlloc::~VBOAlloc() +{ + if(_vbo) + _vbo->free(*this); + _vbo = nullptr; +} + +VBOManager::VBOAlloc::VBOAlloc(VBOAlloc&& move) + : _vbo(move._vbo), _ofs(move._ofs), _size(move._size) +{ + move._vbo = nullptr; +} + +VBOManager::VBOAlloc& VBOManager::VBOAlloc::operator=(VBOAlloc&& move) +{ + _vbo = move._vbo; + _ofs = move._ofs; + _size = move._size; + move._vbo = nullptr; + return *this; +} + +VBOManager::VBOAlloc::VBOAlloc() + : _vbo(nullptr), _ofs(0), _size(0) +{ +} + +VBOManager::VBOAlloc::VBOAlloc(VBO &vbo, size_t ofs, size_t size) + : _vbo(&vbo), _ofs(ofs), _size(size) +{ +} + +VBOManager::VBOAlloc VBOManager::alloc(size_t size, GLenum type) +{ + 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); +} + +VBOManager::VBO::VBO(size_t size, GLenum type) + : _bufID(0) +{ + glGenBuffers(1, &_bufID); + glBindBuffer(GL_ARRAY_BUFFER, _bufID); + glBufferData(GL_ARRAY_BUFFER, size, NULL, type); + _allocs.emplace_back(_Entry{size, false}); +} + +VBOManager::VBO::VBO(VBO&& move) + : _bufID(move._bufID), _allocs(std::move(move._allocs)) +{ + move._bufID = 0; +} + +VBOManager::VBO& VBOManager::VBO::operator=(VBO&& move) +{ + for (auto ent : _allocs) { + assert(!ent.used); + } + if (_bufID) + glDeleteBuffers(1, &_bufID); + _bufID = move._bufID; + move._bufID = 0; + _allocs = std::move(move._allocs); + + return *this; +} + +VBOManager::VBO::~VBO() +{ + for (auto ent : _allocs) { + assert(!ent.used); + } + if (_bufID) + glDeleteBuffers(1, &_bufID); + _bufID = 0; +} + +VBOManager::VBOAlloc VBOManager::VBO::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 VBOManager::VBO::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; + } +} diff --git a/VBOManager.hh b/VBOManager.hh index da61f8d..6a52703 100644 --- a/VBOManager.hh +++ b/VBOManager.hh @@ -5,18 +5,15 @@ #include #include #include +#include -#include - -using namespace gl; +#include class VBOManager { public: - VBOManager() { - } + VBOManager(); - ~VBOManager() { - } + ~VBOManager(); private: @@ -24,35 +21,23 @@ private: static const size_t default_size = 1048576; static const size_t alignment = 8; + static const gl::GLenum default_type = gl::GL_STATIC_DRAW; class AllocFailed {}; public: class VBOAlloc { public: - ~VBOAlloc() { - if(_vbo) - _vbo->free(*this); - _vbo = nullptr; - } + ~VBOAlloc(); - VBOAlloc(VBOAlloc&& move) : _vbo(move._vbo), _ofs(move._ofs), _size(move._size) { - move._vbo = nullptr; - } + VBOAlloc(VBOAlloc&& move); VBOAlloc(VBOAlloc const& copy) = delete; VBOAlloc& operator=(VBOAlloc const& copy) = delete; - VBOAlloc& operator=(VBOAlloc&& move) { - _vbo = move._vbo; - _ofs = move._ofs; - _size = move._size; - move._vbo = nullptr; - return *this; - } + VBOAlloc& operator=(VBOAlloc&& move); - VBOAlloc() : _vbo(nullptr), _ofs(0), _size(0) { - } + VBOAlloc(); size_t getOfs() const { assert(_vbo); @@ -64,14 +49,13 @@ public: return _size; } - GLuint getVBOId() const { + gl::GLuint getVBOId() const { assert(_vbo); return _vbo->getID(); } private: - VBOAlloc(VBO &vbo, size_t ofs, size_t size) : _vbo(&vbo), _ofs(ofs), _size(size) { - } + VBOAlloc(VBO &vbo, size_t ofs, size_t size); friend class VBOManager; friend class VBO; @@ -80,107 +64,33 @@ public: 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); - } + VBOAlloc alloc(size_t size, gl::GLenum type = default_type); 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(size_t size = default_size, gl::GLenum type = default_type); VBO(VBO const& copy) = delete; VBO& operator=(VBO const& copy) = delete; - VBO(VBO&& move) : _bufID(move._bufID), _allocs(std::move(move._allocs)) { - move._bufID = 0; - } + VBO(VBO&& move); - VBO& operator=(VBO&& move) { - for (auto ent : _allocs) { - assert(!ent.used); - } - if (_bufID) - glDeleteBuffers(1, &_bufID); - _bufID = move._bufID; - move._bufID = 0; - _allocs = std::move(move._allocs); - } + VBO& operator=(VBO&& move); - ~VBO() { - for (auto ent : _allocs) { - assert(!ent.used); - } - if (_bufID) - glDeleteBuffers(1, &_bufID); - _bufID = 0; - } + ~VBO(); - VBOAlloc alloc(size_t size) { - if (size%alignment != 0) - size += (alignment - (size%alignment)); + VBOAlloc alloc(size_t size); - 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; - } + void free(VBOAlloc& alloc); - 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 { + gl::GLuint getID() const { return _bufID; } private: - GLuint _bufID; + gl::GLuint _bufID; struct _Entry { size_t size; @@ -190,7 +100,7 @@ private: }; - std::map > _vbos; + std::map > _vbos; }; #endif diff --git a/common.hh b/common.hh index f2df923..6313e9c 100644 --- a/common.hh +++ b/common.hh @@ -9,6 +9,7 @@ #include #include +#include using namespace gl; @@ -24,71 +25,78 @@ public: class POSIXException : public Exception { public: - POSIXException(int err): Exception(), _err(err) { + POSIXException(int err): Exception(), err_(err) { } - virtual ~POSIXException() {} - - int getErr() const {return _err;} + int getErr() const {return err_;} - virtual std::string toString() const { - return std::string("POSIXException: ") + std::strerror(_err); + std::string toString() const override { + return std::string("POSIXException: ") + std::strerror(err_); } private: - int _err; + int err_; }; class GLException : public Exception { public: - GLException(GLenum err) : Exception(), _err(err) { + GLException(GLenum err) : Exception(), err_(err) { } - - virtual ~GLException() {} - - GLenum getErr() const {return _err;} + + GLenum getErr() const {return err_;} std::string errToString() const { std::string ret; - if (_err == GL_INVALID_ENUM) + if (err_ == GL_INVALID_ENUM) ret += "GL_INVALID_ENUM "; - if (_err == GL_INVALID_VALUE) + if (err_ == GL_INVALID_VALUE) ret += "GL_INVALID_VALUE "; - if (_err == GL_INVALID_OPERATION) + if (err_ == GL_INVALID_OPERATION) ret += "GL_INVALID_OPERATION "; - if (_err == GL_INVALID_FRAMEBUFFER_OPERATION) + if (err_ == GL_INVALID_FRAMEBUFFER_OPERATION) ret += "GL_INVALID_FRAMEBUFFER_OPERATION "; - if (_err == GL_OUT_OF_MEMORY) + if (err_ == GL_OUT_OF_MEMORY) ret += "GL_OUT_OF_MEMORY "; - if (_err == GL_STACK_UNDERFLOW) + if (err_ == GL_STACK_UNDERFLOW) ret += "GL_STACK_UNDERFLOW "; - if (_err == GL_STACK_OVERFLOW) + if (err_ == GL_STACK_OVERFLOW) ret += "GL_STACK_OVERFLOW "; return ret; } - virtual std::string toString() const { - return "GLException: " + errToString() + "(" + std::to_string(static_cast(_err)) + ")"; + std::string toString() const override { + return "GLException: " + errToString() + "(" + std::to_string(static_cast(err_)) + ")"; } private: - GLenum _err; + GLenum err_; }; class SDLException : public Exception { public: - SDLException() : Exception(), _msg(SDL_GetError()) { + SDLException() : Exception(), msg_(SDL_GetError()) { } - virtual ~SDLException() {} - - virtual std::string toString() const { - return "SDLException: " + _msg; + std::string toString() const override { + return "SDLException: " + msg_; } private: - std::string _msg; + std::string msg_; +}; + +class TTFException : public Exception { +public: + TTFException() : Exception(), msg_(TTF_GetError()) { + } + + std::string toString() const override { + return "TTFException: " + msg_; + } + +private: + std::string msg_; }; static void checkGlError() { diff --git a/font.cc b/font.cc new file mode 100644 index 0000000..e85dad8 --- /dev/null +++ b/font.cc @@ -0,0 +1,41 @@ +#include +#include + +#include "common.hh" +#include "texture.hh" +#include "font.hh" + +Font::Font(std::string const& filename, unsigned ptsize) + : font_{nullptr} +{ + assert(TTF_WasInit()); + font_ = TTF_OpenFont(filename.c_str(), ptsize); + if(!font_) + throw TTFException{}; +} + +Font::~Font() +{ + if(font_) + TTF_CloseFont(font_); +} + +Texture2D Font::render(std::string const& text, bool fast) const { + SDL_Surface *surf; + if(fast) + surf = TTF_RenderUTF8_Solid(font_, text.c_str(), SDL_Color{255, 255, 255, 255}); + else + surf = TTF_RenderUTF8_Blended(font_, text.c_str(), SDL_Color{255, 255, 255, 255}); + + if(!surf) + throw TTFException{}; + + try { + Texture2D ret{surf}; + SDL_FreeSurface(surf); + return ret; + } catch(...) { + SDL_FreeSurface(surf); + throw; + } +} diff --git a/font.hh b/font.hh new file mode 100644 index 0000000..319a034 --- /dev/null +++ b/font.hh @@ -0,0 +1,26 @@ +#ifndef __OPENGLPLAYGROUND_FONT_HH__ +#define __OPENGLPLAYGROUND_FONT_HH__ + +#include + +struct _TTF_Font; +typedef struct _TTF_Font TTF_Font; +class Texture2D; + +class Font { +public: + Font(std::string const& filename, unsigned ptsize); + Font(Font const& copy) = delete; + + Font& operator=(Font const& copy) = delete; + + ~Font(); + + Texture2D render(std::string const& text, bool fast = false) const; + +private: + TTF_Font* font_; +}; + + +#endif diff --git a/main.cc b/main.cc index 0cd4140..2418c57 100644 --- a/main.cc +++ b/main.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include "common.hh" #include "shaders.hh" @@ -21,6 +23,8 @@ #include "VBOManager.hh" #include "objectParser.hh" #include "Object.hh" +#include "font.hh" +#include "Overlay.hh" using namespace gl; @@ -50,6 +54,13 @@ int main(int argc, char *argv[]) return 1; } + if(TTF_Init() == -1) { + printf("Could not init SDL_ttf: %s\n", TTF_GetError()); + IMG_Quit(); + SDL_Quit(); + return 1; + } + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); @@ -106,7 +117,10 @@ int main(int argc, char *argv[]) 0.1f, 100.0f); glm::mat4 view = glm::lookAt(glm::vec3(2.0f, 2.0f, 10), glm::vec3(0.0f, 0.0f, 0), - glm::vec3(0, 1, 0)); + glm::vec3(0, 1, 0)); + + Font font{"DejaVuSans.ttf", 12}; + // sf::Font font; // if (!font.loadFromFile("DejaVuSans.ttf")) { // std::printf("Error loading font\n"); @@ -120,7 +134,8 @@ int main(int argc, char *argv[]) // sf::Clock clock; // sf::Time last = clock.getElapsedTime(); - + auto last = SDL_GetTicks(); + VBOManager vboManager; Texture2D cubeTex("textures/Wood_Box_Texture.jpg"); @@ -135,7 +150,8 @@ int main(int argc, char *argv[]) const unsigned lights = 2; const unsigned shadowMapSize = 512; glm::mat4 shadowProj = glm::perspectiveFov(90.0f, static_cast(shadowMapSize), - static_cast(shadowMapSize), 1.0f, 128.0f); + static_cast(shadowMapSize), 1.0f, 128.0f); + //glm::mat4 shadowProj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 128.0f); std::vector shadowMaps; for(unsigned i = 0;i < lights;++i) { shadowMaps.emplace_back(shadowMapSize); @@ -160,6 +176,10 @@ int main(int argc, char *argv[]) FragmentShader shadowFs{fileToString("shaders/shadow.fs")}; Program shadowProg{shadowVs, shadowFs}; + VertexShader ovlVs{fileToString("shaders/overlay.vs")}; + FragmentShader ovlFs{fileToString("shaders/overlay.fs")}; + Program ovlProg{ovlVs, ovlFs}; + prog.use(); glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE, glm::value_ptr(proj)); @@ -171,12 +191,28 @@ int main(int argc, char *argv[]) glUniform1iv(prog.getUniformLocation("texShadowMaps"), 2, shadowMapTUs); shadowProg.use(); - glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE, + glUniformMatrix4fv(shadowProg.getUniformLocation("projection_matrix"), 1, GL_FALSE, glm::value_ptr(shadowProj)); - + + ovlProg.use(); + glUniform1i(ovlProg.getUniformLocation("texBase"), 0); + Object box(vboManager, "objects/woodbox.obj", prog); Object pyramid(vboManager, "objects/pyramid.obj", prog); Object plane(vboManager, "objects/plane.obj", prog); + + float px20_width = 2.0f*(20.0f/width); + float px20_height = 2.0f*(20.0f/height); + + std::vector ovlAttribs{ + {{glm::packSnorm1x16(1.0-px20_width), glm::packSnorm1x16(1.0)}, {0, 0}}, + {{glm::packSnorm1x16(1.0), glm::packSnorm1x16(1.0-px20_height)}, {65535u, 65535u}}, + {{glm::packSnorm1x16(1.0), glm::packSnorm1x16(1.0)}, {65535u, 0}}, + {{glm::packSnorm1x16(1.0-px20_width), glm::packSnorm1x16(1.0)}, {0, 0}}, + {{glm::packSnorm1x16(1.0-px20_width), glm::packSnorm1x16(1.0-px20_height)}, {0, 65535u}}, + {{glm::packSnorm1x16(1.0), glm::packSnorm1x16(1.0-px20_height)}, {65535u, 65535u}}}; + + Overlay ovl{vboManager, ovlAttribs, ovlProg}; glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -288,6 +324,20 @@ int main(int argc, char *argv[]) // fpsText.setPosition({1680-fpsText.getLocalBounds().width, 0}); // window.draw(fpsText); + auto now = SDL_GetTicks(); + auto elapsed = now - last; + last = now; + std::string fpsText = std::to_string(static_cast(1000.0/elapsed)); + auto fpsTex = font.render(fpsText); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + fpsTex.bind(); + //redTex.bind(); + ovl.draw(); + glDisable(GL_BLEND); + SDL_GL_SwapWindow(window); } }catch(Exception &ex) { diff --git a/shaders.cc b/shaders.cc new file mode 100644 index 0000000..8f32c40 --- /dev/null +++ b/shaders.cc @@ -0,0 +1,134 @@ +#include + +#include "shaders.hh" + +using namespace gl; + +ShaderException::ShaderException(std::string const& msg) + : GLException(glGetError()), _msg(msg) +{ +} + +Shader::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 == 0) { + 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); + } +} + +Shader::~Shader() +{ + glDeleteShader(_shaderID); +} + +Program::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 == 0) { + 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::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::~Program() +{ + glDeleteProgram(_progID); +} + +void Program::use() const +{ + glUseProgram(_progID); +} + +GLint Program::getUniformLocation(std::string const& name) const +{ + auto search = _uniformLocCache.find(name); + if (search != _uniformLocCache.end()) + return search->second; + + GLint ret = glGetUniformLocation(_progID, name.c_str()); + if (ret != -1) + _uniformLocCache.emplace(name, ret); + return ret; +} + +GLint Program::getAttribLocation(std::string const& name) const +{ + auto search = _attribLocCache.find(name); + if (search != _attribLocCache.end()) + return search->second; + + GLint ret = glGetAttribLocation(_progID, name.c_str()); + if (ret != -1) + _attribLocCache.emplace(name, ret); + return ret; +} diff --git a/shaders.hh b/shaders.hh index 0b77257..ef6a415 100644 --- a/shaders.hh +++ b/shaders.hh @@ -4,22 +4,20 @@ #include #include -#include +#include #include "common.hh" -using namespace gl; class ShaderException : public GLException { public: - ShaderException(std::string const& msg) : GLException(glGetError()), _msg(msg) { - } - - virtual ~ShaderException() {} + ShaderException(std::string const& msg); + + //~ShaderException() {} std::string const& getMsg() const {return _msg;} - virtual std::string toString() const { + std::string toString() const override { return "ShaderException: " + _msg; } @@ -33,33 +31,12 @@ 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: + Shader(std::string const& program, gl::GLenum type); + +public: + virtual ~Shader(); unsigned getID() const { return _shaderID; @@ -75,118 +52,33 @@ class VertexShader : public Shader { public: VertexShader(std::string const& program) : Shader(program, GL_VERTEX_SHADER) { } - - ~VertexShader() override { - } }; 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()); + Program(VertexShader& vertex, FragmentShader& frag); - 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(GeometryShader& geom, VertexShader& vertex, FragmentShader& frag); - ~Program() { - glDeleteProgram(_progID); - } + ~Program(); - void use() const { - glUseProgram(_progID); - } + void use() const; - GLint getUniformLocation(std::string const& name) const { - auto search = _uniformLocCache.find(name); - if (search != _uniformLocCache.end()) - return search->second; - - GLint ret = glGetUniformLocation(_progID, name.c_str()); - if (ret != -1) - _uniformLocCache.emplace(name, ret); - return ret; - } + gl::GLint getUniformLocation(std::string const& name) const; - GLint getAttribLocation(std::string const& name) const { - auto search = _attribLocCache.find(name); - if (search != _attribLocCache.end()) - return search->second; - - GLint ret = glGetAttribLocation(_progID, name.c_str()); - if (ret != -1) - _attribLocCache.emplace(name, ret); - return ret; - } + gl::GLint getAttribLocation(std::string const& name) const; private: GeometryShader* _geom; @@ -194,7 +86,7 @@ private: FragmentShader& _frag; unsigned _progID; - mutable std::unordered_map _uniformLocCache, _attribLocCache; + mutable std::unordered_map _uniformLocCache, _attribLocCache; }; #endif diff --git a/shaders/overlay.fs b/shaders/overlay.fs new file mode 100644 index 0000000..5dc5bcb --- /dev/null +++ b/shaders/overlay.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/overlay.vs b/shaders/overlay.vs new file mode 100644 index 0000000..85c6936 --- /dev/null +++ b/shaders/overlay.vs @@ -0,0 +1,13 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +layout(location = 0) in vec2 vertex; +layout(location = 1) in vec2 vertexTC; + +out vec2 fragTC; + +void main(void) { + vec4 pos = vec4(vertex, 0.0, 1.0); + gl_Position = pos; + fragTC = vertexTC; +} diff --git a/shaders/textured.fs b/shaders/textured.fs index 085db7e..c1ccfcc 100644 --- a/shaders/textured.fs +++ b/shaders/textured.fs @@ -8,15 +8,17 @@ uniform samplerCubeShadow texShadowMaps[lights]; float VectorToDepth (vec3 Vec) { vec3 AbsVec = abs(Vec); - float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z)); + //float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z)); + float LocalZcomp = length(AbsVec); // Replace f and n with the far and near plane values you used when // you drew your cube map. const float f = 128.0; const float n = 1.0; - float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp; - return (NormZComp + 1.0) * 0.5; + // float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp; + return (f/(f-n))+(f*n/(n-f))/LocalZcomp; + //return (NormZComp + 1.0) * 0.5; } in vec2 fragTC; @@ -27,7 +29,7 @@ in vec3 lightVecs[lights]; out vec4 color; -const float bias = 0.00; +const float bias = 0.0; void main(void) { vec4 texColor = texture(texBase, fragTC); diff --git a/texture.cc b/texture.cc new file mode 100644 index 0000000..1f5eaad --- /dev/null +++ b/texture.cc @@ -0,0 +1,214 @@ +#include +#include +#include + +#include "texture.hh" + +using namespace gl; + +static unsigned ilog2(unsigned in) +{ + unsigned ret = 0u, orig = in; + while (in >>= 1) ++ret; + // if ((1<(GL_DEPTH_COMPONENT16), size, size, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + } + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, static_cast(GL_LINEAR)); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast(GL_LINEAR)); +} + +TextureCubeMap::~TextureCubeMap() +{ + glDeleteTextures(1, &_texID); +} + +TextureCubeMap::TextureCubeMap(TextureCubeMap && move) + : _texID(move._texID) +{ + move._texID = 0; +} + +TextureCubeMap& TextureCubeMap::operator=(TextureCubeMap && move) +{ + glDeleteTextures(1, &_texID); + _texID = move._texID; + move._texID = 0; + + return *this; +} + +void TextureCubeMap::bind() const +{ + glBindTexture(GL_TEXTURE_CUBE_MAP, _texID); +} + + +Texture2D::Texture2D(unsigned width, unsigned height) + : _texID(0) +{ + _glCreate(width, height); +} + +Texture2D::Texture2D(std::string const& file) + : _texID(0) +{ + 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); + } catch(...) { + glDeleteTextures(1, &_texID); + throw; + } + } + catch(...) { + SDL_FreeSurface(surf); + throw; + } + SDL_FreeSurface(surf); +} + +Texture2D::Texture2D(SDL_Surface *surface) + : _texID(0) +{ + if(surface->format->Amask == 0) + _glCreate(surface->w, surface->h); + else + _glCreate(surface->w, surface->h, true); + + try { + SDL_Surface *surf; + if((surface->format->format != SDL_PIXELFORMAT_RGB24) && + (surface->format->format != SDL_PIXELFORMAT_RGBA8888)) { + if(surface->format->Amask == 0) { + surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGB24, 0); + } else { + surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0); + } + if(!surf) + throw SDLException{}; + } else { + surf = surface; + } + + if (SDL_MUSTLOCK(surf)) + SDL_LockSurface(surf); + try { + if(surface->format->Amask == 0) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels); + else + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); + glGenerateMipmap(GL_TEXTURE_2D); + } catch(...) { + if (surf != surface) + SDL_FreeSurface(surf); + throw; + } + SDL_FreeSurface(surf); + } catch(...) { + glDeleteTextures(1, &_texID); + throw; + } +} + +Texture2D::Texture2D(Texture2D&& move) + : _texID(move._texID) +{ + move._texID = 0; +} + +Texture2D& Texture2D::operator=(Texture2D&& move) +{ + glDeleteTextures(1, &_texID); + _texID = move._texID; + move._texID = 0; + + return *this; +} + +Texture2D::~Texture2D() +{ + glDeleteTextures(1, &_texID); +} + +void Texture2D::bind() const +{ + glBindTexture(GL_TEXTURE_2D, _texID); +} + +void Texture2D::_glCreate(unsigned width, unsigned height, bool alpha) +{ + glGenTextures(1, &_texID); + 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, alpha?GL_RGBA8: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, static_cast(alpha?GL_RGBA8:GL_RGB8), width, height, 0, + alpha?GL_RGBA8:GL_RGB8, GL_UNSIGNED_BYTE, NULL); + width = std::max(1u, (width / 2u)); + height = std::max(1u, (height / 2u)); + } + } + } catch(...) { + glDeleteTextures(1, &_texID); + } +} diff --git a/texture.hh b/texture.hh index b12c5da..6852d73 100644 --- a/texture.hh +++ b/texture.hh @@ -6,168 +6,73 @@ #include #include -#include -#include - -#include +#include #include "common.hh" -using namespace gl; - -static unsigned ilog2(unsigned in) -{ - unsigned ret = 0u; - while (in >>= 1) ++ret; - return ret; -} class Framebuffer { public: - Framebuffer() : _fbID(0) { - glGenFramebuffers(1, &_fbID); - } + Framebuffer(); - ~Framebuffer() { - glDeleteFramebuffers(1, &_fbID); - } + ~Framebuffer(); - void bind() const { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbID); - } + void bind() const; - GLuint getID() const { + gl::GLuint getID() const { return _fbID; } - void attachTexture(GLenum textarget, GLuint texID) { - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - textarget, texID, 0); - } + void attachTexture(GLenum textarget, gl::GLuint texID); private: - GLuint _fbID; + gl::GLuint _fbID; }; class TextureCubeMap { public: - TextureCubeMap(unsigned size) : _texID(0) { - glGenTextures(1, &_texID); - glBindTexture(GL_TEXTURE_CUBE_MAP, _texID); - - if(SDL_GL_ExtensionSupported("GL_ARB_texture_storage")) - glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_DEPTH_COMPONENT24, - size, size); - else { - std::printf("Warning: extension GL_ARB_texture_storage not supported!\n"); - for (unsigned i = 0;i < 6;++i) { - GLenum const face[6] = {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}; - glTexImage2D(face[i], 0, static_cast(GL_DEPTH_COMPONENT16), size, size, 0, - GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); - } - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, static_cast(GL_LINEAR)); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast(GL_LINEAR)); - } + TextureCubeMap(unsigned size); - ~TextureCubeMap() { - glDeleteTextures(1, &_texID); - } + ~TextureCubeMap(); TextureCubeMap(TextureCubeMap const& copy) = delete; TextureCubeMap& operator=(TextureCubeMap const& copy) = delete; - TextureCubeMap(TextureCubeMap && move) : _texID(move._texID) { - move._texID = 0; - } + TextureCubeMap(TextureCubeMap && move); - TextureCubeMap& operator=(TextureCubeMap && move) { - glDeleteTextures(1, &_texID); - _texID = move._texID; - move._texID = 0; - - return *this; - } + TextureCubeMap& operator=(TextureCubeMap && move); - void bind() const { - glBindTexture(GL_TEXTURE_CUBE_MAP, _texID); - } + void bind() const; - GLuint getID() const { + gl::GLuint getID() const { return _texID; } private: - GLuint _texID; + gl::GLuint _texID; }; class Texture2D { public: - Texture2D(unsigned width, unsigned height) : _texID(0) { - _glCreate(width, height); - } + Texture2D(unsigned width, unsigned height); + Texture2D(std::string const& file); + Texture2D(SDL_Surface *surface); - Texture2D(std::string const& file) : _texID(0) { - SDL_Surface *surf = IMG_Load(file.c_str()); - if (!surf) - throw SDLException(); + Texture2D(Texture2D const& copy) = delete; + Texture2D& operator=(Texture2D const& copy) = delete; - 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); - } catch(...) { - glDeleteTextures(1, &_texID); - throw; - } - } - catch(...) { - SDL_FreeSurface(surf); - throw; - } - SDL_FreeSurface(surf); - } + Texture2D(Texture2D&& move); + Texture2D& operator=(Texture2D&& move); - ~Texture2D() { - glDeleteTextures(1, &_texID); - } + ~Texture2D(); - void bind() { - glBindTexture(GL_TEXTURE_2D, _texID); - } + void bind() const; private: - void _glCreate(unsigned width, unsigned height) { - glGenTextures(1, &_texID); - 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, 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)); - } - } - } catch(...) { - glDeleteTextures(1, &_texID); - } - } + void _glCreate(unsigned width, unsigned height, bool alpha = false); - GLuint _texID; + gl::GLuint _texID; };