#include "engine.h" bool GameObject::init_from_object(const char *objfilename, vec3 (*input_transform)(float x, float y, float z)) { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; std::string warn, err; vector vertices; vector indices; if(!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, objfilename)) throw std::runtime_error(err); unordered_map uniqueVertices = {}; for(const auto& shape : shapes){ for(const auto& index : shape.mesh.indices){ Vertex vertex = {}; if(input_transform){ vertex.pos = input_transform(attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2]); } else { vertex.pos = { attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2] }; } vertex.texCoord = { attrib.texcoords[2 * index.texcoord_index + 0], 1.0 - attrib.texcoords[2 * index.texcoord_index + 1] }; if(uniqueVertices.count(vertex) == 0){ uniqueVertices[vertex] = (uint32_t)vertices.size(); vertices.push_back(vertex); } indices.push_back(uniqueVertices[vertex]); } } float *non_padded_vertex = (float*)malloc(3 * sizeof(float) * vertices.size()); float *non_padded_texture = (float*)malloc(2 * sizeof(float) * vertices.size()); for(size_t i = 0; i < vertices.size(); i++){ non_padded_vertex[i*3 + 0] = vertices[i].pos.x; non_padded_vertex[i*3 + 1] = vertices[i].pos.y; non_padded_vertex[i*3 + 2] = vertices[i].pos.z; non_padded_texture[i*2 + 0] = vertices[i].texCoord.x; non_padded_texture[i*2 + 1] = vertices[i].texCoord.y; } glGenBuffers(1, &vbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * sizeof(float) * vertices.size(), non_padded_vertex, GL_STATIC_DRAW); free(non_padded_vertex); std::cout << "Loaded " << vertices.size() << " Vertices\n"; glGenBuffers(1, &tbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, tbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, 2 * sizeof(float) * vertices.size(), non_padded_texture, GL_STATIC_DRAW); free(non_padded_texture); glGenBuffers(1, &ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), indices.data(), GL_STATIC_DRAW); element_count = indices.size(); std::cout << "Loaded " << indices.size() << " Indexes\n"; return true; } void GameObject::draw_object(const mat4 &vp) { glUseProgram(program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glUniform1i(tex_uniform, 0); glUniformMatrix4fv(mvp_uniform, 1, 0, glm::value_ptr(vp)); glEnableVertexAttribArray(vertex_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(vertex_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(tex_attrib); glBindBuffer(GL_ARRAY_BUFFER, tbuf); glVertexAttribPointer(tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, lbuf); glDrawElementsInstanced(GL_TRIANGLES, element_count, GL_UNSIGNED_INT, 0, locations.size()); } bool GameObject::setup_shaders(const char *vertex, const char *fragment){ vertex_shader = make_shader(vertex, GL_VERTEX_SHADER); fragment_shader = make_shader(fragment, GL_FRAGMENT_SHADER); if(!(vertex_shader && fragment_shader)) return 0; program = glCreateProgram(); glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glLinkProgram(program); GLint link_ok; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if(!link_ok){ glGetProgramInfoLog(program, GBLEN, NULL, general_buffer); puts(general_buffer); puts(RED("Link Failed").c_str()); return false; } return true; } bool GameObject::setup_standard_shaders(){ if(generic_program == -1){ setup_shaders("cube_vertex.glsl", "cube_fragment.glsl"); generic_program = program; } else program = generic_program; vertex_attrib = glGetAttribLocation(program, "in_vertex"); tex_attrib = glGetAttribLocation(program, "in_texcoord"); mvp_uniform = glGetUniformLocation(program, "mvp"); tex_uniform = glGetUniformLocation(program, "tex"); return true; } bool GameObject::setup_texture(const char *filename){ int texwidth, texheight; unsigned char *image_data = SOIL_load_image(filename, &texwidth, &texheight, 0, SOIL_LOAD_RGB); printf("Loaded texture %d by %d\n", texwidth, texheight); if(!image_data) return false; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texwidth, texheight, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data); free(image_data); return true; }