|
From: Lasse Kärkkäi. <tr...@us...> - 2011-02-24 02:48:10
|
Author: Lasse Kärkkäinen <tronic+ndrm at trn.iki.fi> Date: Thu Feb 24 03:16:18 2011 +0100 Rewrite 3dobject for glutil::VertexArray, fix OBJ parser bugs, add glmath::Vec4 support for VA. --- game/3dobject.cc | 111 +++++++++++++----------------------------------------- game/3dobject.hh | 42 ++------------------ game/glshader.hh | 18 +++++++- 3 files changed, 45 insertions(+), 126 deletions(-) diff --git a/game/3dobject.cc b/game/3dobject.cc index 379c28e..8e921c1 100644 --- a/game/3dobject.cc +++ b/game/3dobject.cc @@ -24,41 +24,43 @@ namespace { } } +/// A polygon containing links to required point data +struct Face { + std::vector<int> vertices; + std::vector<int> texcoords; + std::vector<int> normals; +}; + /// Load a Wavefront .obj file and possibly scale it also void Object3d::loadWavefrontObj(std::string filepath, float scale) { int linenumber = 0; std::string row; std::ifstream file(filepath.c_str(), std::ios::binary); if (!file.is_open()) throw std::runtime_error("Couldn't open object file "+filepath); - // Get rid of old data - m_vertices.clear(); - m_faces.clear(); - m_texcoords.clear(); - while (!file.eof()) { - getline(file, row); // Read a line + std::vector<glmath::Vec4> m_vertices, m_normals, m_texcoords; + std::vector<Face> m_faces; + while (getline(file, row)) { ++linenumber; std::istringstream srow(row); float x,y,z; std::string tempst; if (row.substr(0,2) == "v ") { // Vertices srow >> tempst >> x >> y >> z; - m_vertices.push_back(Vertex(x*scale,y*scale,z*scale)); + m_vertices.push_back(glmath::Vec4(x*scale, y*scale, z*scale, 1.0f)); } else if (row.substr(0,2) == "vt") { // Texture Coordinates srow >> tempst >> x >> y; - m_texcoords.push_back(TexCoord(x,y)); + m_texcoords.push_back(glmath::Vec4(x, y, 0.0f, 0.0f)); } else if (row.substr(0,2) == "vn") { // Normals srow >> tempst >> x >> y >> z; double sum = std::abs(x)+std::abs(y)+std::abs(z); if (sum == 0) throw std::runtime_error("Invalid normal in "+filepath+":"+boost::lexical_cast<std::string>(linenumber)); x /= sum; y /= sum; z /= sum; // Normalize components - m_normals.push_back(Vertex(x,y,z)); + m_normals.push_back(glmath::Vec4(x, y, z, 0.0)); } else if (row.substr(0,2) == "f ") { // Faces Face f; srow >> tempst; // Eat away prefix // Parse face point's coordinate references - while (!srow.eof()) { - std::string fpoint; - srow >> fpoint; + for (std::string fpoint; srow >> fpoint; ) { for (size_t i = 1; i <= 3; ++i) { std::string st_id(getWord(fpoint,i,'/')); if (!st_id.empty()) { @@ -86,82 +88,21 @@ void Object3d::loadWavefrontObj(std::string filepath, float scale) { } } } + // Construct a vertex array + for (std::vector<Face>::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i) { + bool hasNormals = !i->normals.empty(); + bool hasTexCoords = !i->texcoords.empty(); + for (size_t j = 0; j < i->vertices.size(); ++j) { + if (hasNormals) m_va.Normal(m_normals[i->normals[j]]); + if (hasTexCoords) m_va.TexCoord(m_texcoords[i->texcoords[j]]); + m_va.Vertex(m_vertices[i->vertices[j]]); + } + } + } void Object3d::drawVBO() { UseShader us(getShader("3dobject")); - int stride = 3*sizeof(GLfloat); - int offset = 0; - if (m_vboStructure & HAS_TEXCOORDS) stride += 2*sizeof(GLfloat); - if (m_vboStructure & HAS_NORMALS) stride += 3*sizeof(GLfloat); - - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, stride, (const GLvoid *)offset); - offset += 3*sizeof(GLfloat); - - if (m_vboStructure & HAS_NORMALS) { - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, stride, (const GLvoid *)offset); - offset += 3*sizeof(GLfloat); - } - - if (m_vboStructure & HAS_TEXCOORDS) { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, stride, (const GLvoid *)offset); - } - - glDrawArrays(m_polyType, 0, m_numvertices); - - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - glBindBuffer(GL_ARRAY_BUFFER, 0); + m_va.Draw(GL_TRIANGLES); } -void Object3d::generateVBO() { - std::vector<GLfloat> data; - - if (m_vbo != 0) glDeleteBuffers(1, &m_vbo); - glGenBuffers(1, &m_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - - // TODO: We should tessellate everything into triangles somehow - // in order to allow non-triangle based meshes. - m_polyType = GL_TRIANGLES; - m_numvertices = m_faces.size() * 3; // Triangle faces - - m_vboStructure = 0; - if (!m_texcoords.empty()) m_vboStructure |= HAS_TEXCOORDS; - if (!m_normals.empty()) m_vboStructure |= HAS_NORMALS; - - std::vector<Face>::const_iterator i; - for (i = m_faces.begin(); i != m_faces.end(); ++i) { - for (size_t j = 0; j < i->vertices.size(); ++j) { - data.push_back(m_vertices[i->vertices[j]].x); - data.push_back(m_vertices[i->vertices[j]].y); - data.push_back(m_vertices[i->vertices[j]].z); - - if (m_vboStructure & HAS_NORMALS) { - data.push_back(m_normals[i->normals[j]].x); - data.push_back(m_normals[i->normals[j]].y); - data.push_back(m_normals[i->normals[j]].z); - } - - if (m_vboStructure & HAS_TEXCOORDS) { - data.push_back(m_texcoords[i->texcoords[j]].s); - data.push_back(m_texcoords[i->texcoords[j]].t); - } - } - } - - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*data.size(), &data.front(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - data.clear(); - m_vertices.clear(); - m_normals.clear(); - m_texcoords.clear(); - m_faces.clear(); -} diff --git a/game/3dobject.hh b/game/3dobject.hh index ef99f11..1479c3b 100644 --- a/game/3dobject.hh +++ b/game/3dobject.hh @@ -5,64 +5,30 @@ #include <boost/scoped_ptr.hpp> #include <boost/noncopyable.hpp> #include "surface.hh" +#include "glshader.hh" #include "glutil.hh" // TODO: Exception handling // TODO: Texture loading -/// Point in 3d space -struct Vertex { - Vertex(float x = 0, float y = 0, float z = 0): x(x), y(y), z(z) {} - float x; - float y; - float z; -}; - -/// 2d texture coordinate -struct TexCoord { - TexCoord(float s = 0, float t = 0): s(s), t(t) {} - float s; - float t; -}; - -/// A polygon containing links to required point data -struct Face { - std::vector<int> vertices; - std::vector<int> texcoords; - std::vector<int> normals; -}; - /// A class representing 3d object /// Non-copyable because of display lists getting messed up class Object3d: boost::noncopyable { private: - std::vector<Vertex> m_vertices; /// vertices - std::vector<TexCoord> m_texcoords; /// texture coordinates - std::vector<Vertex> m_normals; /// normals - std::vector<Face> m_faces; /// faces - GLuint m_vbo; - GLuint m_polyType; - int m_vboStructure; - int m_numvertices; + glutil::VertexArray m_va; boost::scoped_ptr<Texture> m_texture; /// texture /// load a Wavefront .obj 3d object file void loadWavefrontObj(std::string filepath, float scale = 1.0); - void generateVBO(); public: + Object3d() {} /// constructors - Object3d(): m_vbo(0) {}; - Object3d(std::string filepath, std::string texturepath = "", float scale = 1.0): m_vbo(0) { + Object3d(std::string filepath, std::string texturepath = "", float scale = 1.0) { load(filepath, texturepath, scale); } - /// destructor - ~Object3d() { - if (m_vbo != 0) glDeleteBuffers(1, &m_vbo); - } /// load a new object file void load(std::string filepath, std::string texturepath = "", float scale = 1.0) { if (!texturepath.empty()) m_texture.reset(new Texture(texturepath)); loadWavefrontObj(filepath, scale); - generateVBO(); } void drawVBO(); /// draws the object diff --git a/game/glshader.hh b/game/glshader.hh index bfd0d44..4a2ae25 100644 --- a/game/glshader.hh +++ b/game/glshader.hh @@ -121,19 +121,31 @@ namespace glutil { VertexArray() {} VertexArray& Vertex(float x, float y, float z = 0.0f) { - m_vert.position = glmath::Vec4(x, y, z, 1.0f); + return Vertex(glmath::Vec4(x, y, z, 1.0f)); + } + + VertexArray& Vertex(glmath::Vec4 const& v) { + m_vert.position = v; m_vertices.push_back(m_vert); m_vert = VertexInfo(); return *this; } VertexArray& Normal(float x, float y, float z) { - m_vert.normal = glmath::Vec4(x, y, z, 1.0f); + return Normal(glmath::Vec4(x, y, z, 1.0f)); + } + + VertexArray& Normal(glmath::Vec4 const& v) { + m_vert.normal = v; return *this; } VertexArray& TexCoord(float s, float t, float u = 0.0f, float v = 0.0f) { - m_vert.texCoord = glmath::Vec4(s, t, u, v); + return TexCoord(glmath::Vec4(s, t, u, v)); + } + + VertexArray& TexCoord(glmath::Vec4 const& v) { + m_vert.texCoord = v; return *this; } |