Texturing; OBJ loader

This commit is contained in:
2014-11-14 22:36:38 +01:00
parent 0be3e0a50e
commit df90fbf952
15 changed files with 956 additions and 281 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
objs/
oglpg
*.trace
*~

View File

@@ -1,8 +1,8 @@
CXX=g++
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++11
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -Wno-unused-function -Wno-unused-parameter -std=c++11
LDOPTS=-flto
LIBS=-lGL -lSDL2
CXXSRCS=main.cc
LIBS=-lGL -lSDL2 -lSDL2_image -lobj
CXXSRCS=main.cc objectParser.cc
OBJS=$(addprefix objs/,$(CXXSRCS:.cc=.o))
objs/%.o: %.cc

121
common.hh Normal file
View File

@@ -0,0 +1,121 @@
#ifndef __OPENGLPLAYGROUND_COMMON_HH__
#define __OPENGLPLAYGROUND_COMMON_HH__
#include <string>
#include <cstring>
#include <cstdio>
#include <cerrno>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <SDL2/SDL.h>
class Exception {
public:
Exception() {
}
virtual ~Exception() {}
virtual std::string toString() const = 0;
};
class POSIXException : public Exception {
public:
POSIXException(int err): Exception(), _err(err) {
}
virtual ~POSIXException() {}
int getErr() const {return _err;}
virtual std::string toString() const {
return std::string("POSIXException: ") + std::strerror(_err);
}
private:
int _err;
};
class GLException : public Exception {
public:
GLException(GLenum err) : Exception(), _err(err) {
}
virtual ~GLException() {}
GLenum getErr() const {return _err;}
std::string errToString() const {
std::string ret;
if (_err == GL_INVALID_ENUM)
ret += "GL_INVALID_ENUM ";
if (_err == GL_INVALID_VALUE)
ret += "GL_INVALID_VALUE ";
if (_err == GL_INVALID_OPERATION)
ret += "GL_INVALID_OPERATION ";
if (_err == GL_INVALID_FRAMEBUFFER_OPERATION)
ret += "GL_INVALID_FRAMEBUFFER_OPERATION ";
if (_err == GL_OUT_OF_MEMORY)
ret += "GL_OUT_OF_MEMORY ";
if (_err == GL_STACK_UNDERFLOW)
ret += "GL_STACK_UNDERFLOW ";
if (_err == GL_STACK_OVERFLOW)
ret += "GL_STACK_OVERFLOW ";
return ret;
}
virtual std::string toString() const {
return "GLException: " + errToString() + "(" + std::to_string(_err) + ")";
}
private:
GLenum _err;
};
class SDLException : public Exception {
public:
SDLException() : Exception(), _msg(SDL_GetError()) {
}
virtual ~SDLException() {}
virtual std::string toString() const {
return "SDLException: " + _msg;
}
private:
std::string _msg;
};
static void checkGlError() {
GLenum err;
if ((err = glGetError()) != GL_NO_ERROR)
throw GLException(err);
}
static std::string fileToString(std::string const& name) {
std::FILE *file = std::fopen(name.c_str(), "r");
if (!file) {
throw POSIXException(errno);
}
std::string ret;
char buf[512];
std::size_t p;
while((p = std::fread(buf, 1, 511, file)) > 0) {
buf[p] = '\0';
ret.append(buf);
}
if (!std::feof(file)) {
std::fclose(file);
throw POSIXException(errno);
}
std::fclose(file);
return ret;
}
#endif

412
main.cc
View File

