]> git.localhorst.tv Git - blank.git/commitdiff
use indices for model rendering
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 9 Mar 2015 23:11:21 +0000 (00:11 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 9 Mar 2015 23:14:16 +0000 (00:14 +0100)
src/block.cpp
src/block.hpp
src/chunk.cpp
src/chunk.hpp
src/hud.cpp
src/model.cpp
src/model.hpp
src/shape.cpp
src/shape.hpp

index e22d3e63d8ce309f71903a00a69cb985461483dc..50c4a4ffd9040c136f6bfcdebff4704dc8fcdb33 100644 (file)
@@ -5,23 +5,22 @@ namespace blank {
 
 const NullShape BlockType::DEFAULT_SHAPE;
 
-void BlockType::FillVBO(
-       const glm::vec3 &pos,
-       std::vector<glm::vec3> &vertices,
-       std::vector<glm::vec3> &colors,
-       std::vector<glm::vec3> &normals
+void BlockType::FillModel(
+       Model &model,
+       const glm::vec3 &pos_offset,
+       Model::Index idx_offset
 ) const {
-       shape->Vertices(vertices, pos);
-       colors.insert(colors.end(), shape->VertexCount(), color);
-       shape->Normals(normals);
+       shape->Vertices(model.vertices, model.normals, model.indices, pos_offset, idx_offset);
+       model.colors.insert(model.colors.end(), shape->VertexCount(), color);
 }
 
-void BlockType::FillOutlineVBO(
-       std::vector<glm::vec3> &vertices,
-       std::vector<glm::vec3> &colors
+void BlockType::FillOutlineModel(
+       OutlineModel &model,
+       const glm::vec3 &pos_offset,
+       OutlineModel::Index idx_offset
 ) const {
-       shape->Outline(vertices);
-       colors.insert(colors.end(), shape->OutlineCount(), outline_color);
+       shape->Outline(model.vertices, model.indices, pos_offset, idx_offset);
+       model.colors.insert(model.colors.end(), shape->OutlineCount(), outline_color);
 }
 
 
index 0f567c4b5fdf3400b5209ed64c76766a00f4fb88..1c1dddb10c3e4377f6e5d1b6617be38eedf00674 100644 (file)
@@ -32,29 +32,17 @@ struct BlockType {
        static const NullShape DEFAULT_SHAPE;
 
 
-       void FillVBO(
-               const glm::vec3 &pos,
-               std::vector<glm::vec3> &vertices,
-               std::vector<glm::vec3> &colors,
-               std::vector<glm::vec3> &normals
+       void FillModel(
+               Model &m,
+               const glm::vec3 &pos_offset = { 0, 0, 0 },
+               Model::Index idx_offset = 0
        ) const;
-
-       void FillModel(const glm::vec3 &pos, Model &m) const {
-               FillVBO(pos, m.vertices, m.colors, m.normals);
-               m.Invalidate();
-       }
-
-
-       void FillOutlineVBO(
-               std::vector<glm::vec3> &vertices,
-               std::vector<glm::vec3> &colors
+       void FillOutlineModel(
+               OutlineModel &m,
+               const glm::vec3 &pos_offset = { 0, 0, 0 },
+               OutlineModel::Index idx_offset = 0
        ) const;
 
-       void FillOutlineModel(OutlineModel &m) const {
-               FillOutlineVBO(m.vertices, m.colors);
-               m.Invalidate();
-       }
-
 };
 
 
index e52a19f81d2c4898681f2213adfa4dc0e2b6fde2..52d17c055319464479f8d1d7b248044de024cf52 100644 (file)
@@ -111,20 +111,21 @@ glm::mat4 Chunk::Transform(const Pos &offset) const {
 }
 
 
-int Chunk::VertexCount() const {
-       int count = 0;
+void Chunk::Update() {
+       int vtx_count = 0, idx_count = 0;
        for (const auto &block : blocks) {
-               count += Type(block).shape->VertexCount();
+               const Shape *shape = Type(block).shape;
+               vtx_count += shape->VertexCount();
+               idx_count += shape->VertexIndexCount();
        }
-       return count;
-}
-
-void Chunk::Update() {
        model.Clear();
-       model.Reserve(VertexCount());
+       model.Reserve(vtx_count, idx_count);
 
+       Model::Index vtx_counter = 0;
        for (size_t i = 0; i < Size(); ++i) {
-               Type(blocks[i]).FillModel(ToCoords(i), model);
+               const BlockType &type = Type(blocks[i]);
+               type.FillModel(model, ToCoords(i), vtx_counter);
+               vtx_counter += type.shape->VertexCount();
        }
 
        model.Invalidate();
index 28ba4e357aa6a87137b62ecfdc61b73a6205f17a..5c1cadb38d50f1222253d26b123b916a28170b3e 100644 (file)
@@ -75,7 +75,6 @@ public:
        void Draw();
 
 private:
-       int VertexCount() const;
        void Update();
 
 private:
index ed5767dfeac9216f995c28351755ca94397dce5a..d60401199e10f453096534c9f9685fef8c47fab5 100644 (file)
@@ -27,6 +27,9 @@ HUD::HUD()
                { -10.0f,   0.0f, 0.0f }, { 10.0f,  0.0f, 0.0f },
                {   0.0f, -10.0f, 0.0f }, {  0.0f, 10.0f, 0.0f },
        });
+       crosshair.indices = std::vector<OutlineModel::Index>({
+               0, 1, 2, 3
+       });
        crosshair.colors.resize(4, { 10.0f, 10.0f, 10.0f });
        crosshair.Invalidate();
 }
@@ -44,7 +47,7 @@ void HUD::Viewport(float x, float y, float width, float height) {
 
 void HUD::Display(const BlockType &type) {
        block.Clear();
-       type.FillModel({ 0.0f, 0.0f, 0.0f }, block);
+       type.FillModel(block);
        block_visible = type.visible;
 }
 
index 08b29242b1b185a90c60d54ec59e3b58b2fa4edf..0e358c5585c62300d9a7aae3abe0e52da8a18863 100644 (file)
@@ -33,6 +33,7 @@ Model &Model::operator =(Model &&other) {
        vertices = std::move(other.vertices);
        colors = std::move(other.colors);
        normals = std::move(other.normals);
+       indices = std::move(other.indices);
        for (int i = 0; i < ATTRIB_COUNT; ++i) {
                std::swap(handle[i], other.handle[i]);
        }
@@ -45,13 +46,15 @@ void Model::Clear() {
        vertices.clear();
        colors.clear();
        normals.clear();
+       indices.clear();
        Invalidate();
 }
 
-void Model::Reserve(int s) {
-       vertices.reserve(s);
-       colors.reserve(s);
-       normals.reserve(s);
+void Model::Reserve(int v, int i) {
+       vertices.reserve(v);
+       colors.reserve(v);
+       normals.reserve(v);
+       indices.reserve(i);
 }
 
 
@@ -77,6 +80,9 @@ void Model::Update() {
        glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_NORMAL]);
        glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
 
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
+       glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(Index), indices.data(), GL_STATIC_DRAW);
+
        dirty = false;
 }
 
@@ -119,10 +125,12 @@ void Model::Draw() {
                nullptr        // offset
        );
 
-       glDrawArrays(
-               GL_TRIANGLES,   // how
-               0,              // start
-               vertices.size() // len
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
+       glDrawElements(
+               GL_TRIANGLES,      // how
+               indices.size(),    // count
+               GL_UNSIGNED_INT, // type
+               nullptr            // offset
        );
 
        glDisableVertexAttribArray(ATTRIB_NORMAL);
@@ -134,6 +142,7 @@ void Model::Draw() {
 OutlineModel::OutlineModel()
 : vertices()
 , colors()
+, indices()
 , handle{}
 , dirty(false) {
        glGenBuffers(ATTRIB_COUNT, handle);
@@ -147,12 +156,14 @@ OutlineModel::~OutlineModel() {
 void OutlineModel::Clear() {
        vertices.clear();
        colors.clear();
+       indices.clear();
        Invalidate();
 }
 
-void OutlineModel::Reserve(int s) {
-       vertices.reserve(s);
-       colors.reserve(s);
+void OutlineModel::Reserve(int v, int i) {
+       vertices.reserve(v);
+       colors.reserve(v);
+       indices.reserve(i);
 }
 
 
@@ -169,6 +180,9 @@ void OutlineModel::Update() {
        glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_COLOR]);
        glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_STATIC_DRAW);
 
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
+       glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(Index), indices.data(), GL_STATIC_DRAW);
+
        dirty = false;
 }
 
@@ -203,10 +217,12 @@ void OutlineModel::Draw() {
        glEnable(GL_LINE_SMOOTH);
        glLineWidth(2.0f);
 
-       glDrawArrays(
-               GL_LINES,       // how
-               0,              // start
-               vertices.size() // len
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
+       glDrawElements(
+               GL_LINES,          // how
+               indices.size(),    // count
+               GL_UNSIGNED_SHORT, // type
+               nullptr            // offset
        );
 
        glDisableVertexAttribArray(ATTRIB_COLOR);
index 4423cd7115338f671847d2461def60ffd11454cd..6e9583b3ec84f6ae05c7f1beaeeaa05b7e36e75b 100644 (file)
@@ -10,10 +10,14 @@ namespace blank {
 
 class Model {
 
+public:
+       using Index = unsigned int;
+
 public:
        std::vector<glm::vec3> vertices;
        std::vector<glm::vec3> colors;
        std::vector<glm::vec3> normals;
+       std::vector<Index> indices;
 
 public:
        Model();
@@ -28,7 +32,7 @@ public:
        void Invalidate() { dirty = true; }
 
        void Clear();
-       void Reserve(int);
+       void Reserve(int vtx_count, int idx_count);
 
        void Draw();
 
@@ -40,6 +44,7 @@ private:
                ATTRIB_VERTEX,
                ATTRIB_COLOR,
                ATTRIB_NORMAL,
+               ATTRIB_INDEX,
                ATTRIB_COUNT,
        };
 
@@ -51,9 +56,13 @@ private:
 
 class OutlineModel {
 
+public:
+       using Index = unsigned short;
+
 public:
        std::vector<glm::vec3> vertices;
        std::vector<glm::vec3> colors;
+       std::vector<Index> indices;
 
 public:
        OutlineModel();
@@ -65,7 +74,7 @@ public:
        void Invalidate() { dirty = true; }
 
        void Clear();
-       void Reserve(int);
+       void Reserve(int vtx_count, int idx_count);
 
        void Draw();
 
@@ -76,6 +85,7 @@ private:
        enum Attribute {
                ATTRIB_VERTEX,
                ATTRIB_COLOR,
+               ATTRIB_INDEX,
                ATTRIB_COUNT,
        };
 
index e8bd2e6f42a01bb8f8c728614bbd0fa7d5e59e35..615b8f9cc719088d8ff405e3638b9ce4312d4918 100644 (file)
 
 namespace blank {
 
-size_t NullShape::VertexCount() const {
-       return 0;
-}
-
-void NullShape::Vertices(std::vector<glm::vec3> &out, const glm::vec3 &pos) const {
+NullShape::NullShape()
+: Shape(0, 0, 0, 0) {
 
 }
 
-void NullShape::Normals(std::vector<glm::vec3> &out) const {
+void NullShape::Vertices(
+       std::vector<glm::vec3> &,
+       std::vector<glm::vec3> &,
+       std::vector<Model::Index> &,
+       const glm::vec3 &,
+       Model::Index
+) const {
 
 }
 
-size_t NullShape::OutlineCount() const {
-       return 0;
-}
-
-void NullShape::Outline(std::vector<glm::vec3> &out, const glm::vec3 &pos) const {
+void NullShape::Outline(
+       std::vector<glm::vec3> &,
+       std::vector<OutlineModel::Index> &,
+       const glm::vec3 &,
+       OutlineModel::Index
+) const {
 
 }
 
-bool NullShape::Intersects(const Ray &, const glm::mat4 &, float &, glm::vec3 &) const {
+bool NullShape::Intersects(
+       const Ray &,
+       const glm::mat4 &,
+       float &, glm::vec3 &
+) const {
        return false;
 }
 
 
 CuboidShape::CuboidShape(const AABB &b)
-: Shape()
+: Shape(24, 36, 8, 24)
 , bb(b) {
        bb.Adjust();
 }
 
-
-size_t CuboidShape::VertexCount() const {
-       return 36;
-}
-
-void CuboidShape::Vertices(std::vector<glm::vec3> &out, const glm::vec3 &pos) const {
-       out.reserve(36);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z); // front
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // back
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z); // top
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // bottom
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // left
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z); // right
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
+void CuboidShape::Vertices(
+       std::vector<glm::vec3> &vtx,
+       std::vector<glm::vec3> &norm,
+       std::vector<Model::Index> &index,
+       const glm::vec3 &pos,
+       Model::Index idx
+) const {
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z); // front
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // back
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z); // top
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // bottom
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // left
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z); // right
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
+
+       norm.insert(norm.end(), 4, glm::vec3( 0.0f,  0.0f,  1.0f)); // front
+       norm.insert(norm.end(), 4, glm::vec3( 0.0f,  0.0f, -1.0f)); // back
+       norm.insert(norm.end(), 4, glm::vec3( 0.0f,  1.0f,  0.0f)); // top
+       norm.insert(norm.end(), 4, glm::vec3( 0.0f, -1.0f,  0.0f)); // bottom
+       norm.insert(norm.end(), 4, glm::vec3(-1.0f,  0.0f,  0.0f)); // left
+       norm.insert(norm.end(), 4, glm::vec3( 1.0f,  0.0f,  0.0f)); // right
+
+       index.emplace_back(idx +  0); // front
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  4); // back
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx +  8); // top
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx + 11);
+       index.emplace_back(idx + 12); // bottom
+       index.emplace_back(idx + 13);
+       index.emplace_back(idx + 14);
+       index.emplace_back(idx + 14);
+       index.emplace_back(idx + 13);
+       index.emplace_back(idx + 15);
+       index.emplace_back(idx + 16); // left
+       index.emplace_back(idx + 17);
+       index.emplace_back(idx + 18);
+       index.emplace_back(idx + 18);
+       index.emplace_back(idx + 17);
+       index.emplace_back(idx + 19);
+       index.emplace_back(idx + 20); // right
+       index.emplace_back(idx + 21);
+       index.emplace_back(idx + 22);
+       index.emplace_back(idx + 22);
+       index.emplace_back(idx + 21);
+       index.emplace_back(idx + 23);
 }
 
-void CuboidShape::Normals(std::vector<glm::vec3> &out) const {
-       out.reserve(36);
-       out.insert(out.end(), 6, glm::vec3( 0.0f,  0.0f,  1.0f)); // front
-       out.insert(out.end(), 6, glm::vec3( 0.0f,  0.0f, -1.0f)); // back
-       out.insert(out.end(), 6, glm::vec3( 0.0f,  1.0f,  0.0f)); // top
-       out.insert(out.end(), 6, glm::vec3( 0.0f, -1.0f,  0.0f)); // bottom
-       out.insert(out.end(), 6, glm::vec3(-1.0f,  0.0f,  0.0f)); // left
-       out.insert(out.end(), 6, glm::vec3( 1.0f,  0.0f,  0.0f)); // right
-}
-
-
-size_t CuboidShape::OutlineCount() const {
-       return 24;
+void CuboidShape::Outline(
+       std::vector<glm::vec3> &vtx,
+       std::vector<OutlineModel::Index> &index,
+       const glm::vec3 &pos,
+       OutlineModel::Index idx
+) const {
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z); // back
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z); // front
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
+       vtx.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
+
+       index.emplace_back(idx +  0); // back
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  0);
+       index.emplace_back(idx +  4); // front
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  4);
+       index.emplace_back(idx +  0); // sides
+       index.emplace_back(idx +  4);
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  7);
 }
 
-void CuboidShape::Outline(std::vector<glm::vec3> &out, const glm::vec3 &pos) const {
-       out.reserve(24);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.min.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.min.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.max.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.max.y, pos.z + bb.max.z);
-       out.emplace_back(pos.x + bb.min.x, pos.y + bb.min.y, pos.z + bb.max.z);
-}
-
-bool CuboidShape::Intersects(const Ray &ray, const glm::mat4 &M, float &dist, glm::vec3 &normal) const {
+bool CuboidShape::Intersects(
+       const Ray &ray,
+       const glm::mat4 &M,
+       float &dist, glm::vec3 &normal
+) const {
        return Intersection(ray, bb, M, &dist, &normal);
 }
 
 
 StairShape::StairShape(const AABB &bb, const glm::vec2 &clip)
-: top({ { clip.x, clip.y, bb.min.z }, bb.max })
+: Shape(40, 60, 12, 36)
+, top({ { clip.x, clip.y, bb.min.z }, bb.max })
 , bot({ bb.min, { bb.max.x, clip.y, bb.max.z } }) {
 
 }
 
 
-size_t StairShape::VertexCount() const {
-       return 60;
-}
-
-void StairShape::Vertices(std::vector<glm::vec3> &out, const glm::vec3 &pos) const {
-       out.reserve(60);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.max.z); // front, upper
-       out.emplace_back(pos.x + top.max.x, pos.y + top.min.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.min.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z); // front, lower
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.min.z); // back, upper
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.min.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.min.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // back, lower
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z); // top, upper
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z); // top, lower
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // bottom
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.min.z); // left, upper
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // left, lower
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z); // right
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
-       out.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.max.z);
-}
-
-void StairShape::Normals(std::vector<glm::vec3> &out) const {
-       out.reserve(60);
-       out.insert(out.end(), 12, glm::vec3( 0.0f,  0.0f,  1.0f)); // front, x2
-       out.insert(out.end(), 12, glm::vec3( 0.0f,  0.0f, -1.0f)); // back, x2
-       out.insert(out.end(), 12, glm::vec3( 0.0f,  1.0f,  0.0f)); // top, x2
-       out.insert(out.end(),  6, glm::vec3( 0.0f, -1.0f,  0.0f)); // bottom
-       out.insert(out.end(), 12, glm::vec3(-1.0f,  0.0f,  0.0f)); // left, x2
-       out.insert(out.end(),  6, glm::vec3( 1.0f,  0.0f,  0.0f)); // right
-}
-
-
-size_t StairShape::OutlineCount() const {
-       return 36;
+void StairShape::Vertices(
+       std::vector<glm::vec3> &vtx,
+       std::vector<glm::vec3> &norm,
+       std::vector<Model::Index> &index,
+       const glm::vec3 &pos,
+       Model::Index idx
+) const {
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.max.z); // front, upper
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.min.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z); // front, lower
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.max.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.min.z); // back, upper
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z);
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.min.y, pos.z + top.min.z);
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // back, lower
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.max.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z); // top, upper
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z); // top, lower
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // bottom
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.min.z); // left, upper
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // left, lower
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z); // right
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.max.z);
+
+       norm.insert(norm.end(), 8, glm::vec3( 0.0f,  0.0f,  1.0f)); // front, x2
+       norm.insert(norm.end(), 8, glm::vec3( 0.0f,  0.0f, -1.0f)); // back, x2
+       norm.insert(norm.end(), 8, glm::vec3( 0.0f,  1.0f,  0.0f)); // top, x2
+       norm.insert(norm.end(), 4, glm::vec3( 0.0f, -1.0f,  0.0f)); // bottom
+       norm.insert(norm.end(), 8, glm::vec3(-1.0f,  0.0f,  0.0f)); // left, x2
+       norm.insert(norm.end(), 4, glm::vec3( 1.0f,  0.0f,  0.0f)); // right
+
+       index.emplace_back(idx +  0); // front, upper
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  4); // front, lower
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx +  8); // back, upper
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx + 11);
+       index.emplace_back(idx + 12); // back, lower
+       index.emplace_back(idx + 13);
+       index.emplace_back(idx + 14);
+       index.emplace_back(idx + 14);
+       index.emplace_back(idx + 13);
+       index.emplace_back(idx + 15);
+       index.emplace_back(idx + 16); // top, upper
+       index.emplace_back(idx + 17);
+       index.emplace_back(idx + 18);
+       index.emplace_back(idx + 18);
+       index.emplace_back(idx + 17);
+       index.emplace_back(idx + 19);
+       index.emplace_back(idx + 20); // top, lower
+       index.emplace_back(idx + 21);
+       index.emplace_back(idx + 22);
+       index.emplace_back(idx + 22);
+       index.emplace_back(idx + 21);
+       index.emplace_back(idx + 23);
+       index.emplace_back(idx + 24); // bottom
+       index.emplace_back(idx + 25);
+       index.emplace_back(idx + 26);
+       index.emplace_back(idx + 26);
+       index.emplace_back(idx + 25);
+       index.emplace_back(idx + 27);
+       index.emplace_back(idx + 28); // left, upper
+       index.emplace_back(idx + 29);
+       index.emplace_back(idx + 30);
+       index.emplace_back(idx + 30);
+       index.emplace_back(idx + 29);
+       index.emplace_back(idx + 31);
+       index.emplace_back(idx + 32); // left, lower
+       index.emplace_back(idx + 33);
+       index.emplace_back(idx + 34);
+       index.emplace_back(idx + 34);
+       index.emplace_back(idx + 33);
+       index.emplace_back(idx + 35);
+       index.emplace_back(idx + 36); // right
+       index.emplace_back(idx + 37);
+       index.emplace_back(idx + 38);
+       index.emplace_back(idx + 38);
+       index.emplace_back(idx + 37);
+       index.emplace_back(idx + 39);
 }
 
