diff --git a/src/main.cpp b/src/main.cpp index 30b0aa1..e8f8309 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,16 +3,10 @@ #include "object.hpp" #include -#include -#include -#include #include -#include #include -#include - #include #include @@ -96,223 +90,6 @@ int main() emscripten_set_main_loop(iterate, 0, 1); } -Shader::Shader(const GLenum type, const char *const filename) -{ - FILE *file = fopen(filename, "r"); - - fseek(file, 0, SEEK_END); - const long size = ftell(file); - fseek(file, 0, SEEK_SET); - - char *source = (char*)malloc(size + 1); - fread(source, size, 1, file); - source[size] = 0; - - fclose(file); - - _id = glCreateShader(type); - glShaderSource(_id, 1, (const GLchar**)&source, nullptr); - glCompileShader(_id); - - free(source); -} - -Program::Program() -{ - _id = glCreateProgram(); -} - -void Program::attach_shader(const Shader &shader) -{ - glAttachShader(_id, shader.id()); -} - -void Program::bind_attrib_location(const GLuint index, const GLchar *const name) -{ - glBindAttribLocation(_id, index, name); -} - -void Program::link() -{ - glLinkProgram(_id); -} - -void Program::use() const -{ - glUseProgram(_id); -} - -GLuint Program::get_uniform_location(const GLchar *name) const -{ - return glGetUniformLocation(_id, name); -} - -Model::Model(const char *const filename) -{ - std::ifstream file(filename, std::ios::in); - - std::vector tmp_positions; - std::vector tmp_tex_coords; - std::vector tmp_normals; - - size_t index = 0; - - int attr_count = 0; - - std::string line; - while (std::getline(file, line)) - { - if (line.substr(0, 2) == "v ") - { - glm::vec3 v; - sscanf(line.data(), "v %f %f %f", &v.x, &v.y, &v.z); - tmp_positions.push_back(v); - } - else - if (line.substr(0, 3) == "vt ") - { - glm::vec2 vt; - sscanf(line.data(), "vt %f %f", &vt.x, &vt.y); - tmp_tex_coords.push_back(vt); - } - else - if (line.substr(0, 3) == "vn ") - { - glm::vec3 vn; - sscanf(line.data(), "vn %f %f %f", &vn.x, &vn.y, &vn.z); - tmp_normals.push_back(vn); - } - else - if (line.substr(0, 2) == "f ") - { - if (attr_count == 0) - { - if (line.find("//") == std::string::npos) - attr_count = 3; - else - attr_count = 2; - } - - GLushort v[3]; - GLushort vt[3]; - GLushort vn[3]; - - if (attr_count == 2) - sscanf(line.data(), "f %hu//%hu %hu//%hu %hu//%hu", &v[0], &vn[0], &v[1], &vn[1], &v[2], &vn[2]); - else - sscanf(line.data(), "f %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu", &v[0], &vt[0], &vn[0], - &v[1], &vt[1], &vn[1], - &v[2], &vt[2], &vn[2]); - - for (int i = 0; i < 3; ++i) - { - positions.push_back(tmp_positions[v[i] - 1]); - if (attr_count == 3) - tex_coords.push_back(tmp_tex_coords[vt[i] - 1]); - normals.push_back(tmp_normals[vn[i] - 1]); - elements.push_back(index++); - } - } - else - if (line.substr(0, 7) == "mtllib ") - { - _material = new Material(line.substr(7).c_str()); - } - } - - positions_id = create_array_buffer(GL_ARRAY_BUFFER, 3 * positions.size() * sizeof(GLfloat), positions.data()); - - if (attr_count == 3) - tex_coords_id = create_array_buffer(GL_ARRAY_BUFFER, 2 * tex_coords.size() * sizeof(GLfloat), tex_coords.data()); - else - tex_coords_id = 0; - - normals_id = create_array_buffer(GL_ARRAY_BUFFER, 3 * normals.size() * sizeof(GLfloat), normals.data()); - - id = create_array_buffer(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(GLushort), elements.data()); -} - -GLuint Model::create_array_buffer(const GLenum type, const GLsizeiptr size, const GLvoid *const data) -{ - GLuint id; - glGenBuffers(1, &id); - glBindBuffer(type, id); - glBufferData(type, size, data, GL_STATIC_DRAW); - return id; -} - -void Model::draw() const -{ - _material->use(); - - glBindBuffer(GL_ARRAY_BUFFER, positions_id); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0)); - - if (tex_coords_id == 0) - glDisableVertexAttribArray(1); - else - { - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, tex_coords_id); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0)); - } - - glBindBuffer(GL_ARRAY_BUFFER, normals_id); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0)); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); - - glDrawElements(GL_TRIANGLES, elements.size(), GL_UNSIGNED_SHORT, 0); -} - -void Object::draw(const glm::mat4 &mvp) const -{ - const glm::mat4 transform = glm::translate(mvp, position) - * glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)) - * glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)) - * glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); - - glUniformMatrix4fv(mvp_uniform, 1, GL_FALSE, glm::value_ptr(transform)); - - _model.draw(); -} - -Texture::Texture(const char *const filename) -{ - SDL_Surface *surface = IMG_Load((std::string("/data/textures/") + filename).c_str()); - - glGenTextures(1, &_id); - glBindTexture(GL_TEXTURE_2D, _id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); - - SDL_FreeSurface(surface); -} - -void Texture::use() const -{ - glBindTexture(GL_TEXTURE_2D, _id); -} - -Material::Material(const char *const filename) -{ - std::ifstream file(std::string("/data/materials/") + filename, std::ios::in); - - std::string line; - while (std::getline(file, line)) - { - if (line.substr(0, 7) == "map_Kd ") - { - _texture = new Texture(line.substr(7).c_str()); - } - } -} - -void Material::use() const -{ - _texture->use(); -} - Program build_program() { const Shader vertex_shader = Shader(GL_VERTEX_SHADER, "/data/shaders/vertex.glsl"); diff --git a/src/material.cpp b/src/material.cpp new file mode 100644 index 0000000..d0fddaa --- /dev/null +++ b/src/material.cpp @@ -0,0 +1,23 @@ +#include "material.hpp" + +#include +#include + +Material::Material(const char *const filename) +{ + std::ifstream file(std::string("/data/materials/") + filename, std::ios::in); + + std::string line; + while (std::getline(file, line)) + { + if (line.substr(0, 7) == "map_Kd ") + { + _texture = new Texture(line.substr(7).c_str()); + } + } +} + +void Material::use() const +{ + _texture->use(); +} diff --git a/src/model.cpp b/src/model.cpp new file mode 100644 index 0000000..7cd57da --- /dev/null +++ b/src/model.cpp @@ -0,0 +1,122 @@ +#include "model.hpp" + +#include +#include + +Model::Model(const char *const filename) +{ + std::ifstream file(filename, std::ios::in); + + std::vector tmp_positions; + std::vector tmp_tex_coords; + std::vector tmp_normals; + + size_t index = 0; + + int attr_count = 0; + + std::string line; + while (std::getline(file, line)) + { + if (line.substr(0, 2) == "v ") + { + glm::vec3 v; + sscanf(line.data(), "v %f %f %f", &v.x, &v.y, &v.z); + tmp_positions.push_back(v); + } + else + if (line.substr(0, 3) == "vt ") + { + glm::vec2 vt; + sscanf(line.data(), "vt %f %f", &vt.x, &vt.y); + tmp_tex_coords.push_back(vt); + } + else + if (line.substr(0, 3) == "vn ") + { + glm::vec3 vn; + sscanf(line.data(), "vn %f %f %f", &vn.x, &vn.y, &vn.z); + tmp_normals.push_back(vn); + } + else + if (line.substr(0, 2) == "f ") + { + if (attr_count == 0) + { + if (line.find("//") == std::string::npos) + attr_count = 3; + else + attr_count = 2; + } + + GLushort v[3]; + GLushort vt[3]; + GLushort vn[3]; + + if (attr_count == 2) + sscanf(line.data(), "f %hu//%hu %hu//%hu %hu//%hu", &v[0], &vn[0], &v[1], &vn[1], &v[2], &vn[2]); + else + sscanf(line.data(), "f %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu", &v[0], &vt[0], &vn[0], + &v[1], &vt[1], &vn[1], + &v[2], &vt[2], &vn[2]); + + for (int i = 0; i < 3; ++i) + { + positions.push_back(tmp_positions[v[i] - 1]); + if (attr_count == 3) + tex_coords.push_back(tmp_tex_coords[vt[i] - 1]); + normals.push_back(tmp_normals[vn[i] - 1]); + elements.push_back(index++); + } + } + else + if (line.substr(0, 7) == "mtllib ") + { + _material = new Material(line.substr(7).c_str()); + } + } + + positions_id = create_array_buffer(GL_ARRAY_BUFFER, 3 * positions.size() * sizeof(GLfloat), positions.data()); + + if (attr_count == 3) + tex_coords_id = create_array_buffer(GL_ARRAY_BUFFER, 2 * tex_coords.size() * sizeof(GLfloat), tex_coords.data()); + else + tex_coords_id = 0; + + normals_id = create_array_buffer(GL_ARRAY_BUFFER, 3 * normals.size() * sizeof(GLfloat), normals.data()); + + id = create_array_buffer(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(GLushort), elements.data()); +} + +GLuint Model::create_array_buffer(const GLenum type, const GLsizeiptr size, const GLvoid *const data) +{ + GLuint id; + glGenBuffers(1, &id); + glBindBuffer(type, id); + glBufferData(type, size, data, GL_STATIC_DRAW); + return id; +} + +void Model::draw() const +{ + _material->use(); + + glBindBuffer(GL_ARRAY_BUFFER, positions_id); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0)); + + if (tex_coords_id == 0) + glDisableVertexAttribArray(1); + else + { + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, tex_coords_id); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0)); + } + + glBindBuffer(GL_ARRAY_BUFFER, normals_id); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0)); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); + + glDrawElements(GL_TRIANGLES, elements.size(), GL_UNSIGNED_SHORT, 0); +} diff --git a/src/object.cpp b/src/object.cpp new file mode 100644 index 0000000..876f342 --- /dev/null +++ b/src/object.cpp @@ -0,0 +1,16 @@ +#include "object.hpp" + +#include +#include + +void Object::draw(const glm::mat4 &mvp) const +{ + const glm::mat4 transform = glm::translate(mvp, position) + * glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)) + * glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)) + * glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + + glUniformMatrix4fv(mvp_uniform, 1, GL_FALSE, glm::value_ptr(transform)); + + _model.draw(); +} diff --git a/src/program.cpp b/src/program.cpp new file mode 100644 index 0000000..7b38581 --- /dev/null +++ b/src/program.cpp @@ -0,0 +1,31 @@ +#include "program.hpp" + +Program::Program() +{ + _id = glCreateProgram(); +} + +void Program::attach_shader(const Shader &shader) +{ + glAttachShader(_id, shader.id()); +} + +void Program::bind_attrib_location(const GLuint index, const GLchar *const name) +{ + glBindAttribLocation(_id, index, name); +} + +void Program::link() +{ + glLinkProgram(_id); +} + +void Program::use() const +{ + glUseProgram(_id); +} + +GLuint Program::get_uniform_location(const GLchar *name) const +{ + return glGetUniformLocation(_id, name); +} diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..01e77e9 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,25 @@ +#include "shader.hpp" + +#include +#include + +Shader::Shader(const GLenum type, const char *const filename) +{ + FILE *file = fopen(filename, "r"); + + fseek(file, 0, SEEK_END); + const long size = ftell(file); + fseek(file, 0, SEEK_SET); + + char *source = (char*)malloc(size + 1); + fread(source, size, 1, file); + source[size] = 0; + + fclose(file); + + _id = glCreateShader(type); + glShaderSource(_id, 1, (const GLchar**)&source, nullptr); + glCompileShader(_id); + + free(source); +} diff --git a/src/texture.cpp b/src/texture.cpp new file mode 100644 index 0000000..afa11a8 --- /dev/null +++ b/src/texture.cpp @@ -0,0 +1,22 @@ +#include "texture.hpp" + +#include + +#include + +Texture::Texture(const char *const filename) +{ + SDL_Surface *surface = IMG_Load((std::string("/data/textures/") + filename).c_str()); + + glGenTextures(1, &_id); + glBindTexture(GL_TEXTURE_2D, _id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); + + SDL_FreeSurface(surface); +} + +void Texture::use() const +{ + glBindTexture(GL_TEXTURE_2D, _id); +}