@@ -1,11 +1,12 @@
#include <cstdio>
#include <cmath>
#include <string>
#include <unordered_map>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
//#include <GL/glext.h>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
@@ -13,29 +14,59 @@
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
const char vertexShader[] = "#version 330 core\n"
"uniform mat4 projection_matrix;\n"
"uniform mat4 modelview_matrix;\n"
"\n"
"in vec3 vertex;\n"
"in vec3 vertexColor;\n"
"\n"
"out vec3 fragColor;\n"
"\n"
"void main(void) {\n"
"\tgl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);\n"
"\tfragColor = vertexColor;\n"
"}\n";
#include "common.hh"
#include "shaders.hh"
#include "texture.hh"
#include "objectParser.hh"
const char fragShader[] = "#version 330 core\n"
"in vec3 fragColor;\n"
"\n"
"out vec3 color;\n"
"\n"
"void main(void) {\n"
"\tcolor = fragColor;\n"
//"\tgl_FragDepth = gl_FragCoord.z;\n"
"}\n";
const float cubeVertexData[][5] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f ,0.0f, 1.0f},
{1.0f, 1.0f, 0.0f, 1.0f, 1.0f},
{1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{1.0f, 0.0f, -1.0f, 1.0f, 0.0f},
{1.0f, 1.0f, 0.0f, 0.0f, 1.0f},
{1.0f, 1.0f, -1.0f, 1.0f, 1.0f},
{1.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f, 1.0f, 0.0f},
{1.0f, 1.0f, -1.0f, 0.0f, 1.0f},
{0.0f, 1.0f, -1.0f, 1.0f, 1.0f},
{0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, -1.0f, 0.0f, 1.0f},
{0.0f, 1.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, -1.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
{0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
{1.0f, 1.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, -1.0f, 0.0f, 1.0f},
{1.0f, 1.0f, -1.0f, 1.0f, 1.0f}};
const uint8_t cubeIndices[] = {0, 1, 2,
1, 2, 3,
4, 5, 6,
5, 6, 7,
8, 9, 10,
9, 10, 11,
12, 13, 14,
13, 14, 15,
16, 17, 18,
17, 18, 19,
20, 21, 22,
21, 22, 23};
const float vertices[][3] = {{0.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
@@ -66,6 +97,21 @@ const float colors[][3] = {{1.0f, 0.0f, 1.0f},
{0.0f, 1.0f, 0.0f},
{1.0f, 0.0f, 0.0f}};
const float texcoords[][2] = {{0.0f, 0.0f},
{1.0f, 0.0f},
{0.0f, 1.0f},
{1.0f, 1.0f},
{1.0f, 1.0f},
{1.0f, 0.0f},
{0.0f, 1.0f},
{0.0f, 0.0f},
{0.0f, 0.0f},
{0.0f, 0.0f},
{0.0f, 0.0f},
{0.0f, 0.0f}};
const unsigned indices[] = {0, 2, 1,
2, 3, 1,
@@ -90,236 +136,20 @@ const unsigned indicesPyramid[] = {8, 10, 9,
8, 9, 11,
9, 10, 11};
class GLException{
public:
GLException(GLenum err) : _err(err) {
}
virtual ~GLException() {}
int getErr() const {return _err;}
std::string errToString() const {
std::string ret;
if (_err == GL_INVALID_ENUM)
ret += "GL_INVALID_ENUM ";
if (_err == GL_INVALID_VALUE)
ret += "GL_INVALID_VALUE ";
if (_err == GL_INVALID_OPERATION)
ret += "GL_INVALID_OPERATION ";
if (_err == GL_INVALID_FRAMEBUFFER_OPERATION)
ret += "GL_INVALID_FRAMEBUFFER_OPERATION ";
if (_err == GL_OUT_OF_MEMORY)
ret += "GL_OUT_OF_MEMORY ";
if (_err == GL_STACK_UNDERFLOW)
ret += "GL_STACK_UNDERFLOW ";
if (_err == GL_STACK_OVERFLOW)
ret += "GL_STACK_OVERFLOW ";
return ret;
}
virtual std::string toString() const {
return "GLException: " + errToString() + "(" + std::to_string(_err) + ")";
}
private:
GLenum _err;
};
class ShaderException : public GLException {
public:
ShaderException(std::string const& msg) : GLException(glGetError()), _msg(msg) {
}
virtual ~ShaderException() {}
std::string const& getMsg() const {return _msg;}
virtual std::string toString() const {
return "ShaderException: " + _msg;
}
private:
std::string _msg;
};
class Program;
class Shader {
public:
Shader() : _shaderID(0) {
}
Shader(std::string const& program, GLenum type) {
_shaderID = glCreateShader(type);
const char* const arr[] = {program.c_str()};
glShaderSource(_shaderID, 1, arr, NULL);
glCompileShader(_shaderID);
int state;
glGetShaderiv(_shaderID, GL_COMPILE_STATUS, &state);
if (!state) {
int logLength;
glGetShaderiv(_shaderID, GL_INFO_LOG_LENGTH, &logLength);
char *log = new char[logLength];
glGetShaderInfoLog(_shaderID, logLength, NULL, log);
std::string msg(log);
delete[] log;
glDeleteShader(_shaderID);
throw ShaderException(msg);
}
}
virtual ~Shader() {
glDeleteShader(_shaderID);
}
protected:
unsigned getID() const {
return _shaderID;
}
friend class Program;
unsigned int _shaderID;
};
class VertexShader : public Shader {
public:
VertexShader(std::string const& program) : Shader(program, GL_VERTEX_SHADER) {
}
virtual ~VertexShader() {
}
};
class FragmentShader : public Shader {
public:
FragmentShader(std::string const& program) : Shader(program, GL_FRAGMENT_SHADER) {
}
virtual ~FragmentShader() {
}
};
class GeometryShader : public Shader {
public:
GeometryShader(std::string const& program) : Shader(program, GL_GEOMETRY_SHADER) {
}
virtual ~GeometryShader() {
}
};
class Program {
public:
Program(VertexShader& vertex, FragmentShader& frag) : _geom(nullptr), _vertex(vertex), _frag(frag) {
_progID = glCreateProgram();
glAttachShader(_progID, _vertex.getID());
glAttachShader(_progID, _frag.getID());
glLinkProgram(_progID);
int state;
glGetProgramiv(_progID, GL_LINK_STATUS, &state);
if (!state) {
int logLength;
glGetProgramiv(_progID, GL_INFO_LOG_LENGTH, &logLength);
char *log = new char[logLength];
glGetProgramInfoLog(_progID, logLength, NULL, log);
std::string msg(log);
delete[] log;
glDeleteProgram(_progID);
throw ShaderException(msg);
}
glDetachShader(_progID, _vertex.getID());
glDetachShader(_progID, _frag.getID());
}
Program(GeometryShader& geom, VertexShader& vertex, FragmentShader& frag) : _geom(&geom), _vertex(vertex), _frag(frag) {
_progID = glCreateProgram();
glAttachShader(_progID, _geom->getID());
glAttachShader(_progID, _vertex.getID());
glAttachShader(_progID, _frag.getID());
glLinkProgram(_progID);
int state;
glGetProgramiv(_progID, GL_LINK_STATUS, &state);
if (!state) {
int logLength;
glGetProgramiv(_progID, GL_INFO_LOG_LENGTH, &logLength);
char *log = new char[logLength];
glGetProgramInfoLog(_progID, logLength, NULL, log);
std::string msg(log);
delete[] log;
glDeleteProgram(_progID);
throw ShaderException(msg);
}
glDetachShader(_progID, _geom->getID());
glDetachShader(_progID, _vertex.getID());
glDetachShader(_progID, _frag.getID());
}
~Program() {
glDeleteProgram(_progID);
}
void use() const {
glUseProgram(_progID);
}
int getUniformLocation(std::string const& name) const {
int ret = glGetUniformLocation(_progID, name.c_str());
if (ret == -1)
throw GLException(glGetError());
return ret;
}
int getAttribLocation(std::string const& name) const {
int ret = glGetAttribLocation(_progID, name.c_str());
if (ret == -1)
throw GLException(glGetError());
return ret;
}
private:
GeometryShader* _geom;
VertexShader& _vertex;
FragmentShader& _frag;
unsigned _progID;
};
void checkGlError() {
GLenum err;
if ((err = glGetError()) != GL_NO_ERROR)
throw GLException(err);
}
int main(int argc, char *argv[])
{
SDL_Window *window;
int retcode = 0;
SDL_Init(SDL_INIT_VIDEO);
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::printf("Could not init SDL: %s\n", SDL_GetError());
return 1;
}
if (IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) == 0) {
std::printf("Could not init SDL_image: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
@@ -327,7 +157,7 @@ int main(int argc, char *argv[])
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
@@ -337,7 +167,7 @@ int main(int argc, char *argv[])
SDL_WINDOWPOS_UNDEFINED,
640,
480,
/*SDL_WINDOW_FULLSCREEN_DESKTOP |*/ SDL_WINDOW_OPENGL);
SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_OPENGL);
if (!window) {
std::printf("Could not create window: %s\n", SDL_GetError());
@@ -374,9 +204,7 @@ int main(int argc, char *argv[])
0.1f, 100.0f);
glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 10),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0));
// glm::mat4 model = glm::rotate(0.0f, glm::vec3(1.0f, 0.0f, 0.0f));
glm::vec3(0, 1, 0));
// sf::Font font;
// if (!font.loadFromFile("DejaVuSans.ttf")) {
// std::printf("Error loading font\n");
@@ -391,16 +219,29 @@ int main(int argc, char *argv[])
// sf::Clock clock;
// sf::Time last = clock.getElapsedTime();
checkGlError();
Texture2D cubeTex("textures/Wood_Box_Texture.jpg");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic"))
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4.0f);
else
std::printf("Warning: extension GL_EXT_texture_filter_anisotropic not supported\n");
auto box = readObject("objects/woodbox.obj");
VertexShader vs{vertexShader};
FragmentShader fs{fragShader};
VertexShader vs{fileToString("shaders/textured.vs")};
FragmentShader fs{fileToString("shaders/textured.fs")};
Program prog(vs, fs);
checkGlError();
prog.use();
glUniformMatrix4fv(prog.getUniformLocation("projection_matrix"), 1, GL_FALSE,
glm::value_ptr(proj));
glUniform1i(prog.getUniformLocation("texBase"), 0);
int vertexAL = prog.getAttribLocation("vertex");
//int vertexColorAL = prog.getAttribLocation("vertexColor");
int vertexTCAL = prog.getAttribLocation("vertexTC");
checkGlError();
GLuint buf;
@@ -408,13 +249,35 @@ int main(int argc, char *argv[])
glBindBuffer(GL_ARRAY_BUFFER, buf);
checkGlError();
glBufferData(GL_ARRAY_BUFFER, 2*sizeof(float)*3*12, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*12, (void*)vertices[0]);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*12, sizeof(float)*3*12, (void*)colors[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*24*5, NULL, GL_STATIC_DRAW);
//glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*24*5, (void*)cubeVertexData[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(objVertexAttribs)*std::get<0>(box).size(),
(void*)std::get<0>(box).data());
GLuint arr;
glGenVertexArrays(1, &arr);
glBindVertexArray(arr);
// glBufferData(GL_ARRAY_BUFFER, sizeof(float)*(2*3*12+2*12), NULL, GL_STATIC_DRAW);
// glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*12, (void*)vertices[0]);
// glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*3*12, sizeof(float)*3*12, (void*)colors[0]);
// glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*2*3*12, sizeof(float)*2*12, (void*)texcoords[0]);
GLuint arr[2];
glGenVertexArrays(2, arr);
checkGlError();
// glBindVertexArray(arr[0]);
// glEnableVertexAttribArray(vertexAL);
// glEnableVertexAttribArray(vertexColorAL);
// glEnableVertexAttribArray(vertexTCAL);
// glVertexAttribPointer(vertexAL, 3, GL_FLOAT, GL_FALSE, 0, 0);
// glVertexAttribPointer(vertexColorAL, 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float)*3*12));
// glVertexAttribPointer(vertexTCAL, 2, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float)*2*3*12));
glBindVertexArray(arr[0]);
glEnableVertexAttribArray(vertexAL);
glEnableVertexAttribArray(vertexTCAL);
glVertexAttribPointer(vertexAL, 3, GL_FLOAT, GL_FALSE, sizeof(objVertexAttribs), offsetof(objVertexAttribs, vertex));
glVertexAttribPointer(vertexTCAL, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(objVertexAttribs),
(void*)offsetof(objVertexAttribs, texCoords));
checkGlError();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -440,26 +303,19 @@ int main(int argc, char *argv[])
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
checkGlError();
prog.use();
glm::mat4 model = glm::rotate(SDL_GetTicks()*0.001f, glm::vec3(1.0f, 0.0f, 0.0f));
glUniformMatrix4fv(prog.getUniformLocation("modelview_matrix"), 1, GL_FALSE,
glm::value_ptr(view*model));
// glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, indices);
glDrawElements(GL_TRIANGLES, std::get<1>(box).size(), GL_UNSIGNED_SHORT, std::get<1>(box).data());
checkGlError();
glEnableVertexAttribArray(prog.getAttribLocation("vertex"));
glEnableVertexAttribArray(prog.getAttribLocation("vertexColor"));
checkGlError();
glVertexAttribPointer(prog.getAttribLocation("vertex"), 3, GL_FLOAT, GL_FALSE, 0, 0);
checkGlError();
glVertexAttribPointer(prog.getAttribLocation("vertexColor"), 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(float)*3*12));
checkGlError();
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, indices);
checkGlError();
glUniformMatrix4fv(prog.getUniformLocation("modelview_matrix"), 1, GL_FALSE,
glm::value_ptr(view));
checkGlError();
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, indicesPyramid);
checkGlError();
// glUniformMatrix4fv(prog.getUniformLocation("modelview_matrix"), 1, GL_FALSE,
// glm::value_ptr(view));
// glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, indicesPyramid);
// checkGlError();
// glUseProgram(0);
// sf::Time now = clock.getElapsedTime();
@@ -471,7 +327,7 @@ int main(int argc, char *argv[])
SDL_GL_SwapWindow(window);
}
}catch(GLException &ex) {
}catch(Exception &ex) {
std::printf("%s\n", ex.toString().c_str());
retcode = 1;
}