-void StairShape::Outline(std::vector<glm::vec3> &out, const glm::vec3 &pos) const {
-       out.reserve(36);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // bottom
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z); // middle
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + bot.min.z); // top
-       out.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // verticals, ltr/btf
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.min.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
-       out.emplace_back(pos.x + bot.max.x, pos.y + top.max.y, pos.z + bot.max.z);
+void StairShape::Outline(
+       std::vector<glm::vec3> &vtx,
+       std::vector<OutlineModel::Index> &index,
+       const glm::vec3 &pos,
+       OutlineModel::Index idx
+) const {
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.min.z); // bottom
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.max.x, pos.y + bot.min.y, pos.z + bot.max.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + bot.min.z); // middle
+       vtx.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + bot.min.z);
+       vtx.emplace_back(pos.x + bot.min.x, pos.y + bot.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + bot.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.min.z); // top
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.min.z);
+       vtx.emplace_back(pos.x + top.min.x, pos.y + top.max.y, pos.z + top.max.z);
+       vtx.emplace_back(pos.x + top.max.x, pos.y + top.max.y, pos.z + top.max.z);
+
+       index.emplace_back(idx +  0); // bottom
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  0);
+       index.emplace_back(idx +  4); // middle
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  4);
+       index.emplace_back(idx +  8); // top
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx + 11);
+       index.emplace_back(idx + 11);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx +  8);
+       index.emplace_back(idx +  0); // verticals
+       index.emplace_back(idx +  4);
+       index.emplace_back(idx +  2);
+       index.emplace_back(idx +  6);
+       index.emplace_back(idx +  5);
+       index.emplace_back(idx +  8);
+       index.emplace_back(idx +  7);
+       index.emplace_back(idx + 10);
+       index.emplace_back(idx +  1);
+       index.emplace_back(idx +  9);
+       index.emplace_back(idx +  3);
+       index.emplace_back(idx + 11);
 }
 
