From 8ca7805512f01e8f05ea664e7bb9983ac0728403 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 15 Jan 2011 18:29:52 +0000 Subject: [PATCH] Simplify mesh buffer interface --- include/IMesh.hpp | 24 +----- include/Maths.hpp | 6 ++ src/Map.cpp | 6 +- src/Mesh.cpp | 206 +++++++++++----------------------------------- src/Model.cpp | 26 +++++- 5 files changed, 80 insertions(+), 188 deletions(-) diff --git a/include/IMesh.hpp b/include/IMesh.hpp index 61f7f08..60a4027 100644 --- a/include/IMesh.hpp +++ b/include/IMesh.hpp @@ -23,18 +23,6 @@ #include "ITexture.hpp" #include "Colour.hpp" -// Represent OpenGL materials -struct Material { - Material(); - - void apply() const; - - float diffuseR, diffuseG, diffuseB; - float ambientR, ambientG, ambientB; - float specularR, specularG, specularB; - ITexturePtr texture; -}; - // Represents the vertices, normals, etc. in a mesh struct IMeshBuffer { typedef Vector Vertex; @@ -46,17 +34,11 @@ struct IMeshBuffer { virtual size_t vertex_count() const = 0; - virtual void add(const Vertex& vertex, const Normal& normal) = 0; - virtual void add(const Vertex& vertex, const Normal& normal, - const TexCoord& a_tex_coord, - const Colour& colour = make_colour(1.0f, 1.0f, 1.0f)) = 0; + const Colour& colour = make_colour(1.0f, 1.0f, 1.0f), + const TexCoord& tex_coord = make_point(0.0f, 0.0f)) = 0; - virtual void add(const Vertex& vertex, - const Normal& normal, - const Colour& colour) = 0; - // Convenience functions virtual void add_quad(Vertex a, Vertex b, Vertex c, Vertex d, Colour colour) = 0; @@ -64,7 +46,7 @@ struct IMeshBuffer { Normal na, Normal nb, Normal nc, Normal nd, Colour colour) = 0; - virtual void bind_material(const Material& a_material) = 0; + virtual void bind(ITexturePtr texture) = 0; virtual void print_stats() const = 0; diff --git a/include/Maths.hpp b/include/Maths.hpp index 0f30f76..4e2eecb 100644 --- a/include/Maths.hpp +++ b/include/Maths.hpp @@ -81,6 +81,12 @@ struct EqTolerance { static const int Value = 0; }; +template +inline bool approx_equal(T a, T b) +{ + return abs(a - b) <= EqTolerance::Value; +} + // A generic 3D vector template struct Vector { diff --git a/src/Map.cpp b/src/Map.cpp index f16180c..a1eae4d 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -645,9 +645,7 @@ void Map::build_mesh(int id, Point bot_left, Point top_right) IMeshBufferPtr buf = make_mesh_buffer(); - Material m; - m.texture = load_texture("test.png"); - buf->bind_material(m); + buf->bind(load_texture("test.png")); // Incrementing the frame counter here ensures that any track which spans // multiple sectors will be merged with each applicable mesh even when @@ -686,7 +684,7 @@ void Map::build_mesh(int id, Point bot_left, Point top_right) hcol = colour_map[j++]; } while (get<0>(hcol) > h); - buf->add(v.pos, v.normal, tex_order[i], get<1>(hcol)); + buf->add(v.pos, v.normal, get<1>(hcol), tex_order[i]); } } } diff --git a/src/Mesh.cpp b/src/Mesh.cpp index cc72c6d..402c8b3 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -43,13 +43,10 @@ struct MeshBuffer : IMeshBuffer { size_t vertex_count() const { return vertices.size(); } - void add(const Vertex& vertex, const Normal& normal); void add(const Vertex& vertex, const Normal& normal, - const TexCoord& a_tex_coord, - const Colour& colour); - void add(const Vertex& vertex, const Normal& normal, - const Colour& colour); + const Colour& colour, + const TexCoord& tex_coord); void add_quad(Vertex a, Vertex b, Vertex c, Vertex d, Colour colour); @@ -57,7 +54,7 @@ struct MeshBuffer : IMeshBuffer { Normal na, Normal nb, Normal nc, Normal nd, Colour colour); - void bind_material(const Material& a_material); + void bind(ITexturePtr texture); void merge(IMeshBufferPtr other, Vector off, float y_angle); void print_stats() const; @@ -77,22 +74,19 @@ struct MeshBuffer : IMeshBuffer { vector colours; vector indices; vector tex_coords; - bool has_texture, has_material; - Material material; + ITexturePtr texture; int reused; }; MeshBuffer::MeshBuffer() - : has_texture(false), has_material(false), reused(0) + : reused(0) { } -void MeshBuffer::bind_material(const Material& a_material) +void MeshBuffer::bind(ITexturePtr tex) { - material = a_material; - has_texture = a_material.texture; - has_material = true; + texture = tex; } void MeshBuffer::merge(IMeshBufferPtr other, Vector off, float y_angle) @@ -115,7 +109,7 @@ void MeshBuffer::merge(IMeshBufferPtr other, Vector off, float y_angle) vertices.push_back(compose.transform(v)); normals.push_back(rotate.transform(n).normalise()); - if (obuf.has_texture) { + if (obuf.texture) { colours.push_back(colour::WHITE); } else { @@ -141,104 +135,31 @@ void MeshBuffer::print_stats() const << reused << " reused"; } -void MeshBuffer::add(const Vertex& vertex, const Normal& normal) -{ - if (!has_material) - throw runtime_error("MeshBuffer::add called without colour on a mesh " - " without a material"); - - // See if this vertex has already been added - for (vector::iterator it = indices.begin(); - it != indices.end(); ++it) { - if (merge_vector(vertex, vertices[*it]) - && merge_vector(normal, normals[*it])) { - - const Colour& other = colours[*it]; - if (abs(other.r - material.diffuseR) < 0.01f - && abs(other.g - material.diffuseG) < 0.01f - && abs(other.b - material.diffuseB) < 0.01f) { - - indices.push_back(*it); - reused++; - return; - } - } - } - - const size_t index = vertices.size(); - vertices.push_back(vertex); - normals.push_back(normal); - indices.push_back(index); - colours.push_back( - make_colour(material.diffuseR, - material.diffuseG, - material.diffuseB)); -} - -void MeshBuffer::add(const Vertex& vertex, const Normal& normal, - const Colour& colour) -{ -#if 0 - if (has_texture) - throw runtime_error("MeshBuffer::add called without texture coordinate " - "on a mesh which has a texture"); - - if (has_material) - throw runtime_error("MeshBuffer::add called with a colour on a mesh " - " with a material"); -#endif - - // See if this vertex has already been added - for (vector::iterator it = indices.begin(); - it != indices.end(); ++it) { - - assert(*it < vertices.size()); - assert(*it < normals.size()); - - if (merge_vector(vertex, vertices[*it]) - && merge_vector(normal, normals[*it])) { - - const Colour& other = colours[*it]; - if (abs(other.r - colour.r) < 0.01f - && abs(other.g - colour.g) < 0.01f - && abs(other.b - colour.b) < 0.01f) { - - indices.push_back(*it); - reused++; - return; - } - } - } - - const size_t index = vertices.size(); - vertices.push_back(vertex); - normals.push_back(normal); - colours.push_back(colour); - indices.push_back(index); -} - void MeshBuffer::add(const Vertex& vertex, const Normal& normal, - const TexCoord& a_tex_coord, - const Colour& colour) + const Colour& colour, + const TexCoord& a_tex_coord) { - if (!has_texture) - throw runtime_error( - "MeshBuffer::add called with a texture coordinate " - "on a mesh without a texture"); - // See if this vertex has already been added for (vector::iterator it = indices.begin(); it != indices.end(); ++it) { if (merge_vector(vertex, vertices[*it]) && merge_vector(normal, normals[*it])) { - TexCoord& tc = tex_coords[*it]; - if (abs(tc.x - a_tex_coord.x) < 0.001f - && abs(tc.y - a_tex_coord.y) < 0.001f) { - indices.push_back(*it); + + const TexCoord& tc = tex_coords[*it]; + const bool same_tc = (approx_equal(tc.x, a_tex_coord.x) + && approx_equal(tc.y, a_tex_coord.y)); + + const Colour& c = colours[*it]; + const bool same_col = (approx_equal(c.r, colour.r) + && approx_equal(c.g, colour.g) + && approx_equal(c.b, colour.b)); + + if (same_col && same_tc) { + indices.push_back(*it); reused++; return; - } + } } } @@ -256,63 +177,30 @@ void MeshBuffer::add_quad(Vertex a, Vertex b, Vertex c, Vector n1 = surface_normal(b, c, d); Vector n2 = surface_normal(d, a, b); - add(b, n1, colour); - add(c, n1, colour); - add(d, n1, colour); + const TexCoord nulltc = make_point(0.0f, 0.0f); + + add(b, n1, colour, nulltc); + add(c, n1, colour, nulltc); + add(d, n1, colour, nulltc); - add(d, n2, colour); - add(a, n2, colour); - add(b, n2, colour); + add(d, n2, colour, nulltc); + add(a, n2, colour, nulltc); + add(b, n2, colour, nulltc); } void MeshBuffer::add_quad(Vertex a, Vertex b, Vertex c, Vertex d, Normal na, Normal nb, Normal nc, Normal nd, Colour colour) { - - add(b, na, colour); - add(c, nb, colour); - add(d, nc, colour); - - add(d, nd, colour); - add(a, na, colour); - add(b, nb, colour); -} - -// Default material -Material::Material() - : diffuseR(1.0f), diffuseG(1.0f), diffuseB(1.0f), - ambientR(1.0f), ambientG(1.0f), ambientB(1.0f), - specularR(0.0f), specularG(0.0f), specularB(0.0f) -{ -} - -void Material::apply() const -{ - if (texture) { - glEnable(GL_TEXTURE_2D); - texture->bind(); - - glEnable(GL_COLOR_MATERIAL); - glColor3f(1.0f, 1.0f, 1.0f); - } - else { - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_TEXTURE_2D); - - float diffuse[] = { diffuseR, diffuseG, diffuseB, 1.0 }; - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); + const TexCoord nulltc = make_point(0.0f, 0.0f); - float ambient[] = { ambientR, ambientG, ambientB, 1.0 }; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); - - // Note we're ignoring the specular values in the model - float specular[] = { 0, 0, 0, 1.0 }; - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular); - - float emission[] = { 0, 0, 0, 1 }; - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emission); - } + add(b, na, colour, nulltc); + add(c, nb, colour, nulltc); + add(d, nc, colour, nulltc); + + add(d, nd, colour, nulltc); + add(a, na, colour, nulltc); + add(b, nb, colour, nulltc); } // Packed vertex data used by vertex array and VBO mesh implementations @@ -340,7 +228,7 @@ static void copy_vertex_data(const MeshBuffer* buf, VertexData* vertex_data) vd->ny = buf->normals[i].y; vd->nz = buf->normals[i].z; - if (buf->has_texture) { + if (buf->texture) { vd->tx = buf->tex_coords[i].x; vd->ty = 1.0f - buf->tex_coords[i].y; } @@ -371,7 +259,7 @@ VertexArrayMesh::VertexArrayMesh(IMeshBufferPtr a_buffer) { const MeshBuffer* buf = MeshBuffer::get(a_buffer); - texture = buf->material.texture; + texture = buf->texture; my_vertex_count = buf->vertices.size(); my_vertex_data = new VertexData[my_vertex_count]; @@ -451,7 +339,7 @@ VBOMesh::VBOMesh(IMeshBufferPtr a_buffer) // Get the data out of the buffer; const MeshBuffer* buf = MeshBuffer::get(a_buffer); - texture = buf->material.texture; + texture = buf->texture; const size_t vertex_count = buf->vertices.size(); VertexData* p_vertex_data = new VertexData[vertex_count]; @@ -546,15 +434,15 @@ void VBOMesh::render() const ::triangle_count += index_count / 3; } -IMeshPtr make_mesh(IMeshBufferPtr a_buffer) +IMeshPtr make_mesh(IMeshBufferPtr buffer) { - //a_buffer->print_stats(); + buffer->print_stats(); // Prefer VBOs for all meshes - if (GLEW_ARB_vertex_buffer_object && false) - return IMeshPtr(new VBOMesh(a_buffer)); + if (GLEW_ARB_vertex_buffer_object) + return IMeshPtr(new VBOMesh(buffer)); else - return IMeshPtr(new VertexArrayMesh(a_buffer)); + return IMeshPtr(new VertexArrayMesh(buffer)); } IMeshBufferPtr make_mesh_buffer() diff --git a/src/Model.cpp b/src/Model.cpp index 7327194..9a725a9 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -1,5 +1,5 @@ // -// Copyright (C) 2009-2010 Nick Gasson +// Copyright (C) 2009-2011 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -42,6 +42,19 @@ namespace { ModelCache the_cache; } +struct Material { + Material() + : diffuseR(1.0f), diffuseG(1.0f), diffuseB(1.0f), + ambientR(1.0f), ambientG(1.0f), ambientB(1.0f), + specularR(0.0f), specularG(0.0f), specularB(0.0f) + {} + + float diffuseR, diffuseG, diffuseB; + float ambientR, ambientG, ambientB; + float specularR, specularG, specularB; + ITexturePtr texture; +}; + // Abstracts a WaveFront material file class MaterialFile { public: @@ -195,6 +208,7 @@ IModelPtr load_model(IResourcePtr a_res, int face_count = 0; MaterialFilePtr material_file; + Material active_mtl; ifstream& f = h.rstream(); @@ -276,7 +290,7 @@ IModelPtr load_model(IResourcePtr a_res, if (material_file) { assert(buffer); - buffer->bind_material(material_file->get(material_name)); + active_mtl = material_file->get(material_name); } } else if (first == "f") { @@ -313,12 +327,16 @@ IModelPtr load_model(IResourcePtr a_res, assert(buffer); + const Colour col = make_colour(active_mtl.diffuseR, + active_mtl.diffuseG, + active_mtl.diffuseB); + if (vti - 1 < texture_offs.size()) { Point& vt = texture_offs[vti - 1]; - buffer->add(v, vn, vt); + buffer->add(v, vn, col, vt); } else - buffer->add(v, vn); + buffer->add(v, vn, col); } face_count++; -- 2.39.2