+++ /dev/null
-#ifndef BLANK_GRAPHICS_OUTLINEMESH_HPP_
-#define BLANK_GRAPHICS_OUTLINEMESH_HPP_
-
-#include "VertexArray.hpp"
-
-#include <vector>
-#include <GL/glew.h>
-#include <glm/glm.hpp>
-
-
-namespace blank {
-
-class OutlineMesh {
-
-public:
-       using Position = glm::vec3;
-       using Color = glm::vec3;
-       using Index = unsigned short;
-
-       using Positions = std::vector<Position>;
-       using Colors = std::vector<Color>;
-       using Indices = std::vector<Index>;
-
-       enum Attribute {
-               ATTRIB_VERTEX,
-               ATTRIB_COLOR,
-               ATTRIB_INDEX,
-               ATTRIB_COUNT,
-       };
-
-       struct Buffer {
-
-               Positions vertices;
-               Colors colors;
-               Indices indices;
-
-               void Clear() noexcept {
-                       vertices.clear();
-                       colors.clear();
-                       indices.clear();
-               }
-
-               void Reserve(size_t p, size_t i) {
-                       vertices.reserve(p);
-                       colors.reserve(p);
-                       indices.reserve(i);
-               }
-
-       };
-
-       using VAO = VertexArray<ATTRIB_COUNT>;
-
-public:
-       void Update(const Buffer &) noexcept;
-
-       void Draw() noexcept;
-
-private:
-       VAO vao;
-
-};
-
-}
-
-#endif
 
--- /dev/null
+#ifndef BLANK_GRAPHICS_PRIMITIVEMESH_HPP_
+#define BLANK_GRAPHICS_PRIMITIVEMESH_HPP_
+
+#include "VertexArray.hpp"
+
+#include <vector>
+#include <GL/glew.h>
+#include <glm/glm.hpp>
+
+
+namespace blank {
+
+class PrimitiveMesh {
+
+public:
+       using Position = glm::vec3;
+       using Color = glm::vec4;
+       using Index = unsigned short;
+
+       using Positions = std::vector<Position>;
+       using Colors = std::vector<Color>;
+       using Indices = std::vector<Index>;
+
+       enum Attribute {
+               ATTRIB_VERTEX,
+               ATTRIB_COLOR,
+               ATTRIB_INDEX,
+               ATTRIB_COUNT,
+       };
+
+       struct Buffer {
+
+               Positions vertices;
+               Colors colors;
+               Indices indices;
+
+               void Clear() noexcept {
+                       vertices.clear();
+                       colors.clear();
+                       indices.clear();
+               }
+
+               void Reserve(size_t p, size_t i) {
+                       vertices.reserve(p);
+                       colors.reserve(p);
+                       indices.reserve(i);
+               }
+
+               void FillRect(
+                       float w, float h,
+                       const glm::vec4 &color = glm::vec4(0.0f),
+                       const glm::vec2 &pivot = glm::vec2(0.0f)
+               );
+
+       };
+
+       using VAO = VertexArray<ATTRIB_COUNT>;
+
+public:
+       void Update(const Buffer &) noexcept;
+
+       void DrawLines() noexcept;
+       void DrawTriangles() noexcept;
+
+private:
+       VAO vao;
+
+};
+
+}
+
+#endif
 
        BlockLighting &ChunkProgram() noexcept;
        DirectionalLighting &EntityProgram() noexcept;
        DirectionalLighting &HUDProgram() noexcept;
-       PlainColor &WorldOutlineProgram() noexcept;
-       PlainColor &HUDOutlineProgram() noexcept;
+       PlainColor &WorldColorProgram() noexcept;
+       PlainColor &HUDColorProgram() noexcept;
        SkyBoxShader &SkyBoxProgram() noexcept;
        BlendedSprite &SpriteProgram() noexcept;
 
 
        BlockLighting chunk_prog;
        DirectionalLighting entity_prog;
-       PlainColor outline_prog;
+       PlainColor color_prog;
        SkyBoxShader sky_prog;
        BlendedSprite sprite_prog;
 
                CHUNK,
                ENTITY,
                HUD,
-               OUTLINE_WORLD,
-               OUTLINE_HUD,
+               COLOR_WORLD,
+               COLOR_HUD,
                SKY_BOX,
                SPRITE,
        } active_prog;
 
 #include "BlockMesh.hpp"
 #include "EntityMesh.hpp"
-#include "OutlineMesh.hpp"
+#include "PrimitiveMesh.hpp"
 #include "SkyBoxMesh.hpp"
 #include "SpriteMesh.hpp"
 
 }
 
 