-bool StairShape::Intersects(const Ray &ray, const glm::mat4 &M, float &dist, glm::vec3 &norm) const {
+bool StairShape::Intersects(
+       const Ray &ray,
+       const glm::mat4 &M,
+       float &dist,
+       glm::vec3 &norm
+) const {
        float top_dist, bot_dist;
        glm::vec3 top_norm, bot_norm;
        bool top_hit = Intersection(ray, top, M, &top_dist, &top_norm);
index 66827d08b27c1c1ed5064be731b1f7dca54adc90..af19bb12e8ccfbf75fd6205f1e5fecf08e30b6fe 100644 (file)
@@ -2,6 +2,7 @@
 #define BLANK_SHAPE_HPP_
 
 #include "geometry.hpp"
+#include "model.hpp"
 
 #include <vector>
 #include <glm/glm.hpp>
@@ -11,14 +12,55 @@ namespace blank {
 
 struct Shape {
 
-       virtual size_t VertexCount() const = 0;
-       virtual void Vertices(std::vector<glm::vec3> &, const glm::vec3 &pos = { 0.0f, 0.0f, 0.0f }) const = 0;
-       virtual void Normals(std::vector<glm::vec3> &) const = 0;
+       /// the number of vertices (and normals) this shape has
+       size_t VertexCount() const { return vtx; }
+       /// the number of vertex indices this shape has
+       size_t VertexIndexCount() const { return vtx_idx; }
+
+       /// fill given buffers with this shape's elements with an
+       /// optional offset
+       virtual void Vertices(
+               std::vector<glm::vec3> &vertex,
+               std::vector<glm::vec3> &normal,
+               std::vector<Model::Index> &index,
+               const glm::vec3 &elem_offset = { 0.0f, 0.0f, 0.0f },
+               Model::Index idx_offset = 0
+       ) const = 0;
+
+       /// the number of vertices this shape's outline has
+       size_t OutlineCount() const { return outl; }
+       /// the number of vertex indices this shape's outline has
+       size_t OutlineIndexCount() const { return outl_idx; }
+
+       /// fill given buffers with this shape's outline's elements with
+       /// an optional offset
+       virtual void Outline(
+               std::vector<glm::vec3> &vertex,
+               std::vector<OutlineModel::Index> &index,
+               const glm::vec3 &offset = { 0.0f, 0.0f, 0.0f },
+               OutlineModel::Index idx_offset = 0
+       ) const = 0;
+
+       /// Check if given ray would pass though this shape if it were
+       /// transformed with given matrix.
+       /// If true, dist and normal hold the intersection distance and
+       /// normal, otherwise their content is undefined.
+       virtual bool Intersects(
+               const Ray &,
+               const glm::mat4 &,
+               float &dist,
+               glm::vec3 &normal
+       ) const = 0;
+
+protected:
+       Shape(size_t vtx, size_t vtx_idx, size_t outl, size_t outl_idx)
+       : vtx(vtx), vtx_idx(vtx_idx), outl(outl), outl_idx(outl_idx) { }
 
-       virtual size_t OutlineCount() const = 0;
-       virtual void Outline(std::vector<glm::vec3> &, const glm::vec3 &pos = { 0.0f, 0.0f, 0.0f }) const = 0;
-
-       virtual bool Intersects(const Ray &, const glm::mat4 &, float &dist, glm::vec3 &normal) const = 0;
+private:
+       size_t vtx;
+       size_t vtx_idx;
+       size_t outl;
+       size_t outl_idx;
 
 };
 
@@ -27,12 +69,22 @@ class NullShape
 : public Shape {
 
 public:
-       size_t VertexCount() const override;
-       void Vertices(std::vector<glm::vec3> &, const glm::vec3 &) const override;
-       void Normals(std::vector<glm::vec3> &) const override;
-
-       size_t OutlineCount() const override;
-       void Outline(std::vector<glm::vec3> &, const glm::vec3 &) const override;
+       NullShape();
+
+       void Vertices(
+               std::vector<glm::vec3> &vertex,
+               std::vector<glm::vec3> &normal,
+               std::vector<Model::Index> &index,
+               const glm::vec3 &elem_offset = { 0.0f, 0.0f, 0.0f },
+               Model::Index idx_offset = 0
+       ) const override;
+
+       void Outline(
+               std::vector<glm::vec3> &vertex,
+               std::vector<OutlineModel::Index> &index,
+               const glm::vec3 &offset = { 0.0f, 0.0f, 0.0f },
+               OutlineModel::Index idx_offset = 0
+       ) const override;
 
        bool Intersects(const Ray &, const glm::mat4 &, float &, glm::vec3 &) const override;
 
@@ -45,12 +97,20 @@ class CuboidShape
 public:
        CuboidShape(const AABB &bounds);
 
-       size_t VertexCount() const override;
-       void Vertices(std::vector<glm::vec3> &, const glm::vec3 &) const override;
-       void Normals(std::vector<glm::vec3> &) const override;
-
-       size_t OutlineCount() const override;
-       void Outline(std::vector<glm::vec3> &, const glm::vec3 &) const override;
+       void Vertices(
+               std::vector<glm::vec3> &vertex,
+               std::vector<glm::vec3> &normal,
+               std::vector<Model::Index> &index,
+               const glm::vec3 &elem_offset = { 0.0f, 0.0f, 0.0f },
+               Model::Index idx_offset = 0
+       ) const override;
+
+       void Outline(
+               std::vector<glm::vec3> &vertex,
+               std::vector<OutlineModel::Index> &index,
+               const glm::vec3 &offset = { 0.0f, 0.0f, 0.0f },
+               OutlineModel::Index idx_offset = 0
+       ) const override;
 
        bool Intersects(const Ray &, const glm::mat4 &, float &, glm::vec3 &) const override;
 
@@ -66,12 +126,20 @@ class StairShape
 public:
        StairShape(const AABB &bounds, const glm::vec2 &clip);
 
-       size_t VertexCount() const override;
-       void Vertices(std::vector<glm::vec3> &, const glm::vec3 &) const override;
-       void Normals(std::vector<glm::vec3> &) const override;
-
-       size_t OutlineCount() const override;
-       void Outline(std::vector<glm::vec3> &, const glm::vec3 &) const override;
+       void Vertices(
+               std::vector<glm::vec3> &vertex,
+               std::vector<glm::vec3> &normal,
+               std::vector<Model::Index> &index,
+               const glm::vec3 &elem_offset = { 0.0f, 0.0f, 0.0f },
+               Model::Index idx_offset = 0
+       ) const override;
+
+       void Outline(
+               std::vector<glm::vec3> &vertex,
+               std::vector<OutlineModel::Index> &index,
+               const glm::vec3 &offset = { 0.0f, 0.0f, 0.0f },
+               OutlineModel::Index idx_offset = 0
+       ) const override;
 
        bool Intersects(const Ray &, const glm::mat4 &, float &, glm::vec3 &) const override;