Merge branch 'master' of ssh://ka.blankertz.org/home/matthias/git/openglplayground
This commit is contained in:
BIN
DejaVuSans.ttf
Normal file
BIN
DejaVuSans.ttf
Normal file
Binary file not shown.
12
Makefile
12
Makefile
@@ -1,12 +1,14 @@
|
||||
CXX=g++
|
||||
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -Wno-sign-compare -std=c++11
|
||||
LDOPTS=-flto
|
||||
LIBS=-lglbinding -lSDL2 -lSDL2_image -lobj -lprotobuf
|
||||
CXXSRCS=main.cc objectParser.cc object.pb.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 -lprotobuf
|
||||
CXXSRCS=main.cc objectParser.cc shaders.cc Object.cc VBOManager.cc texture.cc font.cc Overlay.cc
|
||||
BINIFY_SRCS=binifyObj.cc objectParser.cc object.pb.cc
|
||||
OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o))
|
||||
BINIFY_OBJS=$(addprefix objs/,$(BINIFY_SRCS:.cc=.o))
|
||||
|
||||
all: oglpg binifyObj
|
||||
|
||||
objs/%.o: %.cc
|
||||
$(CXX) $(CXXOPTS) -c -MMD -MP -o $@ $<
|
||||
@cp objs/$*.d objs/$*.P; rm -f objs/$*.d
|
||||
@@ -23,7 +25,7 @@ binifyObj: $(BINIFY_OBJS)
|
||||
clean:
|
||||
rm -f oglpg $(OBJS) $(BINIFY_OBJS) $(addprefix objs/,$(CXXSRCS:.cc=.P)) $(addprefix objs/,$(BINIFY_SRCS:.cc=.P))
|
||||
|
||||
.PHONY: clean
|
||||
.PHONY: clean all
|
||||
|
||||
-include $(addprefix objs/,$(CXXSRCS:.cc=.P))
|
||||
-include $(addprefix objs/,$(BINIFY_SRCS:.cc=.P))
|
||||
|
||||
77
Object.cc
Normal file
77
Object.cc
Normal 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)));
|
||||
}
|
||||
}
|
||||
67
Object.hh
67
Object.hh
@@ -1,74 +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() {
|
||||
glDeleteVertexArrays(1, &_vaID);
|
||||
}
|
||||
Object(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());
|
||||
}
|
||||
~Object();
|
||||
|
||||
Object& operator=(Object const& copy) = delete;
|
||||
|
||||
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
53
Overlay.cc
Normal 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
36
Overlay.hh
Normal 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
|
||||
146
VBOManager.cc
Normal file
146
VBOManager.cc
Normal file
@@ -0,0 +1,146 @@
|
||||
#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));
|
||||
}
|
||||
return;
|
||||
}
|
||||
pos += it->size;
|
||||
}
|
||||
}
|
||||
128
VBOManager.hh
128
VBOManager.hh
@@ -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,32 +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& operator=(VBOAlloc&& move) {
|
||||
_vbo = move._vbo;
|
||||
_ofs = move._ofs;
|
||||
_size = move._size;
|
||||
move._vbo = nullptr;
|
||||
return *this;
|
||||
}
|
||||
VBOAlloc(VBOAlloc const& copy) = delete;
|
||||
VBOAlloc& operator=(VBOAlloc const& copy) = delete;
|
||||
|
||||
VBOAlloc() : _vbo(nullptr), _ofs(0), _size(0) {
|
||||
}
|
||||
VBOAlloc& operator=(VBOAlloc&& move);
|
||||
|
||||
VBOAlloc();
|
||||
|
||||
size_t getOfs() const {
|
||||
assert(_vbo);
|
||||
@@ -61,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;
|
||||
@@ -77,96 +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(VBO&& move) : _bufID(move._bufID), _allocs(move._allocs) {
|
||||
move._bufID = 0;
|
||||
}
|
||||
VBO& operator=(VBO const& copy) = delete;
|
||||
|
||||
~VBO() {
|
||||
for (auto ent : _allocs) {
|
||||
assert(!ent.used);
|
||||
}
|
||||
if (_bufID)
|
||||
glDeleteBuffers(1, &_bufID);
|
||||
_bufID = 0;
|
||||
}
|
||||
VBO(VBO&& move);
|
||||
|
||||
VBOAlloc alloc(size_t size) {
|
||||
if (size%alignment != 0)
|
||||
size += (alignment - (size%alignment));
|
||||
VBO& operator=(VBO&& move);
|
||||
|
||||
~VBO();
|
||||
|
||||
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;
|
||||
}
|
||||
VBOAlloc alloc(size_t size);
|
||||
|
||||
throw AllocFailed();
|
||||
}
|
||||
void free(VBOAlloc& alloc);
|
||||
|
||||
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));
|
||||
}
|
||||
return;
|
||||
}
|
||||
pos += it->size;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint getID() const {
|
||||
gl::GLuint getID() const {
|
||||
return _bufID;
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint _bufID;
|
||||
gl::GLuint _bufID;
|
||||
|
||||
struct _Entry {
|
||||
size_t size;
|
||||
@@ -176,7 +100,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
std::map<GLenum, std::vector<VBO> > _vbos;
|
||||
std::map<gl::GLenum, std::vector<VBO> > _vbos;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
64
common.hh
64
common.hh
@@ -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
41
font.cc
Normal 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
26
font.hh
Normal 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
60
main.cc
@@ -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
134
shaders.cc
Normal 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;
|
||||
}
|
||||
150
shaders.hh
150
shaders.hh
@@ -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,41 +31,18 @@ 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;
|
||||
}
|
||||
|
||||
friend class Program;
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int _shaderID;
|
||||
};
|
||||
@@ -77,120 +52,33 @@ class VertexShader : public Shader {
|
||||
public:
|
||||
VertexShader(std::string const& program) : Shader(program, GL_VERTEX_SHADER) {
|
||||
}
|
||||
|
||||
virtual ~VertexShader() {
|
||||
}
|
||||
};
|
||||
|
||||
class FragmentShader : public Shader {
|
||||
public:
|
||||
FragmentShader(std::string const& program) : Shader(program, GL_FRAGMENT_SHADER) {
|
||||
}
|
||||
|
||||
virtual ~FragmentShader() {
|
||||
}
|
||||
};
|
||||
|
||||
class GeometryShader : public Shader {
|
||||
public:
|
||||
GeometryShader(std::string const& program) : Shader(program, GL_GEOMETRY_SHADER) {
|
||||
}
|
||||
|
||||
virtual ~GeometryShader() {
|
||||
}
|
||||
};
|
||||
|
||||
class Program {
|
||||
public:
|
||||
Program(VertexShader& vertex, FragmentShader& frag) : _geom(nullptr), _vertex(vertex), _frag(frag) {
|
||||
_progID = glCreateProgram();
|
||||
|
||||
glAttachShader(_progID, _vertex.getID());
|
||||
glAttachShader(_progID, _frag.getID());
|
||||
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;
|
||||
@@ -198,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
11
shaders/overlay.fs
Normal 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
13
shaders/overlay.vs
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
228
texture.cc
Normal file
228
texture.cc
Normal file
@@ -0,0 +1,228 @@
|
||||
#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;
|
||||
while (in >>= 1) ++ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Framebuffer::Framebuffer()
|
||||
: _fbID(0)
|
||||
{
|
||||
glGenFramebuffers(1, &_fbID);
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer()
|
||||
{
|
||||
glDeleteFramebuffers(1, &_fbID);
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(Framebuffer && move)
|
||||
: _fbID(move._fbID)
|
||||
{
|
||||
move._fbID = 0;
|
||||
}
|
||||
|
||||
Framebuffer& Framebuffer::operator=(Framebuffer && move)
|
||||
{
|
||||
glDeleteFramebuffers(1, &_fbID);
|
||||
_fbID = move._fbID;
|
||||
move._fbID = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
170
texture.hh
170
texture.hh
@@ -6,198 +6,80 @@
|
||||
#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() {
|
||||
glGenFramebuffers(1, &_fbID);
|
||||
}
|
||||
Framebuffer();
|
||||
|
||||
~Framebuffer() {
|
||||
glDeleteFramebuffers(1, &_fbID);
|
||||
}
|
||||
~Framebuffer();
|
||||
|
||||
Framebuffer(Framebuffer const& copy) = delete;
|
||||
Framebuffer& operator=(Framebuffer const& copy) = delete;
|
||||
|
||||
Framebuffer(Framebuffer && move) : _fbID(move._fbID) {
|
||||
move._fbID = 0;
|
||||
}
|
||||
Framebuffer(Framebuffer && move);
|
||||
|
||||
Framebuffer& operator=(Framebuffer && move) {
|
||||
glDeleteFramebuffers(1, &_fbID);
|
||||
_fbID = move._fbID;
|
||||
move._fbID = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
Framebuffer& operator=(Framebuffer && move);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
_glCreate(width, height);
|
||||
}
|
||||
|
||||
Texture2D(std::string const& file) {
|
||||
SDL_Surface *surf = IMG_Load(file.c_str());
|
||||
if (!surf)
|
||||
throw SDLException();
|
||||
|
||||
try {
|
||||
_glCreate(surf->w, surf->h);
|
||||
try {
|
||||
assert(surf->format->format == SDL_PIXELFORMAT_RGB24); // TODO: Proper support of many formats
|
||||
if (SDL_MUSTLOCK(surf))
|
||||
SDL_LockSurface(surf);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
} catch(...) {
|
||||
glDeleteTextures(1, &_texID);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch(...) {
|
||||
SDL_FreeSurface(surf);
|
||||
throw;
|
||||
}
|
||||
SDL_FreeSurface(surf);
|
||||
}
|
||||
|
||||
~Texture2D() {
|
||||
glDeleteTextures(1, &_texID);
|
||||
}
|
||||
Texture2D(unsigned width, unsigned height);
|
||||
Texture2D(std::string const& file);
|
||||
Texture2D(SDL_Surface *surface);
|
||||
|
||||
Texture2D(Texture2D const& copy) = delete;
|
||||
Texture2D& operator=(Texture2D const& copy) = delete;
|
||||
|
||||
Texture2D(Texture2D && move) : _texID(move._texID) {
|
||||
move._texID = 0;
|
||||
}
|
||||
|
||||
Texture2D& operator=(Texture2D && move) {
|
||||
glDeleteTextures(1, &_texID);
|
||||
_texID = move._texID;
|
||||
move._texID = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
Texture2D(Texture2D&& move);
|
||||
Texture2D& operator=(Texture2D&& move);
|
||||
|
||||
void bind() {
|
||||
glBindTexture(GL_TEXTURE_2D, _texID);
|
||||
}
|
||||
~Texture2D();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user