-void OutlineMesh::Update(const Buffer &buf) noexcept {
+void PrimitiveMesh::Buffer::FillRect(
+       float w, float h,
+       const glm::vec4 &color,
+       const glm::vec2 &pivot
+) {
+       Clear();
+       Reserve(4, 6);
+
+       vertices.emplace_back( -pivot.x,  -pivot.y, 0.0f);
+       vertices.emplace_back(w-pivot.x,  -pivot.y, 0.0f);
+       vertices.emplace_back( -pivot.x, h-pivot.y, 0.0f);
+       vertices.emplace_back(w-pivot.x, h-pivot.y, 0.0f);
+
+       colors.resize(4, color);
+
+       indices.assign({ 0, 2, 1, 1, 2, 3 });
+}
+
+
+void PrimitiveMesh::Update(const Buffer &buf) noexcept {
 #ifndef NDEBUG
        if (buf.colors.size() < buf.vertices.size()) {
-               std::cerr << "OutlineMesh: not enough colors!" << std::endl;
+               std::cerr << "PrimitiveMesh: not enough colors!" << std::endl;
        }
 #endif
 
 }
 
 
-void OutlineMesh::Draw() noexcept {
+void PrimitiveMesh::DrawLines() noexcept {
        glEnable(GL_LINE_SMOOTH);
        glLineWidth(2.0f);
        vao.DrawLineElements();
 }
 
+void PrimitiveMesh::DrawTriangles() noexcept {
+       vao.DrawTriangleElements();
+}
+
 
 void SkyBoxMesh::LoadUnitBox() {
        Buffer buffer;
 
                GL_VERTEX_SHADER,
                "#version 330 core\n"
                "layout(location = 0) in vec3 vtx_position;\n"
-               "layout(location = 1) in vec3 vtx_color;\n"
+               "layout(location = 1) in vec4 vtx_color;\n"
                "uniform mat4 MVP;\n"
-               "out vec3 frag_color;\n"
+               "out vec4 frag_color;\n"
                "void main() {\n"
                        "gl_Position = MVP * vec4(vtx_position, 1);\n"
                        "frag_color = vtx_color;\n"
        program.LoadShader(
                GL_FRAGMENT_SHADER,
                "#version 330 core\n"
-               "in vec3 frag_color;\n"
-               "out vec3 color;\n"
+               "in vec4 frag_color;\n"
+               "out vec4 color;\n"
                "void main() {\n"
                        "color = frag_color;\n"
                "}\n"
 
        return entity_prog;
 }
 
-PlainColor &Viewport::WorldOutlineProgram() noexcept {
-       if (active_prog != OUTLINE_WORLD) {
-               outline_prog.Activate();
-               outline_prog.SetVP(cam.View(), cam.Projection());
-               active_prog = OUTLINE_WORLD;
+PlainColor &Viewport::WorldColorProgram() noexcept {
+       if (active_prog != COLOR_WORLD) {
+               color_prog.Activate();
+               color_prog.SetVP(cam.View(), cam.Projection());
+               active_prog = COLOR_WORLD;
        }
-       return outline_prog;
+       return color_prog;
 }
 
-PlainColor &Viewport::HUDOutlineProgram() noexcept {
-       if (active_prog != OUTLINE_HUD) {
-               outline_prog.Activate();
-               outline_prog.SetVP(canv.View(), canv.Projection());
-               active_prog = OUTLINE_HUD;
+PlainColor &Viewport::HUDColorProgram() noexcept {
+       if (active_prog != COLOR_HUD) {
+               color_prog.Activate();
+               color_prog.SetVP(canv.View(), canv.Projection());
+               active_prog = COLOR_HUD;
        }
-       return outline_prog;
+       return color_prog;
 }
 
 SkyBoxShader &Viewport::SkyBoxProgram() noexcept {
 
 #ifndef BLANK_MODEL_COLLISIONBOUNDS_HPP_
 #define BLANK_MODEL_COLLISIONBOUNDS_HPP_
 
-#include "../graphics/OutlineMesh.hpp"
+#include "../graphics/PrimitiveMesh.hpp"
 
 #include <glm/glm.hpp>
 
        std::size_t OutlineIndexCount() const { return out_idx.size(); }
 
        /// fill given buffers with these bounds' outline's elements
-       void Outline(OutlineMesh::Buffer &out) const;
+       void Outline(PrimitiveMesh::Buffer &out) const;
 
        /// Check if given ray would pass though this shape if it were
        /// transformed with given matrix.
 
 protected:
        void SetOutline(
-               const OutlineMesh::Positions &pos,
-               const OutlineMesh::Indices &idx);
+               const PrimitiveMesh::Positions &pos,
+               const PrimitiveMesh::Indices &idx);
 
 private:
-       OutlineMesh::Positions out_pos;
-       OutlineMesh::Indices out_idx;
+       PrimitiveMesh::Positions out_pos;
+       PrimitiveMesh::Indices out_idx;
 
 };
 
 
 
        size_t OutlineCount() const noexcept;
        size_t OutlineIndexCount() const noexcept;
-       void Outline(OutlineMesh::Buffer &out) const;
+       void Outline(PrimitiveMesh::Buffer &out) const;
 
        bool Intersects(
                const Ray &,
 
 
 namespace blank {
 
-void CollisionBounds::Outline(OutlineMesh::Buffer &out) const {
+void CollisionBounds::Outline(PrimitiveMesh::Buffer &out) const {
        out.vertices.insert(out.vertices.end(), out_pos.begin(), out_pos.end());
        out.indices.insert(out.indices.end(), out_idx.begin(), out_idx.end());
 }
 
 void CollisionBounds::SetOutline(
-       const OutlineMesh::Positions &pos,
-       const OutlineMesh::Indices &idx
+       const PrimitiveMesh::Positions &pos,
+       const PrimitiveMesh::Indices &idx
 ) {
        out_pos = pos;
        out_idx = idx;
 
        }
 }
 
-void Shape::Outline(OutlineMesh::Buffer &out) const {
+void Shape::Outline(PrimitiveMesh::Buffer &out) const {
        if (bounds) {
                bounds->Outline(out);
        }
 
 #include "FixedText.hpp"
 #include "MessageBox.hpp"
 #include "../graphics/EntityMesh.hpp"
-#include "../graphics/OutlineMesh.hpp"
+#include "../graphics/PrimitiveMesh.hpp"
 
 #include <glm/glm.hpp>
 
        const Player &player;
 
        // block focus
-       OutlineMesh outline;
+       PrimitiveMesh outline;
        glm::mat4 outline_transform;
        bool outline_visible;
 
        IntervalTimer msg_timer;
 
        // crosshair
-       OutlineMesh crosshair;
+       PrimitiveMesh crosshair;
 
 };
 
 
        messages.Background(glm::vec4(0.5f));
 
        // crosshair
-       OutlineMesh::Buffer buf;
+       PrimitiveMesh::Buffer buf;
        buf.vertices = std::vector<glm::vec3>({
                { -10.0f,   0.0f, 0.0f }, { 10.0f,  0.0f, 0.0f },
                {   0.0f, -10.0f, 0.0f }, {  0.0f, 10.0f, 0.0f },
        });
-       buf.indices = std::vector<OutlineMesh::Index>({
+       buf.indices = std::vector<PrimitiveMesh::Index>({
                0, 1, 2, 3
        });
-       buf.colors.resize(4, { 10.0f, 10.0f, 10.0f });
+       buf.colors.resize(4, { 10.0f, 10.0f, 10.0f, 1.0f });
        crosshair.Update(buf);
 }
 
 namespace {
 
-OutlineMesh::Buffer outl_buf;
+PrimitiveMesh::Buffer outl_buf;
 
 }
 
        const Block &block = chunk.BlockAt(index);
        const BlockType &type = chunk.Type(index);
        outl_buf.Clear();
-       type.FillOutlineMesh(outl_buf);
+       type.OutlinePrimitiveMesh(outl_buf);
        outline.Update(outl_buf);
        outline_transform = chunk.Transform(player.GetEntity().ChunkCoords());
        outline_transform *= chunk.ToTransform(Chunk::ToPos(index), index);
 void HUD::Render(Viewport &viewport) noexcept {
        // block focus
        if (outline_visible && config.video.world) {
-               PlainColor &outline_prog = viewport.WorldOutlineProgram();
+               PlainColor &outline_prog = viewport.WorldColorProgram();
                outline_prog.SetM(outline_transform);
-               outline.Draw();
+               outline.DrawLines();
        }
 
        // clear depth buffer so everything renders above the world
                }
 
                // crosshair
-               PlainColor &outline_prog = viewport.HUDOutlineProgram();
+               PlainColor &outline_prog = viewport.HUDColorProgram();
                viewport.EnableInvertBlending();
                viewport.SetCursor(glm::vec3(0.0f), Gravity::CENTER);
                outline_prog.SetM(viewport.Cursor());
-               crosshair.Draw();
+               crosshair.DrawLines();
        }
 
        // debug overlay
 
 #include "Block.hpp"
 #include "../graphics/BlockMesh.hpp"
 #include "../graphics/EntityMesh.hpp"
-#include "../graphics/OutlineMesh.hpp"
+#include "../graphics/PrimitiveMesh.hpp"
 #include "../model/Shape.hpp"
 
 #include <glm/glm.hpp>
                const glm::mat4 &transform = glm::mat4(1.0f),
                BlockMesh::Index idx_offset = 0
        ) const noexcept;
-       void FillOutlineMesh(OutlineMesh::Buffer &m) const noexcept;
+       void OutlinePrimitiveMesh(PrimitiveMesh::Buffer &) const noexcept;
 
 };
 
 
        buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod);
 }
 
-void BlockType::FillOutlineMesh(OutlineMesh::Buffer &buf) const noexcept {
+void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept {
        if (!shape) return;
        shape->Outline(buf);
-       buf.colors.insert(buf.colors.end(), shape->OutlineCount(), outline_color);
+       buf.colors.insert(buf.colors.end(), shape->OutlineCount(), glm::vec4(outline_color, 1.0f));
 }