281
objectParser.cc Normal file
View File

@@ -0,0 +1,281 @@
#include <iostream>
#include <cassert>
#include <vector>
#include <tuple>
#include <map>
#include <tr1/functional>
#include <obj.hpp>
#include "objectParser.hh"
using namespace obj;
using std::tr1::placeholders::_1;
using std::tr1::placeholders::_2;
using std::tr1::placeholders::_3;
using std::tr1::placeholders::_4;
class ObjectParser {
private:
void texture_vertex_callback(obj::float_type u, obj::float_type v)
{
if ((u > 1.0f) || (u < 0.0f))
std::cout << "Warning: Clamping texture coordinate U to [0.0, 1.0]" << std::endl;
uint16_t c_u = static_cast<uint16_t>(fminf(1.0f, fmaxf(0.0f, u))*65535.0);
if ((v > 1.0f) || (v < 0.0f))
std::cout << "Warning: Clamping texture coordinate V to [0.0, 1.0]" << std::endl;
uint16_t c_v = static_cast<uint16_t>(fminf(1.0f, fmaxf(0.0f, v))*65535.0);
_texCoords.emplace_back(c_u, c_v);
std::cout << "vt " << c_u << " " << c_v << "\n";
}
void geometric_vertex_callback(obj::float_type x, obj::float_type y, obj::float_type z)
{
_vertices.emplace_back(x, y, z);
std::cout << "v " << x << " " << y << " " << z << "\n";
}
void vertex_normal_callback(obj::float_type x, obj::float_type y, obj::float_type z)
{
union {
struct {
signed :2;
signed z:10;
signed y:10;
signed x:10;
} bits;
uint32_t all;
} pack_10;
if ((x > 1.0f) || (x < -1.0f))
std::cout << "Warning: Clamping normal X to [-1.0, 1.0]" << std::endl;
pack_10.bits.x = static_cast<int>(fminf(1.0f, fmaxf(-1.0f, x))*511.0);
if ((y > 1.0f) || (y < -1.0f))
std::cout << "Warning: Clamping normal Y to [-1.0, 1.0]" << std::endl;
pack_10.bits.y = static_cast<int>(fminf(1.0f, fmaxf(-1.0f, y))*511.0);
if ((z > 1.0f) || (z < -1.0f))
std::cout << "Warning: Clamping normal Z to [-1.0, 1.0]" << std::endl;
pack_10.bits.z = static_cast<int>(fminf(1.0f, fmaxf(-1.0f, z))*511.0);
_normals.push_back(pack_10.all);
std::cout << "vn " << pack_10.bits.x << " " << pack_10.bits.y << " " << pack_10.bits.z << "\n";
}
void triangular_face_geometric_vertices_callback(index_type a, index_type b, index_type c)
{
}
size_t _find_vertex_tc_pair(index_2_tuple_type const& a)
{
auto pair_it = _vertex_tc_pairs_map.find(std::tuple<std::size_t, std::size_t>(std::tr1::get<0>(a), std::tr1::get<1>(a)));
size_t pair_pos;
if (pair_it != _vertex_tc_pairs_map.end())
pair_pos = pair_it->second;
else {
_vertex_tc_pairs.emplace_back(std::get<0>(_vertices[std::tr1::get<0>(a)-1]),
std::get<1>(_vertices[std::tr1::get<0>(a)-1]),
std::get<2>(_vertices[std::tr1::get<0>(a)-1]),
std::get<0>(_texCoords[std::tr1::get<1>(a)-1]),
std::get<1>(_texCoords[std::tr1::get<1>(a)-1]));
pair_pos = _vertex_tc_pairs.size()-1;
_vertex_tc_pairs_map.emplace(std::tuple<std::size_t, std::size_t>(std::tr1::get<0>(a), std::tr1::get<1>(a)),
pair_pos);
}
return pair_pos;
}
void triangular_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c)
{
if ((_vertices.size() < std::tr1::get<0>(a)) ||
(_vertices.size() < std::tr1::get<0>(b)) ||
(_vertices.size() < std::tr1::get<0>(c)))
throw ParseException("Vertex Index out of range");
if ((_texCoords.size() < std::tr1::get<1>(a)) ||
(_texCoords.size() < std::tr1::get<1>(b)) ||
(_texCoords.size() < std::tr1::get<1>(c)))
throw ParseException("Texture Coordinate Index out of range");
std::cout << "f (" << std::tr1::get<0>(a) << ", " << std::tr1::get<1>(a) << ")" <<
" (" << std::tr1::get<0>(b) << ", " << std::tr1::get<1>(b) << ")" <<
" (" << std::tr1::get<0>(c) << ", " << std::tr1::get<1>(c) << ")\n";
size_t a_pos = _find_vertex_tc_pair(a);
size_t b_pos = _find_vertex_tc_pair(b);
size_t c_pos = _find_vertex_tc_pair(c);
_faces.emplace_back(a_pos, b_pos, c_pos);
std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n";
}
void triangular_face_geometric_vertices_vertex_normals_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c)
{
}
void triangular_face_geometric_vertices_texture_vertices_vertex_normals_callback(index_3_tuple_type a, index_3_tuple_type b,
index_3_tuple_type c)
{
}
void quadrilateral_face_geometric_vertices_callback(index_type a, index_type b, index_type c, index_type d)
{
assert(false);
}
void quadrilateral_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b,
index_2_tuple_type c, index_2_tuple_type d)
{
assert(false);
}
void quadrilateral_face_geometric_vertices_vertex_normals_callback(index_2_tuple_type a, index_2_tuple_type b,
index_2_tuple_type c, index_2_tuple_type d)
{
assert(false);
}
void quadrilateral_face_geometric_vertices_texture_vertices_vertex_normals_callback(index_3_tuple_type a, index_3_tuple_type b,
index_3_tuple_type c, index_3_tuple_type d)
{
assert(false);
}
void polygonal_face_geometric_vertices_begin_callback(index_type a, index_type b, index_type c)
{
assert(false);
}
void polygonal_face_geometric_vertices_vertex_callback(index_type a)
{
assert(false);
}
void polygonal_face_geometric_vertices_end_callback()
{
assert(false);
}
void polygonal_face_geometric_vertices_texture_vertices_begin_callback(index_2_tuple_type a, index_2_tuple_type b,
index_2_tuple_type c)
{
assert(false);
}
void polygonal_face_geometric_vertices_texture_vertices_vertex_callback(index_2_tuple_type a)
{
assert(false);
}
void polygonal_face_geometric_vertices_texture_vertices_end_callback()
{
assert(false);
}
void polygonal_face_geometric_vertices_vertex_normals_begin_callback(index_2_tuple_type a, index_2_tuple_type b,
index_2_tuple_type c)
{
assert(false);
}
void polygonal_face_geometric_vertices_vertex_normals_vertex_callback(index_2_tuple_type a)
{
assert(false);
}
void polygonal_face_geometric_vertices_vertex_normals_end_callback()
{
assert(false);
}
void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_begin_callback(index_3_tuple_type a, index_3_tuple_type b,
index_3_tuple_type c)
{
assert(false);
}
void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_vertex_callback(index_3_tuple_type a)
{
assert(false);
}
void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_end_callback()
{
assert(false);
}
std::vector<std::tuple<float, float, float> > _vertices;
std::vector<std::tuple<uint16_t, uint16_t> > _texCoords;
std::vector<uint32_t> _normals;
std::map<std::tuple<std::size_t, std::size_t>, std::size_t > _vertex_tc_pairs_map;
std::vector<std::tuple<float, float, float, uint16_t, uint16_t> > _vertex_tc_pairs;
std::vector<std::tuple<std::size_t, std::size_t, std::size_t> > _faces;
public:
ObjectParser() {
}
~ObjectParser() {
}
void parse(std::string const& filename)
{
obj::obj_parser obj_parser(obj::obj_parser::triangulate_faces | obj::obj_parser::translate_negative_indices);
obj_parser.geometric_vertex_callback(std::tr1::bind(&ObjectParser::geometric_vertex_callback, this, _1, _2, _3));
obj_parser.texture_vertex_callback(std::tr1::bind(&ObjectParser::texture_vertex_callback, this, _1, _2));
obj_parser.vertex_normal_callback(std::tr1::bind(&ObjectParser::vertex_normal_callback, this, _1, _2, _3));
obj_parser.face_callbacks
(std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_texture_vertices_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_vertex_normals_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_texture_vertices_vertex_normals_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_callback, this, _1, _2, _3, _4),
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_texture_vertices_callback, this, _1, _2, _3, _4),
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_vertex_normals_callback, this, _1, _2, _3, _4),
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_texture_vertices_vertex_normals_callback, this, _1, _2, _3, _4),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_begin_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_callback, this, _1),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_end_callback, this),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_begin_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_callback, this, _1),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_end_callback, this),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_begin_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_vertex_callback, this, _1),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_end_callback, this),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_begin_callback, this, _1, _2, _3),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_vertex_callback, this, _1),
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_end_callback, this));
obj_parser.parse(filename);
}
std::vector<objVertexAttribs> buildVA()
{
std::vector<objVertexAttribs> ret;
for (auto const& ent : _vertex_tc_pairs) {
objVertexAttribs tmp;
tmp.vertex[0] = std::get<0>(ent);
tmp.vertex[1] = std::get<1>(ent);
tmp.vertex[2] = std::get<2>(ent);
tmp.texCoords[0] = std::get<3>(ent);
tmp.texCoords[1] = std::get<4>(ent);
ret.push_back(tmp);
}
return ret;
}
std::vector<uint16_t> buildIndices() const
{
std::vector<uint16_t> ret;
for (auto const& ent : _faces) {
ret.push_back(std::get<0>(ent));
ret.push_back(std::get<1>(ent));
ret.push_back(std::get<2>(ent));
}
return ret;
}
};
std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> > readObject(std::string const& filename)
{
ObjectParser parser;
parser.parse(filename);
return std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> >(parser.buildVA(), parser.buildIndices());
}

