#include "game.h" /* Remember to free the result! */ char* get_source(const char *filename){ FILE *source_file = fopen(filename, "r"); fseek(source_file, 0, SEEK_END); long length = ftell(source_file); char *source = (char*)malloc(length + 1); rewind(source_file); fread(source, 1, length, source_file); fclose(source_file); source[length] = 0; return source; } bool operator==(const vertex& a, const vertex& o){ return a.x == o.x && a.y == o.y && a.z == o.z && a.u == o.u && a.v == o.v; } namespace std { template<> struct hash { size_t operator()(vertex const& v) const { size_t vals[] = {(size_t)(v.x * 100000), (size_t)(v.y * 10000), (size_t)(v.z * 1000), (size_t)(v.u * 100), (size_t)v.v}; size_t result = vals[0]; for(auto v : vals) result = result ^ v; return result; } }; } void GameObject::add_location(vec3 location){ models.push_back(translate(mat4(1.0), location)); } bool GameObject::init(){ tinyobj::attrib_t attrib; vector shapes; vector materials; string warn, err; if(!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, object_file.c_str())){ printf("Loading failed for: %s\n%s\n", object_file.c_str(), err.c_str()); return false; } vector vertices; vector elements; unordered_map unique_vertices; for(const auto& shape : shapes){ for(const auto& index : shape.mesh.indices){ vertex new_vertex; new_vertex.x = attrib.vertices[3 * index.vertex_index + 0]; // x coordinate if(flip_yz){ new_vertex.z = attrib.vertices[3 * index.vertex_index + 1]; // y coordinate new_vertex.y = attrib.vertices[3 * index.vertex_index + 2]; // z coordinate } else { new_vertex.y = attrib.vertices[3 * index.vertex_index + 1]; // y coordinate new_vertex.z = attrib.vertices[3 * index.vertex_index + 2]; // z coordinate } new_vertex.u = attrib.texcoords[2 * index.texcoord_index + 0]; // u coordinate new_vertex.v = 1.0f - attrib.texcoords[2 * index.texcoord_index + 1]; // v coordinate if(unique_vertices.count(new_vertex) == 0){ unique_vertices[new_vertex] = (unsigned int)vertices.size(); vertices.push_back(new_vertex); } elements.push_back(unique_vertices[new_vertex]); } } element_count = elements.size(); printf("Element count: %lu\n", elements.size()); // Format: xyzuv glGenBuffers(1, &vbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, 20 * vertices.size(), vertices.data(), GL_STATIC_DRAW); glGenBuffers(1, &ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * elements.size(), elements.data(), GL_STATIC_DRAW); /* Setup texture here */ int img_width, img_height; unsigned char* image = stbi_load(texture_file.c_str(), &img_width, &img_height, 0, STBI_rgb); if(!image){ printf("image failed to load: %s\n", texture_file.c_str()); return false; } else { printf("Image size is %d by %d\n", img_width, img_height); } 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, img_width, img_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); free(image); glGenBuffers(1, &models_buffer); char *source = get_source("shaders/vertex_shader.glsl"); puts(source); unsigned int vs_reference = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs_reference, 1, (const char**)&source, 0); glCompileShader(vs_reference); glGetShaderInfoLog(vs_reference, 2048, NULL, source); puts(source); free(source); int compile_ok; glGetShaderiv(vs_reference, GL_COMPILE_STATUS, &compile_ok); if(!compile_ok){ printf("Vertex shader failed to compile\n"); return false; } source = get_source("shaders/fragment_shader.glsl"); puts(source); unsigned int fs_reference = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs_reference, 1, (const char**)&source, 0); glCompileShader(fs_reference); glGetShaderInfoLog(fs_reference, 2048, NULL, source); puts(source); glGetShaderiv(fs_reference, GL_COMPILE_STATUS, &compile_ok); if(!compile_ok){ printf("Fragment shader failed to compile\n"); return false; } free(source); program = glCreateProgram(); glAttachShader(program, vs_reference); glAttachShader(program, fs_reference); glLinkProgram(program); int link_ok; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); glGetProgramInfoLog(program, 2048, NULL, source); puts(source); if(!link_ok){ printf("Link failure\n"); return false; } v_attrib = glGetAttribLocation(program, "in_vertex"); tc_attrib = glGetAttribLocation(program, "in_texcoord"); vp_uniform = glGetUniformLocation(program, "vp"); return true; } void GameObject::draw(mat4 vp){ static int count; count++; glUseProgram(program); glEnableVertexAttribArray(v_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(v_attrib, 3, GL_FLOAT, GL_FALSE, 20, 0); glEnableVertexAttribArray(tc_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(tc_attrib, 2, GL_FLOAT, GL_FALSE, 20, (const void*)12); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glBindBuffer(GL_SHADER_STORAGE_BUFFER, models_buffer); glBufferData(GL_SHADER_STORAGE_BUFFER, models.size() * sizeof(mat4), models.data(), GL_DYNAMIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, models_buffer); /* This is for a specific object again */ glUniformMatrix4fv(vp_uniform, 1, 0, value_ptr(vp)); glDrawElementsInstanced(GL_TRIANGLES, element_count, GL_UNSIGNED_INT, 0, models.size()); }