More seperate cc files, font & overlay rendering

This commit is contained in:
2015-02-13 15:46:18 +01:00
parent 05bf47c678
commit e3ec085cf0
19 changed files with 925 additions and 449 deletions

BIN
DejaVuSans.ttf Normal file

Binary file not shown.

View File

@@ -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

77
Object.cc Normal file
View File

@@ -0,0 +1,77 @@
#include <vector>
#include <glbinding/gl/gl.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include "shaders.hh"
#include "Object.hh"
using namespace gl;
Object::Object(VBOManager& vboManager, std::vector<objVertexAttribs> const& vas,
std::vector<uint16_t> 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<objVertexAttribs> 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)));
}
}

View File

@@ -1,78 +1,37 @@
#ifndef __OPENGLPLAYGROUND_OBJECT_HH__
#define __OPENGLPLAYGROUND_OBJECT_HH__
#include <memory>
#include <vector>
#include <glbinding/gl/types.h>
#include "objectParser.hh"
#include "VBOManager.hh"
class Program;
class Object {
public:
Object(VBOManager& vboManager, std::vector<objVertexAttribs> const& vas, std::vector<uint16_t> const& indices,
Program& prog)
: _vboManager(vboManager), _prog(prog), _indices(indices), _vaID(0) {
construct(vas);
}
Object(VBOManager& vboManager, std::vector<objVertexAttribs> const& vas,
std::vector<uint16_t> 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<objVertexAttribs> 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<objVertexAttribs> const& vas);
VBOManager& _vboManager;
VBOManager::VBOAlloc _vbo;
Program& _prog;
std::vector<uint16_t> _indices;
GLuint _vaID;
gl::GLuint _vaID;
};
#endif

53
Overlay.cc Normal file
View File

@@ -0,0 +1,53 @@
#include <vector>
#include <glbinding/gl/gl.h>
#include "shaders.hh"
#include "Overlay.hh"
using namespace gl;
Overlay::Overlay(VBOManager& vboManager, std::vector<ovlVertexAttribs> 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<void const*>(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_);
}

36
Overlay.hh Normal file
View File

@@ -0,0 +1,36 @@
#ifndef __OPENGLPLAYGROUND_OVERLAY_HH__
#define __OPENGLPLAYGROUND_OVERLAY_HH__
#include <vector>
#include <glbinding/gl/types.h>
#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<ovlVertexAttribs> 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

145
VBOManager.cc Normal file
View File

@@ -0,0 +1,145 @@
#include <glbinding/gl/gl.h>
#include <cassert>
#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;
}
}

View File

@@ -5,18 +5,15 @@
#include <tuple>
#include <vector>
#include <list>
#include <cassert>
#include <glbinding/gl/gl.h>
using namespace gl;
#include <glbinding/gl/types.h>
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<GLenum, std::vector<VBO> > _vbos;
std::map<gl::GLenum, std::vector<VBO> > _vbos;
};
#endif

View File

@@ -9,6 +9,7 @@
#include <glbinding/gl/gl.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
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<int>(_err)) + ")";
std::string toString() const override {
return "GLException: " + errToString() + "(" + std::to_string(static_cast<int>(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() {

41
font.cc Normal file
View File

@@ -0,0 +1,41 @@
#include <cassert>
#include <SDL2/SDL_ttf.h>
#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;
}
}

26
font.hh Normal file
View File

@@ -0,0 +1,26 @@
#ifndef __OPENGLPLAYGROUND_FONT_HH__
#define __OPENGLPLAYGROUND_FONT_HH__
#include <string>
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

60
main.cc
View File

@@ -4,6 +4,7 @@
#include <unordered_map>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>
@@ -14,6 +15,7 @@
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/packing.hpp>
#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<float>(shadowMapSize),
static_cast<float>(shadowMapSize), 1.0f, 128.0f);
static_cast<float>(shadowMapSize), 1.0f, 128.0f);
//glm::mat4 shadowProj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 128.0f);
std::vector<TextureCubeMap> 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<ovlVertexAttribs> 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<unsigned>(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) {

134
shaders.cc Normal file
View File

@@ -0,0 +1,134 @@
#include <glbinding/gl/gl.h>
#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;
}

View File

@@ -4,22 +4,20 @@
#include <string>
#include <unordered_map>
#include <glbinding/gl/gl.h>
#include <glbinding/gl/types.h>
#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<std::string, GLint> _uniformLocCache, _attribLocCache;
mutable std::unordered_map<std::string, gl::GLint> _uniformLocCache, _attribLocCache;
};
#endif

11
shaders/overlay.fs Normal file
View File

@@ -0,0 +1,11 @@
#version 330 core
uniform sampler2D texBase;
in vec2 fragTC;
out vec4 color;
void main(void) {
color = texture(texBase, fragTC);
}

13
shaders/overlay.vs Normal file
View File

@@ -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;
}

View File

@@ -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);

214
texture.cc Normal file
View File

@@ -0,0 +1,214 @@
#include <glbinding/gl/gl.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "texture.hh"
using namespace gl;
static unsigned ilog2(unsigned in)
{
unsigned ret = 0u, orig = in;
while (in >>= 1) ++ret;
// if ((1<<ret) < orig) ++ret;
return ret;
}
Framebuffer::Framebuffer()
: _fbID(0)
{
glGenFramebuffers(1, &_fbID);
}
Framebuffer::~Framebuffer()
{
glDeleteFramebuffers(1, &_fbID);
}
void Framebuffer::bind() const
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbID);
}
void Framebuffer::attachTexture(GLenum textarget, GLuint texID)
{
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
textarget, texID, 0);
}
TextureCubeMap::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<GLint>(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<GLint>(GL_LINEAR));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(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<const int>(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);
}
}

View File

@@ -6,168 +6,73 @@
#include <cassert>
#include <algorithm>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <glbinding/gl/gl.h>
#include <glbinding/gl/types.h>
#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<GLint>(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<GLint>(GL_LINEAR));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(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<const int>(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;
};