34
objectParser.hh Normal file
View File

@@ -0,0 +1,34 @@
#ifndef __OPENGLPLAYGROUND_OBJECTPARSER_HH__
#define __OPENGLPLAYGROUND_OBJECTPARSER_HH__
#include <string>
#include <vector>
#include "common.hh"
class ParseException : public Exception {
public:
ParseException(std::string const& msg) : Exception(), _msg(msg) {
}
virtual ~ParseException() {}
std::string const& getMsg() const {return _msg;}
virtual std::string toString() const {
return "ParseException: " + _msg;
}
private:
std::string _msg;
};
struct objVertexAttribs {
float vertex[3];
uint16_t texCoords[2];
} __attribute__((__packed__));
std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> > readObject(std::string const& filename);
#endif

33
objects/woodbox.obj Normal file
View File

@@ -0,0 +1,33 @@
v 0.0 0.0 0.0
v 1.0 0.0 0.0
v 0.0 1.0 0.0
v 1.0 1.0 0.0
v 0.0 0.0 -1.0
v 1.0 0.0 -1.0
v 0.0 1.0 -1.0
v 1.0 1.0 -1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 1.0 1.0
vn 0.0 0.0 1.0
vn 1.0 0.0 0.0
vn 0.0 0.0 -1.0
vn -1.0 0.0 0.0
vn 0.0 1.0 0.0
vn 0.0 -1.0 0.0
f 1/1 3/3 4/4 2/2
f 2/1 4/3 8/4 6/2
f 6/1 8/3 7/4 5/2
f 5/1 7/3 3/4 1/2
f 5/1 1/3 2/4 6/2
f 3/1 7/3 8/4 4/2

