#include "mesh.h" #include #include #include "sparrowrenderer.h" #include "material.h" #include "buffer.h" const char* const Mesh::flagStr[Mesh::NB_FLAGS] = { "INDEXED", "TEXTURABLE", "INSTANCED", "MESH_3D", "MESH_2D", "TANGENT_SPACE", "BILLBOARD", "COLOR_TEXTURE", "ALPHA_MASK", "PHONG", "DIFFUSE_TEXTURE", "AMBIENT_TEXTURE", "SPECULAR_TEXTURE", "NORMAL_MAP", "BUMP_MAP" }; Mesh::Mesh() : material(NULL), isDoubleSided(false), isBillboard(false), depth(0), vao(0), primitive_type(GL_TRIANGLES) { clearBuffers(); } Mesh::~Mesh() { destroyGL(); } void Mesh::addBuffer(Buffer *b, int bufferType) { buffersId[bufferType] = buffers.size(); buffers.push_back(b); } void Mesh::clearBuffers() { for(int i=0; isetVertexAttrib(0, 3); addBuffer(b, POSITION_BUFFER); // init normals vbo if(!normals.empty()) { b = new Buffer(normals, Buffer::VBO); b->setVertexAttrib(1, 3); addBuffer(b, NORMAL_BUFFER); } // init tangents vbo if(!tangents.empty()) { b = new Buffer(tangents, Buffer::VBO); b->setVertexAttrib(3, 3); b->setVertexAttrib(4, 3); addBuffer(b, TANGENT_BUFFER); } } else if(!positions2D.empty()) { b = new Buffer(positions2D, Buffer::VBO); b->setVertexAttrib(0, 2); addBuffer(b, POSITION_BUFFER); } else { fprintf(stderr, "ERROR : Mesh can't be initialized without position data"); return; } // init texCoords vbo if(!texCoords.empty()) { b = new Buffer(texCoords, Buffer::VBO); b->setVertexAttrib(2, 2); addBuffer(b, TEXCOORD_BUFFER); } // init instances vbo if(!instances_offsets.empty()) { b = new Buffer(instances_offsets, Buffer::VBO); b->setVertexAttrib(5, 3, 0, 1); addBuffer(b, INSTANCE_BUFFER); } // init EBO if(!indices.empty()) { b = new Buffer(indices, Buffer::EBO); addBuffer(b, INDICES_BUFFER); } // unbind vao glBindVertexArray(0); } void Mesh::draw(Shader* shader, bool drawNormals, bool drawTexCoord, bool drawTangents) { if(isDoubleSided) glDisable(GL_CULL_FACE); bool crappy = (shader == NULL); material->bindAttributes(shader); glBindVertexArray(vao); if(crappy) { Buffer *b = buffers[buffersId[POSITION_BUFFER]]; b->bind(); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)); // TODO : check 2D positions if(!texCoords.empty() && drawTexCoord) { b = buffers[buffersId[TEXCOORD_BUFFER]]; b->bind(); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0)); } if(!normals.empty() && drawNormals) { b = buffers[buffersId[NORMAL_BUFFER]]; b->bind(); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 0, BUFFER_OFFSET(0)); } b->unbind(); } if(indices.empty()) { int size = positions3D.empty() ? positions2D.size() : positions3D.size(); if(!instances_offsets.empty() && !crappy) glDrawArraysInstanced(primitive_type, 0, size, instances_offsets.size()); else glDrawArrays(primitive_type, 0, size); } else { Buffer *b = buffers[buffersId[INDICES_BUFFER]]; b->bind(); if(!instances_offsets.empty() && !crappy) glDrawElementsInstanced(primitive_type, indices.size(), GL_UNSIGNED_INT, NULL, instances_offsets.size()); else glDrawElements(primitive_type, indices.size(), GL_UNSIGNED_INT, NULL); b->unbind(); } if(crappy) { glDisableClientState(GL_VERTEX_ARRAY); if(!normals.empty() && drawNormals) glDisableClientState(GL_NORMAL_ARRAY); if(!texCoords.empty() && drawTexCoord) glDisableClientState(GL_TEXTURE_COORD_ARRAY); } glBindVertexArray(0); if(isDoubleSided) glEnable(GL_CULL_FACE); } void Mesh::destroyGL() { if(vao != 0) { glDeleteVertexArrays(1, &vao); vao = 0; } clearBuffers(); } unsigned int Mesh::getFlags() { unsigned int flags = material->getFlags(); if(!indices.empty()) flags |= 1 << MESH_INDEXED; if(!texCoords.empty()) flags |= 1 << MESH_TEXTURABLE; if(!instances_offsets.empty()) flags |= 1 << MESH_INSTANCED; if(!positions3D.empty()) { flags |= 1 << MESH_3D; if(!tangents.empty()) flags |= 1 << MESH_TANGENT_SPACE; if(isBillboard) flags |= 1 << MESH_BILLBOARD; } else flags |= 1 << MESH_2D; return flags; } struct VertexComparator { // c'est plutot crade mais j'ai pas trouve d'autre moyen pour le moment static Mesh* mesh; static void setMesh(Mesh* m) {VertexComparator::mesh = m;} bool operator() (const int& vertId1, const int& vertId2) const { if(mesh->positions3D[vertId1].x != mesh->positions3D[vertId2].x) return (mesh->positions3D[vertId1].x < mesh->positions3D[vertId2].x); if(mesh->positions3D[vertId1].y != mesh->positions3D[vertId2].y) return (mesh->positions3D[vertId1].y < mesh->positions3D[vertId2].y); if(mesh->positions3D[vertId1].z != mesh->positions3D[vertId2].z) return (mesh->positions3D[vertId1].z < mesh->positions3D[vertId2].z); if(!mesh->texCoords.empty()) { if(mesh->texCoords[vertId1].x != mesh->texCoords[vertId2].x) return (mesh->texCoords[vertId1].x < mesh->texCoords[vertId2].x); if(mesh->texCoords[vertId1].y != mesh->texCoords[vertId2].y) return (mesh->texCoords[vertId1].y < mesh->texCoords[vertId2].y); } if(!mesh->normals.empty()) { if(mesh->normals[vertId1].x != mesh->normals[vertId2].x) return (mesh->normals[vertId1].x < mesh->normals[vertId2].x); if(mesh->normals[vertId1].y != mesh->normals[vertId2].y) return (mesh->normals[vertId1].y < mesh->normals[vertId2].y); if(mesh->normals[vertId1].z != mesh->normals[vertId2].z) return (mesh->normals[vertId1].z < mesh->normals[vertId2].z); } return false; } }; Mesh* VertexComparator::mesh = NULL; void Mesh::mergeVertices() { if(positions3D.empty()) return; bool *deleted = new bool[positions3D.size()]; int *offsets = new int[positions3D.size()]; std::set vertexSet; VertexComparator::setMesh(this); for(std::size_t i=0; i::iterator,bool> ret = vertexSet.insert(indices[i]); deleted[indices[i]] = !ret.second && *(ret.first) != indices[i]; if(deleted[indices[i]]) { if(!tangents.empty()) { tangents[*(ret.first)].tangent += tangents[indices[i]].tangent; tangents[*(ret.first)].binormal += tangents[indices[i]].binormal; } indices[i] = *(ret.first); } } int offset = 0; int pos = 0; for(std::size_t i=0; i(positions3D.size()); for (std::size_t j=0; j < indices.size(); j += 3) { int vertexId0 = indices[j]; int vertexId1 = indices[j+1]; int vertexId2 = indices[j+2]; const glm::vec3 &v1 = positions3D[vertexId0]; const glm::vec3 &v2 = positions3D[vertexId1]; const glm::vec3 &v3 = positions3D[vertexId2]; const glm::vec2& w1 = texCoords[vertexId0]; const glm::vec2& w2 = texCoords[vertexId1]; const glm::vec2& w3 = texCoords[vertexId2]; float x1 = v2.x - v1.x; float x2 = v3.x - v1.x; float y1 = v2.y - v1.y; float y2 = v3.y - v1.y; float z1 = v2.z - v1.z; float z2 = v3.z - v1.z; float s1 = w2.x - w1.x; float s2 = w3.x - w1.x; float t1 = w2.y - w1.y; float t2 = w3.y - w1.y; float r = 1.0f / (s1 * t2 - s2 * t1); glm::vec3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); glm::vec3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); Tangents& tan1 = tangents[vertexId0]; Tangents& tan2 = tangents[vertexId1]; Tangents& tan3 = tangents[vertexId2]; tan1.tangent += sdir; tan2.tangent += sdir; tan3.tangent += sdir; tan1.binormal += tdir; tan2.binormal += tdir; tan3.binormal += tdir; } }