1
0
Fork 0
This repository has been archived on 2023-03-27. You can view files and clone it, but cannot push or open issues or pull requests.
matabstrix/main.cpp

461 lines
10 KiB
C++
Raw Normal View History

2015-11-03 10:40:20 -05:00
#include <cstdlib>
2015-11-06 17:47:24 -05:00
2015-11-05 09:28:18 -05:00
#include <vector>
#include <fstream>
#include <sstream>
2015-11-03 10:40:20 -05:00
2015-11-03 23:48:27 -05:00
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
2015-11-04 13:38:02 -05:00
#include <glm/gtc/matrix_transform.hpp>
2015-11-03 23:48:27 -05:00
2015-11-06 17:47:24 -05:00
#include <SDL_image.h>
2015-11-03 14:00:55 -05:00
#include <GL/glew.h>
2015-11-03 10:40:20 -05:00
#include <GL/glfw.h>
#include <emscripten/emscripten.h>
2015-11-04 13:38:02 -05:00
#include <emscripten/html5.h>
2015-11-05 14:17:04 -05:00
class Shader
{
public:
Shader(GLenum type, const char *filename);
inline GLuint id() const { return _id; };
2015-11-03 14:00:55 -05:00
2015-11-05 14:17:04 -05:00
private:
GLuint _id;
};
2015-11-04 17:52:34 -05:00
2015-11-05 14:17:04 -05:00
class Program
{
public:
Program();
void attach_shader(const Shader &shader);
void bind_attrib_location(GLuint index, const GLchar *name);
void link();
2015-11-06 17:47:24 -05:00
void use() const;
GLuint get_uniform_location(const GLchar *name) const;
2015-11-05 14:17:04 -05:00
private:
GLuint _id;
};
2015-11-03 14:42:02 -05:00
2015-11-05 14:17:04 -05:00
class Model
2015-11-05 09:28:18 -05:00
{
2015-11-05 14:17:04 -05:00
public:
Model(const char *filename);
void draw() const;
private:
std::vector<glm::vec3> positions;
2015-11-05 11:50:43 -05:00
GLuint positions_id;
std::vector<glm::vec2> tex_coords;
GLuint tex_coords_id;
2015-11-05 11:50:43 -05:00
std::vector<glm::vec3> normals;
2015-11-05 17:47:06 -05:00
GLuint normals_id;
2015-11-05 09:28:18 -05:00
std::vector<GLushort> elements;
GLuint id;
2015-11-05 14:17:04 -05:00
static GLuint create_array_buffer(GLenum type, GLsizeiptr size, const GLvoid *data);
2015-11-04 14:39:44 -05:00
};
2015-11-05 14:17:04 -05:00
class Object
{
public:
Object(const Model &model) : _model(model) {};
void draw(const glm::mat4 &mvp) const;
glm::vec3 position;
glm::vec3 rotation;
private:
const Model &_model;
};
2015-11-06 17:47:24 -05:00
class Texture
{
public:
Texture(const char *filename);
void use() const;
private:
GLuint _id;
};
2015-11-05 14:17:04 -05:00
static Program build_program();
static void iterate();
static GLFWCALL void on_key(int key, int action);
static EM_BOOL on_em_mousemove(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data);
static GLuint mvp_id;
static bool keys[GLFW_KEY_LAST];
static float pos_x = 0, pos_y = -4;
static float delta_z = 0, delta_x = 0;
2015-11-04 19:24:06 -05:00
2015-11-05 17:00:00 -05:00
static Model *cube;
2015-11-05 14:17:04 -05:00
static Model *suzanne;
static Model *teapot;
static Model *bunny;
2015-11-05 17:00:00 -05:00
static Object *cube1;
2015-11-05 14:17:04 -05:00
static Object *suzanne1;
static Object *teapot1;
static Object *bunny1;
2015-11-04 14:39:44 -05:00
2015-11-06 17:47:24 -05:00
static Texture *suzanne_tex;
static Texture *bunny_tex;
2015-11-03 06:46:05 -05:00
int main()
{
2015-11-03 10:40:20 -05:00
if (!glfwInit())
exit(EXIT_FAILURE);
if (!glfwOpenWindow(640, 480, 8, 8, 8, 8, 16, 0, GLFW_WINDOW))
{
glfwTerminate();
exit(EXIT_FAILURE);
}
2015-11-03 14:00:55 -05:00
if (glewInit() != GLEW_OK)
{
glfwCloseWindow();
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(on_key);
2015-11-04 13:38:02 -05:00
emscripten_set_mousemove_callback(nullptr, nullptr, false, on_em_mousemove);
2015-11-05 14:17:04 -05:00
Program program = build_program();
program.use();
2015-11-03 14:00:55 -05:00
2015-11-05 14:17:04 -05:00
mvp_id = program.get_uniform_location("mvp");
2015-11-05 17:00:00 -05:00
cube = new Model("/data/models/cube.obj");
2015-11-05 14:17:04 -05:00
suzanne = new Model("/data/models/suzanne.obj");
teapot = new Model("/data/models/teapot.obj");
bunny = new Model("/data/models/bunny.obj");
2015-11-05 17:00:00 -05:00
cube1 = new Object(*cube);
cube1->position.x = 2.5;
cube1->position.y = -4.0;
2015-11-05 14:17:04 -05:00
suzanne1 = new Object(*suzanne);
2015-11-06 17:47:24 -05:00
suzanne1->position.z = -1;
2015-11-05 11:50:43 -05:00
2015-11-05 14:17:04 -05:00
teapot1 = new Object(*teapot);
teapot1->position.x = -3.0;
teapot1->rotation.z = -45;
2015-11-03 14:42:02 -05:00
2015-11-05 14:17:04 -05:00
bunny1 = new Object(*bunny);
bunny1->position.x = 3.0;
2015-11-05 09:28:18 -05:00
2015-11-06 17:47:24 -05:00
suzanne_tex = new Texture("/data/textures/suzanne.png");
bunny_tex = new Texture("/data/textures/bunny.png");
GLint u_texture = program.get_uniform_location("texture");
glUniform1i(u_texture, 0);
2015-11-03 14:00:55 -05:00
glViewport(0, 0, 640, 480);
2015-11-04 14:39:44 -05:00
glEnable(GL_DEPTH_TEST);
2015-11-06 17:47:24 -05:00
glClearColor(1, 1, 1, 0);
2015-11-03 14:00:55 -05:00
emscripten_set_main_loop(iterate, 0, 1);
}
2015-11-05 14:17:04 -05:00
Shader::Shader(const GLenum type, const char *const filename)
2015-11-03 14:00:55 -05:00
{
2015-11-05 08:30:39 -05:00
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);
2015-11-05 14:17:04 -05:00
_id = glCreateShader(type);
glShaderSource(_id, 1, (const GLchar**)&source, nullptr);
glCompileShader(_id);
2015-11-05 08:30:39 -05:00
free(source);
2015-11-05 14:17:04 -05:00
}
2015-11-05 08:30:39 -05:00
2015-11-05 14:17:04 -05:00
Program::Program()
{
_id = glCreateProgram();
2015-11-03 10:40:20 -05:00
}
2015-11-05 14:17:04 -05:00
void Program::attach_shader(const Shader &shader)
2015-11-04 17:52:34 -05:00
{
2015-11-05 14:17:04 -05:00
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);
}
2015-11-06 17:47:24 -05:00
void Program::use() const
2015-11-05 14:17:04 -05:00
{
glUseProgram(_id);
2015-11-04 17:52:34 -05:00
}
2015-11-06 17:47:24 -05:00
GLuint Program::get_uniform_location(const GLchar *name) const
2015-11-05 14:17:04 -05:00
{
return glGetUniformLocation(_id, name);
}
Model::Model(const char *const filename)
{
std::ifstream file(filename, std::ios::in);
2015-11-06 16:23:17 -05:00
std::vector<glm::vec3> tmp_positions;
2015-11-06 16:40:21 -05:00
std::vector<glm::vec2> tmp_tex_coords;
2015-11-05 17:47:06 -05:00
std::vector<glm::vec3> tmp_normals;
2015-11-06 16:23:17 -05:00
size_t index = 0;
2015-11-06 16:40:21 -05:00
int attr_count = 0;
2015-11-05 14:17:04 -05:00
std::string line;
while (std::getline(file, line))
{
2015-11-05 17:47:06 -05:00
if (line.substr(0, 2) == "v ")
2015-11-05 14:17:04 -05:00
{
glm::vec3 v;
sscanf(line.data(), "v %f %f %f", &v.x, &v.y, &v.z);
2015-11-06 16:23:17 -05:00
tmp_positions.push_back(v);
2015-11-05 14:17:04 -05:00
}
else
2015-11-06 16:40:21 -05:00
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
2015-11-05 17:47:06 -05:00
if (line.substr(0, 3) == "vn ")
{
2015-11-06 16:40:21 -05:00
glm::vec3 vn;
sscanf(line.data(), "vn %f %f %f", &vn.x, &vn.y, &vn.z);
tmp_normals.push_back(vn);
2015-11-05 17:47:06 -05:00
}
else
if (line.substr(0, 2) == "f ")
2015-11-05 14:17:04 -05:00
{
2015-11-06 16:40:21 -05:00
if (attr_count == 0)
{
if (line.find("//") == std::string::npos)
attr_count = 3;
else
attr_count = 2;
}
2015-11-06 16:23:17 -05:00
GLushort v[3];
2015-11-06 16:40:21 -05:00
GLushort vt[3];
2015-11-06 16:23:17 -05:00
GLushort vn[3];
2015-11-06 16:40:21 -05:00
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]);
2015-11-06 16:23:17 -05:00
for (int i = 0; i < 3; ++i)
{
positions.push_back(tmp_positions[v[i] - 1]);
2015-11-06 16:40:21 -05:00
if (attr_count == 3)
tex_coords.push_back(tmp_tex_coords[vt[i] - 1]);
2015-11-06 16:23:17 -05:00
normals.push_back(tmp_normals[vn[i] - 1]);
2015-11-06 16:40:21 -05:00
elements.push_back(index++);
2015-11-06 16:23:17 -05:00
}
2015-11-05 14:17:04 -05:00
}
}
positions_id = create_array_buffer(GL_ARRAY_BUFFER, 3 * positions.size() * sizeof(GLfloat), positions.data());
2015-11-06 17:47:24 -05:00
2015-11-06 16:40:21 -05:00
if (attr_count == 3)
tex_coords_id = create_array_buffer(GL_ARRAY_BUFFER, 2 * tex_coords.size() * sizeof(GLfloat), tex_coords.data());
2015-11-06 17:47:24 -05:00
else
tex_coords_id = 0;
normals_id = create_array_buffer(GL_ARRAY_BUFFER, 3 * normals.size() * sizeof(GLfloat), normals.data());
2015-11-06 17:47:24 -05:00
2015-11-05 14:17:04 -05:00
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)
2015-11-04 17:52:34 -05:00
{
GLuint id;
glGenBuffers(1, &id);
2015-11-05 11:50:43 -05:00
glBindBuffer(type, id);
glBufferData(type, size, data, GL_STATIC_DRAW);
2015-11-04 17:52:34 -05:00
return id;
}
2015-11-05 14:17:04 -05:00
void Model::draw() const
{
glBindBuffer(GL_ARRAY_BUFFER, positions_id);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const GLvoid*>(0));
2015-11-06 17:47:24 -05:00
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<const GLvoid*>(0));
}
2015-11-05 14:17:04 -05:00
2015-11-05 17:47:06 -05:00
glBindBuffer(GL_ARRAY_BUFFER, normals_id);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const GLvoid*>(0));
2015-11-05 14:17:04 -05:00
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_id, 1, GL_FALSE, glm::value_ptr(transform));
_model.draw();
}
2015-11-06 17:47:24 -05:00
Texture::Texture(const char *const filename)
{
SDL_Surface *surface = IMG_Load(filename);
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);
}
2015-11-05 14:17:04 -05:00
Program build_program()
{
const Shader vertex_shader = Shader(GL_VERTEX_SHADER, "/data/shaders/vertex.glsl");
const Shader fragment_shader = Shader(GL_FRAGMENT_SHADER, "/data/shaders/fragment.glsl");
Program program;
program.attach_shader(vertex_shader);
program.attach_shader(fragment_shader);
program.bind_attrib_location(0, "position");
program.bind_attrib_location(1, "tex_coord");
2015-11-05 17:47:06 -05:00
program.bind_attrib_location(2, "normal");
2015-11-05 14:17:04 -05:00
program.link();
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
2015-11-05 17:47:06 -05:00
glEnableVertexAttribArray(2);
2015-11-05 14:17:04 -05:00
return program;
}
2015-11-03 10:40:20 -05:00
void iterate()
{
2015-11-04 16:33:53 -05:00
if (keys['W'])
{
pos_x += 0.1 * sin(glm::radians(delta_z));
pos_y += 0.1 * cos(glm::radians(delta_z));
}
if (keys['S'])
{
pos_x -= 0.1 * sin(glm::radians(delta_z));
pos_y -= 0.1 * cos(glm::radians(delta_z));
}
if (keys['A'])
{
pos_x -= 0.1 * cos(glm::radians(delta_z));
pos_y += 0.1 * sin(glm::radians(delta_z));
}
if (keys['D'])
{
pos_x += 0.1 * cos(glm::radians(delta_z));
pos_y -= 0.1 * sin(glm::radians(delta_z));
}
2015-11-04 14:39:44 -05:00
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2015-11-03 14:00:55 -05:00
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(-pos_x, -pos_y, -2.0f));
2015-11-04 13:38:02 -05:00
glm::mat4 view = glm::mat4(1.0f)
* glm::rotate(glm::mat4(1.0f), glm::radians(delta_x - 90), glm::vec3(1.0f, 0.0f, 0.0f))
* glm::rotate(glm::mat4(1.0f), glm::radians(delta_z), glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 projection = glm::perspective(45.0f, (float)640 / (float)480, 0.1f, 10.0f);
glm::mat4 mvp = projection * view * model;
2015-11-06 17:47:24 -05:00
glBindTexture(GL_TEXTURE_2D, 0);
2015-11-05 17:00:00 -05:00
cube1->draw(mvp);
2015-11-06 17:47:24 -05:00
suzanne_tex->use();
2015-11-05 14:17:04 -05:00
suzanne1->draw(mvp);
2015-11-06 17:47:24 -05:00
glBindTexture(GL_TEXTURE_2D, 0);
2015-11-05 14:17:04 -05:00
teapot1->draw(mvp);
2015-11-06 17:47:24 -05:00
bunny_tex->use();
2015-11-05 14:17:04 -05:00
bunny1->draw(mvp);
2015-11-03 06:46:05 -05:00
}
2015-11-04 13:38:02 -05:00
GLFWCALL void on_key(int key, int action)
{
keys[key] = action != GLFW_RELEASE;
}
2015-11-04 13:38:02 -05:00
EM_BOOL on_em_mousemove(int event_type, const EmscriptenMouseEvent *mouse_event, void *user_data)
{
delta_z += mouse_event->movementX;
delta_x += mouse_event->movementY;
if (delta_z < 0)
delta_z = 359;
else
if (delta_z >= 360)
delta_z = 0;
if (delta_x < -90)
delta_x = -90;
else
if (delta_x > 90)
delta_x = 90;
return true;
}