205
shaders.hh Normal file
View File

@@ -0,0 +1,205 @@
#ifndef __OPENGLPLAYGROUND_SHADERS_HH__
#define __OPENGLPLAYGROUND_SHADERS_HH__
#include <string>
#include <unordered_map>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include "common.hh"
class ShaderException : public GLException {
public:
ShaderException(std::string const& msg) : GLException(glGetError()), _msg(msg) {
}
virtual ~ShaderException() {}
std::string const& getMsg() const {return _msg;}
virtual std::string toString() const {
return "ShaderException: " + _msg;
}
private:
std::string _msg;
};
class Program;
class Shader {
public:
Shader() : _shaderID(0) {
}
Shader(std::string const& program, GLenum type) {
_shaderID = glCreateShader(type);
const char* const arr[] = {program.c_str()};
glShaderSource(_shaderID, 1, arr, NULL);
glCompileShader(_shaderID);
int state;
glGetShaderiv(_shaderID, GL_COMPILE_STATUS, &state);
if (!state) {
int logLength;
glGetShaderiv(_shaderID, GL_INFO_LOG_LENGTH, &logLength);
char *log = new char[logLength];
glGetShaderInfoLog(_shaderID, logLength, NULL, log);
std::string msg(log);
delete[] log;
glDeleteShader(_shaderID);
throw ShaderException(msg);
}
}
virtual ~Shader() {
glDeleteShader(_shaderID);
}
protected:
unsigned getID() const {
return _shaderID;
}
friend class Program;
unsigned int _shaderID;
};
class VertexShader : public Shader {
public:
VertexShader(std::string const& program) : Shader(program, GL_VERTEX_SHADER) {
}
virtual ~VertexShader() {
}
};
class FragmentShader : public Shader {
public:
FragmentShader(std::string const& program) : Shader(program, GL_FRAGMENT_SHADER) {
}
virtual ~FragmentShader() {
}
};
class GeometryShader : public Shader {
public:
GeometryShader(std::string const& program) : Shader(program, GL_GEOMETRY_SHADER) {
}
virtual ~GeometryShader() {
}
};
class Program {
public:
Program(VertexShader& vertex, FragmentShader& frag) : _geom(nullptr), _vertex(vertex), _frag(frag) {
_progID = glCreateProgram();
glAttachShader(_progID, _vertex.getID());
glAttachShader(_progID, _frag.getID());
glLinkProgram(_progID);
int state;
glGetProgramiv(_progID, GL_LINK_STATUS, &state);
if (!state) {
int logLength;
glGetProgramiv(_progID, GL_INFO_LOG_LENGTH, &logLength);
char *log = new char[logLength];
glGetProgramInfoLog(_progID, logLength, NULL, log);
std::string msg(log);
delete[] log;
glDeleteProgram(_progID);
throw ShaderException(msg);
}
glDetachShader(_progID, _vertex.getID());
glDetachShader(_progID, _frag.getID());
}
Program(GeometryShader& geom, VertexShader& vertex, FragmentShader& frag) : _geom(&geom), _vertex(vertex), _frag(frag) {
_progID = glCreateProgram();
glAttachShader(_progID, _geom->getID());
glAttachShader(_progID, _vertex.getID());
glAttachShader(_progID, _frag.getID());
glLinkProgram(_progID);
int state;
glGetProgramiv(_progID, GL_LINK_STATUS, &state);
if (!state) {
int logLength;
glGetProgramiv(_progID, GL_INFO_LOG_LENGTH, &logLength);
char *log = new char[logLength];
glGetProgramInfoLog(_progID, logLength, NULL, log);
std::string msg(log);
delete[] log;
glDeleteProgram(_progID);
throw ShaderException(msg);
}
glDetachShader(_progID, _geom->getID());
glDetachShader(_progID, _vertex.getID());
glDetachShader(_progID, _frag.getID());
}
~Program() {
glDeleteProgram(_progID);
}
void use() const {
glUseProgram(_progID);
}
int getUniformLocation(std::string const& name) const {
auto search = _uniformLocCache.find(name);
if (search != _uniformLocCache.end())
return search->second;
int ret = glGetUniformLocation(_progID, name.c_str());
if (ret == -1)
throw GLException(glGetError());
_uniformLocCache.emplace(name, ret);
return ret;
}
int getAttribLocation(std::string const& name) const {
auto search = _attribLocCache.find(name);
if (search != _attribLocCache.end())
return search->second;
int ret = glGetAttribLocation(_progID, name.c_str());
if (ret == -1)
throw GLException(glGetError());
_attribLocCache.emplace(name, ret);
return ret;
}
private:
GeometryShader* _geom;
VertexShader& _vertex;
FragmentShader& _frag;
unsigned _progID;
mutable std::unordered_map<std::string, GLint> _uniformLocCache, _attribLocCache;
};
#endif

9
shaders/color.fs Normal file
View File

@@ -0,0 +1,9 @@
#version 330 core
in vec3 fragColor;
out vec4 color;
void main(void) {
color = vec4(fragColor, 1.0);
}

14
shaders/color.vs Normal file
View File

@@ -0,0 +1,14 @@
#version 330 core
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
in vec3 vertex;
in vec3 vertecColor;
out vec3 fragColor;
void main(void) {
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
fragColor = vertexColor;
}

11
shaders/textured.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);
}

14
shaders/textured.vs Normal file
View File

@@ -0,0 +1,14 @@
#version 330 core
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
in vec3 vertex;
in vec2 vertexTC;
out vec2 fragTC;
void main(void) {
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
fragTC = vertexTC;
}

95
texture.hh Normal file
View File

@@ -0,0 +1,95 @@
#ifndef __OPENGLPLAYGROUND_TEXTURE_HH__
#define __OPENGLPLAYGROUND_TEXTURE_HH__
#include <string>
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include "common.hh"
static unsigned ilog2(unsigned in)
{
unsigned ret = 0u;
while (in >>= 1) ++ret;
return ret;
}
class Texture2D {
public:
Texture2D(unsigned width, unsigned height) {
_glCreate(width, height);
}
Texture2D(std::string const& file) {
SDL_Surface *surf = IMG_Load(file.c_str());
if (!surf)
throw SDLException();
try {
_glCreate(surf->w, surf->h);
try {
assert(surf->format->format == SDL_PIXELFORMAT_RGB24); // TODO: Proper support of many formats
if (SDL_MUSTLOCK(surf))
SDL_LockSurface(surf);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
checkGlError();
} catch(...) {
glDeleteTextures(1, &_texID);
throw;
}
}
catch(...) {
SDL_FreeSurface(surf);
throw;
}
SDL_FreeSurface(surf);
}
~Texture2D() {
glDeleteTextures(1, &_texID);
}
void bind() {
glBindTexture(GL_TEXTURE_2D, _texID);
checkGlError();
}
private:
void _glCreate(unsigned width, unsigned height) {
glGenTextures(1, &_texID);
checkGlError();
try {
glBindTexture(GL_TEXTURE_2D, _texID);
unsigned logWidth = ilog2(width), logHeight = ilog2(height);
unsigned levels = std::max(logWidth,logHeight)+1u;
if(SDL_GL_ExtensionSupported("GL_ARB_texture_storage"))
glTexStorage2D(GL_TEXTURE_2D, levels, GL_RGB8, width, height);
else {
std::printf("Warning: extension GL_ARB_texture_storage not supported!\n");
for (unsigned i = 0u; i < levels; ++i)
{
glTexImage2D(GL_TEXTURE_2D, i, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
width = std::max(1u, (width / 2u));
height = std::max(1u, (height / 2u));
}
}
checkGlError();
} catch(...) {
glDeleteTextures(1, &_texID);
}
}
GLuint _texID;
};
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB