#include "../app/IntervalTimer.hpp"
 #include "../geometry/primitive.hpp"
+#include "../graphics/glm.hpp"
 #include "../world/EntityController.hpp"
 
-#include <glm/glm.hpp>
-
 
 namespace blank {
 
 
                bool safe = false;
                for (const Player &ref : refs) {
                        glm::vec3 diff(ref.GetEntity().AbsoluteDifference(e));
-                       if (dot(diff, diff) < despawn_range) {
+                       if (glm::length2(diff) < despawn_range) {
                                safe = true;
                                break;
                        }
 
 #define BLANK_AI_SPAWNER_HPP_
 
 #include "../app/IntervalTimer.hpp"
+#include "../graphics/glm.hpp"
 
 #include <vector>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 
 #include "../geometry/distance.hpp"
 #include "../geometry/rotation.hpp"
+#include "../graphics/glm.hpp"
 #include "../rand/GaloisLFSR.hpp"
 #include "../world/Entity.hpp"
 #include "../world/World.hpp"
 
 #include <cmath>
 #include <limits>
-#include <glm/glm.hpp>
 
 
 namespace blank {
                // orient head towards heading
                glm::vec3 heading(e.Heading());
                // only half pitch, so we don't crane our neck
-               float tgt_pitch = std::atan(heading.y / length(glm::vec2(heading.x, heading.z))) * 0.5f;
+               float tgt_pitch = std::atan(heading.y / glm::length(glm::vec2(heading.x, heading.z))) * 0.5f;
                // always look straight ahead
                // maybe look at the pursuit target if there is one
                float tgt_yaw = 0.0f;
 
                // distance test
                const glm::vec3 diff(pe.AbsoluteDifference(e));
-               float dist = length(diff);
+               float dist = glm::length(diff);
                if (dist > distance) continue;
 
                // FOV test, 45° in each direction
-               if (dot(diff / dist, aim.dir) < sight_angle) {
+               if (glm::dot(diff / dist, aim.dir) < sight_angle) {
                        continue;
                }
 
        const glm::ivec3 &reference(from.ChunkCoords());
        Ray aim(from.Aim(reference));
        const glm::vec3 diff(to.AbsoluteDifference(from));
-       float dist = length(diff);
-       if (dist > sight_dist || dot(diff / dist, aim.dir) < sight_angle) {
+       float dist = glm::length(diff);
+       if (dist > sight_dist || glm::dot(diff / dist, aim.dir) < sight_angle) {
                return false;
        }
        WorldCollision col;
                return;
        }
        // halt if we're close enough, flee if we're too close
-       float dist_sq = length2(e.AbsoluteDifference(steering.GetTargetEntity()));
+       float dist_sq = glm::length2(e.AbsoluteDifference(steering.GetTargetEntity()));
        if (dist_sq < 8.0f) {
                ctrl.SetState(flee, e);
        } else if (dist_sq < 25.0f) {
 
 #define BLANK_AUDIO_AUDIO_HPP_
 
 #include "../app/IntervalTimer.hpp"
+#include "../graphics/glm.hpp"
 
 #include <al.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_CLIENT_CHUNKTRANSMISSION_HPP_
 #define BLANK_CLIENT_CHUNKTRANSMISSION_HPP_
 
+#include "../graphics/glm.hpp"
 #include "../world/Chunk.hpp"
 
 #include <cstdint>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
        }
 
        glm::vec3 displacement(replay.GetState().Diff(player_state));
-       const float disp_squared = dot(displacement, displacement);
+       const float disp_squared = glm::dot(displacement, displacement);
 
        if (disp_squared < 16.0f * numeric_limits<float>::epsilon()) {
                SetMovement(restore_movement);
 
 #ifndef BLANK_GEOMETRY_LOCATION_HPP_
 #define BLANK_GEOMETRY_LOCATION_HPP_
 
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
        using Coarse = glm::ivec3;
        using CoarseScalar = int;
-       using Fine = glm::tvec3<T>;
+       using Fine = TVEC3<T, glm::precision(0)>;
        using FineScalar = T;
        using Self = Location<T>;
 
 
 #ifndef BLANK_GEOMETRY_DISTANCE_HPP_
 #define BLANK_GEOMETRY_DISTANCE_HPP_
 
+#include "../graphics/glm.hpp"
+
 #include <algorithm>
 #include <limits>
-#include <glm/glm.hpp>
 #include <glm/gtx/component_wise.hpp>
 #include <glm/gtx/norm.hpp>
 
 
 template <class T>
 inline bool iszero(const T &v) noexcept {
-       return length2(v) < std::numeric_limits<typename T::value_type>::epsilon();
+       return glm::length2(v) < std::numeric_limits<typename T::value_type>::epsilon();
 }
 
 template<class Vec>
 inline void limit(Vec &v, float max) noexcept {
-       float len2 = length2(v);
+       float len2 = glm::length2(v);
        float max2 = max * max;
        if (len2 > max2) {
-               v = normalize(v) * max;
+               v = glm::normalize(v) * max;
        }
 }
 
-template<class T>
-T manhattan_distance(const glm::tvec3<T> &a, const glm::tvec3<T> &b) noexcept {
-       return compAdd(abs(a - b));
+template<class T, glm::precision P = glm::precision(0)>
+T manhattan_distance(const TVEC3<T, P> &a, const TVEC3<T, P> &b) noexcept {
+       return glm::compAdd(glm::abs(a - b));
 }
 
-template<class T>
-T manhattan_radius(const glm::tvec3<T> &v) noexcept {
-       return compMax(abs(v));
+template<class T, glm::precision P = glm::precision(0)>
+T manhattan_radius(const TVEC3<T, P> &v) noexcept {
+       return glm::compMax(glm::abs(v));
 }
 
 }
 
 namespace blank {
 
 glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept {
-       glm::vec3 v(cross(a, b));
+       glm::vec3 v(glm::cross(a, b));
        if (iszero(v)) {
                // a and b are parallel
                if (iszero(a - b)) {
                        } else {
                                arb.y += 1.0f;
                        }
-                       glm::vec3 axis(normalize(cross(a, arb)));
+                       glm::vec3 axis(glm::normalize(glm::cross(a, arb)));
                        return glm::mat3(glm::rotate(PI, axis));
                }
        }
-       float mv = length2(v);
-       float c = dot(a, b);
+       float mv = glm::length2(v);
+       float c = glm::dot(a, b);
        float f = (1 - c) / mv;
-       glm::mat3 vx(matrixCross3(v));
-       return glm::mat3(1.0f) + vx + (pow2(vx) * f);
+       glm::mat3 vx(glm::matrixCross3(v));
+       return glm::mat3(1.0f) + vx + (glm::pow2(vx) * f);
 }
 
 std::ostream &operator <<(std::ostream &out, const AABB &box) {
                *dist = t_min;
        }
        if (normal) {
-               glm::vec3 min_all(min(t1, t2));
+               glm::vec3 min_all(glm::min(t1, t2));
                if (min_all.x > min_all.y) {
                        if (min_all.x > min_all.z) {
                                normal->x = t2.x < t1.x ? 1 : -1;
                glm::vec3(b_m[0]),
                glm::vec3(b_m[1]),
                glm::vec3(b_m[2]),
-               normalize(cross(glm::vec3(a_m[0]), glm::vec3(b_m[0]))),
-               normalize(cross(glm::vec3(a_m[0]), glm::vec3(b_m[1]))),
-               normalize(cross(glm::vec3(a_m[0]), glm::vec3(b_m[2]))),
-               normalize(cross(glm::vec3(a_m[1]), glm::vec3(b_m[0]))),
-               normalize(cross(glm::vec3(a_m[1]), glm::vec3(b_m[1]))),
-               normalize(cross(glm::vec3(a_m[1]), glm::vec3(b_m[2]))),
-               normalize(cross(glm::vec3(a_m[2]), glm::vec3(b_m[0]))),
-               normalize(cross(glm::vec3(a_m[2]), glm::vec3(b_m[1]))),
-               normalize(cross(glm::vec3(a_m[2]), glm::vec3(b_m[2]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[0]), glm::vec3(b_m[0]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[0]), glm::vec3(b_m[1]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[0]), glm::vec3(b_m[2]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[1]), glm::vec3(b_m[0]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[1]), glm::vec3(b_m[1]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[1]), glm::vec3(b_m[2]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[2]), glm::vec3(b_m[0]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[2]), glm::vec3(b_m[1]))),
+               glm::normalize(glm::cross(glm::vec3(a_m[2]), glm::vec3(b_m[2]))),
        };
 
        depth = std::numeric_limits<float>::infinity();
 
        int cur_axis = 0;
        for (const glm::vec3 &axis : axes) {
-               if (any(isnan(axis))) {
+               if (glm::any(glm::isnan(axis))) {
                        // can result from the cross products if A and B have parallel axes
                        ++cur_axis;
                        continue;
                        ((plane.normal.y > 0.0f) ? box.max.y : box.min.y),
                        ((plane.normal.z > 0.0f) ? box.max.z : box.min.z)
                );
-               const float dp = dot(plane.normal, np);
+               const float dp = glm::dot(plane.normal, np);
                // cull if nearest point is on the "outside" side of the plane
                if (dp < -plane.dist) return true;
        }
 
 #ifndef BLANK_GEOMETRY_PRIMITIVE_HPP_
 #define BLANK_GEOMETRY_PRIMITIVE_HPP_
 
+#include "../graphics/glm.hpp"
+
 #include <algorithm>
 #include <iosfwd>
-#include <glm/glm.hpp>
 #include <glm/gtx/norm.hpp>
 
 
 
        /// return distance between origin and farthest vertex
        float OriginRadius() const noexcept {
-               glm::vec3 high(glm::max(abs(min), abs(max)));
-               return length(high);
+               glm::vec3 high(glm::max(glm::abs(min), glm::abs(max)));
+               return glm::length(high);
        }
 };
 
                // for derivation, see http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
                // x1 = orig
                // x2-x1 = dir, which means |x2-x1| is 1.0
-               return length(cross(dir, orig - point));
+               return glm::length(glm::cross(dir, orig - point));
        }
        float DistanceSquared(const glm::vec3 &point) const noexcept {
-               return length2(cross(dir, orig - point));
+               return glm::length2(glm::cross(dir, orig - point));
        }
 };
 
        : normal(abcd), dist(abcd.w) { }
 
        void Normalize() noexcept {
-               const float l = length(normal);
+               const float l = glm::length(normal);
                normal /= l;
                dist /= l;
        }
 
 #ifndef BLANK_GEOMETRY_ROTATION_HPP_
 #define BLANK_GEOMETRY_ROTATION_HPP_
 
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_BLENDEDSPRITE_HPP_
 #define BLANK_GRAPHICS_BLENDEDSPRITE_HPP_
 
+#include "glm.hpp"
 #include "Program.hpp"
 
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_BLOCKLIGHTING_HPP_
 #define BLANK_GRAPHICS_BLOCKLIGHTING_HPP_
 
+#include "glm.hpp"
 #include "Program.hpp"
 
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_BLOCKMESH_HPP_
 #define BLANK_GRAPHICS_BLOCKMESH_HPP_
 
+#include "glm.hpp"
 #include "VertexArray.hpp"
 
 #include <vector>
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 public:
        using Position = glm::vec3;
        using TexCoord = glm::vec3;
-       using ColorMod = glm::tvec3<unsigned char>;
+       using ColorMod = TVEC3<unsigned char, glm::precision(0)>;
        using Light = float;
        using Index = unsigned int;
 
 
 #ifndef BLANK_GRAPHICS_CAMERA_HPP_
 #define BLANK_GRAPHICS_CAMERA_HPP_
 
-#include <glm/glm.hpp>
+#include "glm.hpp"
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_CANVAS_HPP_
 #define BLANK_GRAPHICS_CANVAS_HPP_
 
-#include <glm/glm.hpp>
+#include "glm.hpp"
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_DIRECTIONALLIGHTING_HPP_
 #define BLANK_GRAPHICS_DIRECTIONALLIGHTING_HPP_
 
+#include "glm.hpp"
 #include "Program.hpp"
 
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_ENTITYMESH_HPP_
 #define BLANK_GRAPHICS_ENTITYMESH_HPP_
 
+#include "glm.hpp"
 #include "VertexArray.hpp"
 
 #include <vector>
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 public:
        using Position = glm::vec3;
        using TexCoord = glm::vec3;
-       using ColorMod = glm::tvec3<unsigned char>;
+       using ColorMod = TVEC3<unsigned char, glm::precision(0)>;
        using Normal = glm::vec3;
        using Index = unsigned int;
 
 
 #ifndef BLANK_GRAPHICS_FONT_HPP_
 #define BLANK_GRAPHICS_FONT_HPP_
 
+#include "glm.hpp"
+
 #include <SDL_ttf.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_PLAINCOLOR_HPP_
 #define BLANK_GRAPHICS_PLAINCOLOR_HPP_
 
+#include "glm.hpp"
 #include "Program.hpp"
 
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_PRIMITIVEMESH_HPP_
 #define BLANK_GRAPHICS_PRIMITIVEMESH_HPP_
 
+#include "glm.hpp"
 #include "VertexArray.hpp"
 
 #include <vector>
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 public:
        using Position = glm::vec3;
-       using Color = glm::tvec4<unsigned char>;
+       using Color = TVEC4<unsigned char, glm::precision(0)>;
        using Index = unsigned short;
 
        using Positions = std::vector<Position>;
 
 #ifndef BLANK_GRAPHICS_PROGRAM_HPP_
 #define BLANK_GRAPHICS_PROGRAM_HPP_
 
+#include "glm.hpp"
+
 #include <iosfwd>
 #include <list>
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_SKYBOXMESH_HPP_
 #define BLANK_GRAPHICS_SKYBOXMESH_HPP_
 
+#include "glm.hpp"
 #include "VertexArray.hpp"
 
 #include <vector>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_GRPAHICS_SPRITEMESH_HPP_
 #define BLANK_GRPAHICS_SPRITEMESH_HPP_
 
+#include "glm.hpp"
 #include "VertexArray.hpp"
 
 #include <vector>
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #include "Camera.hpp"
 #include "Canvas.hpp"
 #include "DirectionalLighting.hpp"
+#include "glm.hpp"
 #include "PlainColor.hpp"
 #include "SkyBoxShader.hpp"
 
-#include <glm/glm.hpp>
-
 
 namespace blank {
 
 
 #ifndef BLANK_GRAPHICS_ALIGN_HPP_
 #define BLANK_GRAPHICS_ALIGN_HPP_
 
-#include <glm/glm.hpp>
+#include "glm.hpp"
 
 
 namespace blank {
 
 #ifndef BLANK_GRAPHICS_GL_TRAITS_HPP_
 #define BLANK_GRAPHICS_GL_TRAITS_HPP_
 
+#include "glm.hpp"
+
 #include <GL/glew.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 template<>
 template<class T, glm::precision P>
-struct gl_traits<glm::tvec1<T, P>> {
+struct gl_traits<TVEC1<T, P>> {
        static constexpr GLint size = 1;
        static constexpr GLenum type = gl_traits<T>::type;
 };
 template<class T, glm::precision P>
-constexpr GLint gl_traits<glm::tvec1<T, P>>::size;
+constexpr GLint gl_traits<TVEC1<T, P>>::size;
 template<class T, glm::precision P>
-constexpr GLenum gl_traits<glm::tvec1<T, P>>::type;
+constexpr GLenum gl_traits<TVEC1<T, P>>::type;
 
 template<>
 template<class T, glm::precision P>
-struct gl_traits<glm::tvec2<T, P>> {
+struct gl_traits<TVEC2<T, P>> {
        static constexpr GLint size = 2;
        static constexpr GLenum type = gl_traits<T>::type;
 };
 template<class T, glm::precision P>
-constexpr GLint gl_traits<glm::tvec2<T, P>>::size;
+constexpr GLint gl_traits<TVEC2<T, P>>::size;
 template<class T, glm::precision P>
-constexpr GLenum gl_traits<glm::tvec2<T, P>>::type;
+constexpr GLenum gl_traits<TVEC2<T, P>>::type;
 
 template<>
 template<class T, glm::precision P>
-struct gl_traits<glm::tvec3<T, P>> {
+struct gl_traits<TVEC3<T, P>> {
        static constexpr GLint size = 3;
        static constexpr GLenum type = gl_traits<T>::type;
 };
 template<class T, glm::precision P>
-constexpr GLint gl_traits<glm::tvec3<T, P>>::size;
+constexpr GLint gl_traits<TVEC3<T, P>>::size;
 template<class T, glm::precision P>
-constexpr GLenum gl_traits<glm::tvec3<T, P>>::type;
+constexpr GLenum gl_traits<TVEC3<T, P>>::type;
 
 template<>
 template<class T, glm::precision P>
-struct gl_traits<glm::tvec4<T, P>> {
+struct gl_traits<TVEC4<T, P>> {
        static constexpr GLint size = 4;
        static constexpr GLenum type = gl_traits<T>::type;
 };
 template<class T, glm::precision P>
-constexpr GLint gl_traits<glm::tvec4<T, P>>::size;
+constexpr GLint gl_traits<TVEC4<T, P>>::size;
 template<class T, glm::precision P>
-constexpr GLenum gl_traits<glm::tvec4<T, P>>::type;
+constexpr GLenum gl_traits<TVEC4<T, P>>::type;
 
 }
 
 
--- /dev/null
+#ifndef BLANK_GRAPHICS_GLM_HPP_
+#define BLANK_GRAPHICS_GLM_HPP_
+
+#ifndef GLM_FORCE_RADIANS
+#  define GLM_FORCE_RADIANS 1
+#endif
+
+#include <glm/glm.hpp>
+
+// GLM moved tvec[1234] from glm::detail to glm in 0.9.6
+
+#if GLM_VERSION < 96
+#  define TVEC1 glm::detail::tvec1
+#  define TVEC2 glm::detail::tvec2
+#  define TVEC3 glm::detail::tvec3
+#  define TVEC4 glm::detail::tvec4
+#else
+#  define TVEC1 glm::tvec1
+#  define TVEC2 glm::tvec2
+#  define TVEC3 glm::tvec3
+#  define TVEC4 glm::tvec4
+#endif
+
+#endif
 
 
 #include "Token.hpp"
 #include "Tokenizer.hpp"
+#include "../graphics/glm.hpp"
 
 #include <iosfwd>
 #include <string>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #define BLANK_MODEL_COLLISIONBOUNDS_HPP_
 
 #include "../graphics/PrimitiveMesh.hpp"
-
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
 #define BLANK_MODEL_INSTANCE_HPP_
 
 #include "Part.hpp"
+#include "../graphics/glm.hpp"
 
 #include <vector>
-#include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 
 
 
 #define BLANK_MODEL_MODEL_HPP_
 
 #include "Part.hpp"
+#include "../graphics/glm.hpp"
 
 #include <cstdint>
 #include <list>
 #include <vector>
-#include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 
 
 
 #ifndef BLAMK_MODEL_PART_HPP_
 #define BLAMK_MODEL_PART_HPP_
 
+#include "../graphics/EntityMesh.hpp"
+#include "../graphics/glm.hpp"
+
 #include <cstdint>
 #include <list>
 #include <memory>
 #include <vector>
-#include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 
 
 namespace blank {
 
 class DirectionalLighting;
-class EntityMesh;
 class Instance;
 class Model;
 class ResourceIndex;
        std::vector<float> tex_map;
        mutable std::unique_ptr<EntityMesh> mesh;
        State initial;
-       glm::tvec3<unsigned char> hsl_mod;
-       glm::tvec3<unsigned char> rgb_mod;
+       EntityMesh::ColorMod hsl_mod;
+       EntityMesh::ColorMod rgb_mod;
        std::uint16_t id;
 
 };
 
 #include "../geometry/primitive.hpp"
 #include "../graphics/BlockMesh.hpp"
 #include "../graphics/EntityMesh.hpp"
+#include "../graphics/glm.hpp"
 #include "../world/Block.hpp"
 
 #include <memory>
 #include <vector>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 
 #include "CollisionBounds.hpp"
 #include "../geometry/primitive.hpp"
+#include "../graphics/glm.hpp"
 
 #include <vector>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
                        in.ReadQuat(initial.orientation);
                } else if (name == "hsl_mod") {
                        in.ReadVec(color_conv);
-                       hsl_mod = glm::tvec3<unsigned char>(color_conv * 255.0f);
+                       hsl_mod = EntityMesh::ColorMod(color_conv * 255.0f);
                } else if (name == "rgb_mod") {
                        in.ReadVec(color_conv);
-                       rgb_mod = glm::tvec3<unsigned char>(color_conv * 255.0f);
+                       rgb_mod = EntityMesh::ColorMod(color_conv * 255.0f);
                } else if (name == "textures") {
                        in.Skip(Token::BRACKET_OPEN);
                        while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
 }
 
 glm::mat4 Part::LocalTransform(const Instance &inst) const noexcept {
-       glm::mat4 transform(toMat4(initial.orientation * inst.state[id].orientation));
+       glm::mat4 transform(glm::toMat4(initial.orientation * inst.state[id].orientation));
        transform[3] = glm::vec4(initial.position + inst.state[id].position, 1.0f);
        return transform;
 }
 
 #ifndef BLANK_NET_PACKET_HPP_
 #define BLANK_NET_PACKET_HPP_
 
+#include "../graphics/glm.hpp"
+
 #include <cstdint>
 #include <ostream>
 #include <string>
 #include <SDL_net.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
                }
        }
        // omitted component squared is 1 - length squared of others
-       val[largest_index] = sqrt(1.0f - dot(val, val));
+       val[largest_index] = sqrt(1.0f - glm::length2(val));
        // and already normalized
 }
 
 
 #ifndef BLANK_RAND_OCTAVENOISE_HPP_
 #define BLANK_RAND_OCTAVENOISE_HPP_
 
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
 #ifndef BLANK_RAND_SIMPLEXNOISE_HPP_
 #define BLANK_RAND_SIMPLEXNOISE_HPP_
 
+#include "../graphics/glm.hpp"
+
 #include <cstdint>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #ifndef BLANK_RAND_WORLEYNOISE_HPP_
 #define BLANK_RAND_WORLEYNOISE_HPP_
 
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
 #include "WorleyNoise.hpp"
 
 #include <cmath>
+#include <glm/gtx/norm.hpp>
 
 
 namespace {
        // I know 0.6 is wrong, but for some reason it looks better than 0.5
 
        // 0
-       float t = glm::clamp(0.6f - dot(offset[0], offset[0]), 0.0f, 1.0f);
+       float t = glm::clamp(0.6f - glm::length2(offset[0]), 0.0f, 1.0f);
        t *= t;
        int corner = Perm12(index[0] + Perm(index[1] + Perm(index[2])));
-       n += t * t * dot(Grad(corner), offset[0]);
+       n += t * t * glm::dot(Grad(corner), offset[0]);
 
        // 1
-       t = glm::clamp(0.6f - dot(offset[1], offset[1]), 0.0f, 1.0f);
+       t = glm::clamp(0.6f - glm::length2(offset[1]), 0.0f, 1.0f);
        t *= t;
        corner = Perm12(index[0] + second_int.x + Perm(index[1] + second_int.y + Perm(index[2] + second_int.z)));
-       n += t * t * dot(Grad(corner), offset[1]);
+       n += t * t * glm::dot(Grad(corner), offset[1]);
 
        // 2
-       t = glm::clamp(0.6f - dot(offset[2], offset[2]), 0.0f, 1.0f);
+       t = glm::clamp(0.6f - glm::length2(offset[2]), 0.0f, 1.0f);
        t *= t;
        corner = Perm12(index[0] + third_int.x + Perm(index[1] + third_int.y + Perm(index[2] + third_int.z)));
-       n += t * t * dot(Grad(corner), offset[2]);
+       n += t * t * glm::dot(Grad(corner), offset[2]);
 
        // 3
-       t = glm::clamp(0.6f - dot(offset[3], offset[3]), 0.0f, 1.0f);
+       t = glm::clamp(0.6f - glm::length2(offset[3]), 0.0f, 1.0f);
        t *= t;
        corner = Perm12(index[0] + 1 + Perm(index[1] + 1 + Perm(index[2] + 1)));
-       n += t * t * dot(Grad(corner), offset[3]);
+       n += t * t * glm::dot(Grad(corner), offset[3]);
 
        return 32.0f * n;
 }
 }
 
 float WorleyNoise::operator ()(const glm::vec3 &in) const noexcept {
-       glm::vec3 center = floor(in);
+       glm::vec3 center = glm::floor(in);
 
        float closest = 1.0f;  // cannot be farther away than 1.0
 
                                        cube_rand = 159739 * cube_rand + 112139;
                                        point.z += float(cube_rand % 262144) / 262144.0f;
 
-                                       glm::vec3 diff(in - point);
-                                       float distance = sqrt(dot(diff, diff));
+                                       float distance = glm::distance(in, point);
                                        if (distance < closest) {
                                                closest = distance;
                                        }
 
 void ClientConnection::CheckPlayerFix() {
        // player_update_state's position holds the client's most recent prediction
        glm::vec3 diff = player_update_state.Diff(PlayerEntity().GetState());
-       float dist_squared = dot(diff, diff);
+       float dist_squared = glm::length2(diff);
 
        // if client's prediction is off by more than 1cm, send
        // our (authoritative) state back so it can fix it
 
 , input(env.assets.small_ui_font) {
        input.Position(glm::vec3(25.0f, -25.0f, -1.0f), Gravity::SOUTH_WEST, Gravity::SOUTH_WEST);
        input.Width(env.viewport.Width() - 50.0f);
-       input.Foreground(glm::vec4(1.0f));
-       input.Background(glm::vec4(0.5f));
+       input.Foreground(PrimitiveMesh::Color(255));
+       input.Background(PrimitiveMesh::Color(127));
 }
 
 void ChatState::Preset(const std::string &text) {
 
 #include "FixedText.hpp"
 #include "MessageBox.hpp"
 #include "../graphics/EntityMesh.hpp"
+#include "../graphics/glm.hpp"
 #include "../graphics/PrimitiveMesh.hpp"
 
-#include <glm/glm.hpp>
-
 
 namespace blank {
 
 
 #define BLANK_UI_INTERFACE_HPP_
 
 #include "../app/Config.hpp"
+#include "../graphics/glm.hpp"
 
 #include <SDL.h>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 
 #include "Text.hpp"
 #include "../graphics/align.hpp"
+#include "../graphics/glm.hpp"
 #include "../graphics/PrimitiveMesh.hpp"
 
 #include <deque>
 #include <string>
-#include <glm/glm.hpp>
 
 
 namespace blank {
        glm::vec3 adv;
        glm::vec2 size;
 
-       glm::vec4 bg;
-       glm::vec4 fg;
+       PrimitiveMesh::Color bg;
+       PrimitiveMesh::Color fg;
 
        PrimitiveMesh bg_mesh;
 
 
 #ifndef BLANK_UI_PLAYERCONTROLLER_HPP_
 #define BLANK_UI_PLAYERCONTROLLER_HPP_
 
-#include <glm/glm.hpp>
-
+#include "../graphics/glm.hpp"
 #include "../world/EntityCollision.hpp"
 #include "../world/EntityController.hpp"
 #include "../world/WorldCollision.hpp"
 
 #define BLANK_UI_TEXT_HPP_
 
 #include "../graphics/align.hpp"
+#include "../graphics/glm.hpp"
 #include "../graphics/Texture.hpp"
 #include "../graphics/SpriteMesh.hpp"
 
 #include <string>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
        void Position(const glm::vec3 &p, Gravity g, Gravity pv) noexcept;
        void Width(float) noexcept;
 
-       void Foreground(const glm::vec4 &col) noexcept { fg = col; dirty_cursor = true; }
-       void Background(const glm::vec4 &col) noexcept { bg = col; dirty_box = true; }
+       void Foreground(const PrimitiveMesh::Color &col) noexcept { fg = col; dirty_cursor = true; }
+       void Background(const PrimitiveMesh::Color &col) noexcept { bg = col; dirty_box = true; }
 
        void Handle(const SDL_TextInputEvent &);
        void Handle(const SDL_TextEditingEvent &);
        PrimitiveMesh bg_mesh;
        PrimitiveMesh cursor_mesh;
 
-       glm::vec4 bg;
-       glm::vec4 fg;
+       PrimitiveMesh::Color bg;
+       PrimitiveMesh::Color fg;
 
        glm::vec3 position;
        glm::vec2 size;
 
 }
 
 void PlayerController::SetMovement(const glm::vec3 &m) noexcept {
-       if (dot(m, m) > 1.0f) {
-               move_dir = normalize(m);
+       if (glm::dot(m, m) > 1.0f) {
+               move_dir = glm::normalize(m);
        } else {
                move_dir = m;
        }
                if (!iszero(move_dir)) {
                        // scale input by max velocity, apply yaw, and transform to world space
                        steering.SetTargetVelocity(glm::vec3(
-                               glm::vec4(rotateY(move_dir * entity.MaxVelocity(), entity.Yaw()), 0.0f)
-                               * transpose(entity.Transform())
+                               glm::vec4(glm::rotateY(move_dir * entity.MaxVelocity(), entity.Yaw()), 0.0f)
+                               * glm::transpose(entity.Transform())
                        ));
                        steering.Enable(Steering::TARGET_VELOCITY);
                        steering.Disable(Steering::HALT);
        // if view is straight up or down, this will be a null vector (NaN after normalization)
        // in that case maybe the model forward should be used?
        // the current implementation implicitly falls back to TURN_NONE which is -Z
-       const glm::vec3 local_forward(normalize(view_forward - proj(view_forward, player_up)));
+       const glm::vec3 local_forward(glm::normalize(view_forward - glm::proj(view_forward, player_up)));
        // FIXME: I suspect this only works when player_up is positive Y
        if (local_forward.x > 0.707f) {
                new_block.SetTurn(Block::TURN_RIGHT);
 
        }
        BlendedSprite &prog = viewport.SpriteProgram();
        prog.SetBG(glm::vec4(0.0f));
-       prog.SetFG(fg);
+       prog.SetFG(glm::vec4(fg) * (1.0f / 255.0f));
        for (Text &txt : lines) {
                prog.SetM(viewport.Cursor());
                txt.Render(viewport);
        if (!input.empty()) {
                BlendedSprite &prog = viewport.SpriteProgram();
                prog.SetBG(glm::vec4(0.0f));
-               prog.SetFG(fg);
+               prog.SetFG(glm::vec4(fg) * (1.0f / 255.0f));
                prog.SetM(viewport.Cursor());
                text.Render(viewport);
        }
 
 #ifndef BLANK_WORLD_BLOCK_HPP_
 #define BLANK_WORLD_BLOCK_HPP_
 
+#include "../graphics/glm.hpp"
+
 #include <iosfwd>
-#include <glm/glm.hpp>
 
 
 namespace blank {
        }
 
        static Face NormalFace(const glm::vec3 &norm) noexcept {
-               const glm::vec3 anorm(abs(norm));
+               const glm::vec3 anorm(glm::abs(norm));
                if (anorm.x > anorm.y) {
                        if (anorm.x > anorm.z) {
                                return norm.x > 0.0f ? FACE_RIGHT : FACE_LEFT;
 
 #ifndef BLANK_WORLD_BLOCKGRAVITY_HPP_
 #define BLANK_WORLD_BLOCKGRAVITY_HPP_
 
+#include "../graphics/glm.hpp"
+
 #include <memory>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 #include "BlockGravity.hpp"
 #include "../graphics/BlockMesh.hpp"
 #include "../graphics/EntityMesh.hpp"
+#include "../graphics/glm.hpp"
 #include "../graphics/PrimitiveMesh.hpp"
 #include "../model/Shape.hpp"
 
-#include <glm/glm.hpp>
 #include <limits>
 #include <vector>
 
 
        const Shape *shape;
        std::vector<float> textures;
-       glm::tvec3<unsigned char> hsl_mod;
-       glm::tvec3<unsigned char> rgb_mod;
-       glm::tvec3<unsigned char> outline_color;
+       TVEC3<unsigned char, glm::precision(0)> hsl_mod;
+       TVEC3<unsigned char, glm::precision(0)> rgb_mod;
+       TVEC3<unsigned char, glm::precision(0)> outline_color;
 
        /// gravity configuration or null if not emitting gravity
        std::unique_ptr<BlockGravity> gravity;
 
 #include "BlockTypeRegistry.hpp"
 #include "../geometry/Location.hpp"
 #include "../geometry/primitive.hpp"
+#include "../graphics/glm.hpp"
 
 #include <set>
 #include <vector>
-#include <glm/glm.hpp>
 #include <glm/gtx/transform.hpp>
 
 
                        pos.y >= 0 && pos.y < side &&
                        pos.z >= 0 && pos.z < side;
        }
+       static int ToIndex(const ExactLocation::Fine &pos) noexcept {
+               return ToIndex(RoughLocation::Fine(pos));
+       }
        static constexpr int ToIndex(const RoughLocation::Fine &pos) noexcept {
                return pos.x + pos.y * side + pos.z * side * side;
        }
        const ExactLocation::Coarse &Position() const noexcept { return position; }
 
        glm::mat4 Transform(const ExactLocation::Coarse &offset) const noexcept {
-               return glm::translate((position - offset) * ExactLocation::Extent());
+               return glm::translate(ExactLocation::Fine((position - offset) * ExactLocation::Extent()));
        }
 
        void *BlockData() noexcept { return &blocks[0]; }
 
 #include "EntityState.hpp"
 #include "Steering.hpp"
 #include "../geometry/primitive.hpp"
+#include "../graphics/glm.hpp"
 #include "../model/Instance.hpp"
 
 #include <cstdint>
 #include <string>
-#include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 
 
 
 #ifndef BLANK_WORLD_ENTITYDERIVATIVE_HPP_
 #define BLANK_WORLD_ENTITYDERIVATIVE_HPP_
 
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
 #define BLANK_WORLD_ENTITYSTATE_HPP_
 
 #include "../geometry/Location.hpp"
+#include "../graphics/glm.hpp"
 
-#include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 
 
 
 #include "BlockType.hpp"
 #include "BlockTypeRegistry.hpp"
 #include "Chunk.hpp"
+#include "../graphics/glm.hpp"
 #include "../rand/OctaveNoise.hpp"
 
-#include <glm/glm.hpp>
-
 
 namespace blank {
 
 
 #ifndef BLANK_WORLD_GENERATOR_HPP_
 #define BLANK_WORLD_GENERATOR_HPP_
 
+#include "../graphics/glm.hpp"
 #include "../rand/SimplexNoise.hpp"
 
 #include <cstdint>
 #include <vector>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 
 #include "../geometry/Location.hpp"
 #include "../geometry/primitive.hpp"
-
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
 #include "Entity.hpp"
 #include "Generator.hpp"
 #include "Player.hpp"
+#include "../graphics/glm.hpp"
 #include "../rand/GaloisLFSR.hpp"
 
 #include <cstdint>
 #include <list>
 #include <string>
 #include <vector>
-#include <glm/glm.hpp>
 
 
 namespace blank {
 
 
 #include "BlockType.hpp"
 #include "Chunk.hpp"
-
-#include <glm/glm.hpp>
+#include "../graphics/glm.hpp"
 
 
 namespace blank {
 
                        in.Skip(Token::BRACKET_CLOSE);
                } else if (name == "rgb_mod") {
                        in.ReadVec(color_conv);
-                       rgb_mod = glm::tvec3<unsigned char>(color_conv * 255.0f);
+                       rgb_mod = BlockMesh::ColorMod(color_conv * 255.0f);
                } else if (name == "hsl_mod") {
                        in.ReadVec(color_conv);
-                       hsl_mod = glm::tvec3<unsigned char>(color_conv * 255.0f);
+                       hsl_mod = BlockMesh::ColorMod(color_conv * 255.0f);
                } else if (name == "outline") {
                        in.ReadVec(color_conv);
-                       outline_color = glm::tvec3<unsigned char>(color_conv * 255.0f);
+                       outline_color = BlockMesh::ColorMod(color_conv * 255.0f);
                } else if (name == "gravity") {
                        gravity = BlockGravity::Read(in);
                } else if (name == "label") {
 void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept {
        if (!shape) return;
        shape->Outline(buf);
-       buf.colors.insert(buf.colors.end(), shape->OutlineCount(), glm::tvec4<unsigned char>(outline_color, 255));
+       buf.colors.insert(buf.colors.end(), shape->OutlineCount(), PrimitiveMesh::Color(outline_color, 255));
 }
 
 
        : strength(strength) { }
 
        glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &) const noexcept override {
-               float dist2 = length2(diff);
-               glm::vec3 dir = -normalize(diff);
+               float dist2 = glm::length2(diff);
+               glm::vec3 dir = -glm::normalize(diff);
                return dir * (strength / dist2);
        }
 
 
        constexpr float block_rad = 2.0f;
        const float bb_radius = box_rad + block_rad;
 
-       const RoughLocation::Fine begin(max(
+       const RoughLocation::Fine begin(glm::max(
                RoughLocation::Fine(0),
-               RoughLocation::Fine(floor(box_coords - bb_radius))
+               RoughLocation::Fine(glm::floor(box_coords - bb_radius))
        ));
-       const RoughLocation::Fine end(min(
+       const RoughLocation::Fine end(glm::min(
                RoughLocation::Fine(side - 1),
-               RoughLocation::Fine(ceil(box_coords + bb_radius))
+               RoughLocation::Fine(glm::ceil(box_coords + bb_radius))
        ) - 1);
 
        for (RoughLocation::Fine pos(begin); pos.z < end.y; ++pos.z) {
        const glm::vec3 entity_coords(Mentity[3] - Mchunk[3]);
        const float ec_radius = entity.Radius() + Radius();
 
-       if (distance2(entity_coords, Center()) > ec_radius * ec_radius) {
+       if (glm::distance2(entity_coords, Center()) > ec_radius * ec_radius) {
                return false;
        }
 
        constexpr float block_rad = 2.0f;
        const float eb_radius = entity.Radius() + block_rad;
 
-       const RoughLocation::Fine begin(max(
+       const RoughLocation::Fine begin(glm::max(
                RoughLocation::Fine(0),
-               RoughLocation::Fine(floor(entity_coords - eb_radius))
+               RoughLocation::Fine(glm::floor(entity_coords - eb_radius))
        ));
-       const RoughLocation::Fine end(min(
+       const RoughLocation::Fine end(glm::min(
                RoughLocation::Fine(side),
-               RoughLocation::Fine(ceil(entity_coords + eb_radius))
+               RoughLocation::Fine(glm::ceil(entity_coords + eb_radius))
        ));
 
        for (RoughLocation::Fine pos(begin); pos.z < end.z; ++pos.z) {
        chunk_prog.SetTexture(block_tex);
        chunk_prog.SetFogDensity(fog_density);
 
-       Frustum frustum(transpose(chunk_prog.GetVP()));
+       Frustum frustum(glm::transpose(chunk_prog.GetVP()));
        AABB box;
 
        for (int i = 0; i < index.TotalChunks(); ++i) {
 
        if (model) {
                view_transform = model.EyesTransform();
        } else {
-               view_transform = toMat4(glm::quat(glm::vec3(state.pitch, state.yaw, 0.0f)));
+               view_transform = glm::toMat4(glm::quat(glm::vec3(state.pitch, state.yaw, 0.0f)));
        }
 }
 
 void Entity::UpdateHeading() noexcept {
-       speed = length(Velocity());
+       speed = glm::length(Velocity());
        if (speed > std::numeric_limits<float>::epsilon()) {
                heading = Velocity() / speed;
        } else {
                // check if our orientation and velocity are aligned
                const glm::vec3 forward(-model_transform[2]);
                // facing is local -Z rotated about local Y by yaw and transformed into world space
-               const glm::vec3 facing(normalize(glm::vec3(glm::vec4(rotateY(glm::vec3(0.0f, 0.0f, -1.0f), state.yaw), 0.0f) * transpose(model_transform))));
+               const glm::vec3 facing(glm::normalize(glm::vec3(glm::vec4(glm::rotateY(glm::vec3(0.0f, 0.0f, -1.0f), state.yaw), 0.0f) * glm::transpose(model_transform))));
                // only adjust if velocity isn't almost parallel to up
-               float vel_dot_up = dot(Velocity(), up);
+               float vel_dot_up = glm::dot(Velocity(), up);
                if (std::abs(1.0f - std::abs(vel_dot_up)) > std::numeric_limits<float>::epsilon()) {
                        // get direction of velocity projected onto model plane
-                       glm::vec3 direction(normalize(Velocity() - (Velocity() * vel_dot_up)));
+                       glm::vec3 direction(glm::normalize(Velocity() - (Velocity() * vel_dot_up)));
                        // if velocity points away from our facing (with a little bias), flip it around
                        // (the entity is "walking backwards")
-                       if (dot(facing, direction) < -0.1f) {
+                       if (glm::dot(facing, direction) < -0.1f) {
                                direction = -direction;
                        }
                        // calculate the difference between forward and direction
-                       const float absolute_difference = std::acos(dot(forward, direction));
+                       const float absolute_difference = std::acos(glm::dot(forward, direction));
                        // if direction is clockwise with respect to up vector, invert the angle
-                       const float relative_difference = dot(cross(forward, direction), up) < 0.0f
+                       const float relative_difference = glm::dot(glm::cross(forward, direction), up) < 0.0f
                                ? -absolute_difference
                                : absolute_difference;
                        // only correct by half the difference max
                                std::cout << std::endl;
                        }
                        // now rotate body by correction and head by -correction
-                       state.orient = rotate(state.orient, correction, up);
+                       state.orient = glm::rotate(state.orient, correction, up);
                        state.yaw -= correction;
                }
        }
        if (std::abs(state.yaw) > max_head_yaw) {
                float deviation = state.yaw < 0.0f ? state.yaw + max_head_yaw : state.yaw - max_head_yaw;
                // rotate the entity by deviation about local Y
-               state.orient = rotate(state.orient, deviation, up);
+               state.orient = glm::rotate(state.orient, deviation, up);
                // and remove from head yaw
                state.yaw -= deviation;
                // shouldn't be necessary if max_head_yaw is < PI, but just to be sure :p
 
 glm::mat4 EntityState::Transform(const glm::ivec3 &reference) const noexcept {
        const glm::vec3 translation = RelativePosition(reference);
-       glm::mat4 transform(toMat4(orient));
+       glm::mat4 transform(glm::toMat4(orient));
        transform[3] = glm::vec4(translation, 1.0f);
        return transform;
 }
                world.Random().SNorm() * wander_disp
        );
        if (!iszero(displacement)) {
-               wander_pos = normalize(wander_pos + displacement * dt) * wander_radius;
+               wander_pos = glm::normalize(wander_pos + displacement * dt) * wander_radius;
        }
 }
 
        for (const WorldCollision &c : col) {
                // diff points from block to state
                glm::vec3 diff = entity.GetState().RelativePosition(c.ChunkPos()) - c.BlockCoords();
-               float dist = length2(diff);
+               float dist = glm::length2(diff);
                if (dist < distance) {
                        nearest = &c;
                        difference = diff;
                return;
        }
        // and try to avoid it
-       float to_go = dot(difference, entity.Heading());
+       float to_go = glm::dot(difference, entity.Heading());
        glm::vec3 point(entity.Position() + entity.Heading() * to_go);
-       obstacle_dir = normalize(point - nearest->BlockCoords()) * (entity.Speed() / std::sqrt(distance));
+       obstacle_dir = glm::normalize(point - nearest->BlockCoords()) * (entity.Speed() / std::sqrt(distance));
 }
 
 glm::vec3 Steering::Force(const EntityState &state) const noexcept {
 }
 
 bool Steering::SumForce(glm::vec3 &out, const glm::vec3 &in, float max) noexcept {
-       if (iszero(in) || any(isnan(in))) {
+       if (iszero(in) || glm::any(glm::isnan(in))) {
                return false;
        }
-       float current = iszero(out) ? 0.0f : length(out);
+       float current = iszero(out) ? 0.0f : glm::length(out);
        float remain = max - current;
        if (remain <= 0.0f) {
                return true;
        }
-       float additional = length(in);
+       float additional = glm::length(in);
        if (additional > remain) {
-               out += normalize(in) * remain;
+               out += glm::normalize(in) * remain;
                return true;
        } else {
                out += in;
        if (iszero(diff)) {
                return glm::vec3(0.0f);
        } else {
-               return TargetVelocity(state, normalize(diff) * speed);
+               return TargetVelocity(state, glm::normalize(diff) * speed);
        }
 }
 
        if (iszero(diff)) {
                return glm::vec3(0.0f);
        } else {
-               return TargetVelocity(state, normalize(diff) * speed);
+               return TargetVelocity(state, glm::normalize(diff) * speed);
        }
 }
 
 glm::vec3 Steering::Arrive(const EntityState &state, const ExactLocation &loc) const noexcept {
        const glm::vec3 diff(loc.Difference(state.pos).Absolute());
-       const float dist = length(diff);
+       const float dist = glm::length(diff);
        if (dist < std::numeric_limits<float>::epsilon()) {
                return glm::vec3(0.0f);
        } else {
        if (iszero(diff)) {
                return TargetVelocity(state, other.Velocity());
        } else {
-               const float time_estimate = length(diff) / speed;
+               const float time_estimate = glm::length(diff) / speed;
                ExactLocation prediction(other.ChunkCoords(), other.Position() + (other.Velocity() * time_estimate));
                return Seek(state, prediction);
        }
        if (iszero(diff)) {
                return TargetVelocity(state, -other.Velocity());
        } else {
-               const float time_estimate = length(diff) / speed;
+               const float time_estimate = glm::length(diff) / speed;
                ExactLocation prediction(other.ChunkCoords(), other.Position() + (other.Velocity() * time_estimate));
                return Flee(state, prediction);
        }
 }
 
 glm::vec3 Steering::Wander(const EntityState &state) const noexcept {
-       return TargetVelocity(state, normalize(entity.Heading() * wander_dist + wander_pos) * speed);
+       return TargetVelocity(state, glm::normalize(entity.Heading() * wander_dist + wander_pos) * speed);
 }
 
 glm::vec3 Steering::ObstacleAvoidance(const EntityState &state) const noexcept {
        }
        // if entity is already going in the direction of correction,
        // let the problem resolve itself
-       if (dot(state.velocity, correction) >= 0.0f) {
+       if (glm::dot(state.velocity, correction) >= 0.0f) {
                return;
        }
        // apply correction, maybe could use some damping, gotta test
        state.pos.block += correction;
        // kill velocity?
-       glm::vec3 normal_velocity(proj(state.velocity, correction));
+       glm::vec3 normal_velocity(glm::proj(state.velocity, correction));
        state.velocity -= normal_velocity;
 }
 
                if (!c.Blocks()) continue;
                glm::vec3 normal(c.normal);
                // swap if neccessary (normal may point away from the entity)
-               if (dot(normal, state.RelativePosition(c.ChunkPos()) - c.BlockCoords()) < 0) {
+               if (glm::dot(normal, state.RelativePosition(c.ChunkPos()) - c.BlockCoords()) < 0) {
                        normal = -normal;
                }
                // check if block surface is "inside"
                        continue;
                }
                glm::vec3 local_pen(normal * c.depth);
-               min_pen = min(min_pen, local_pen);
-               max_pen = max(max_pen, local_pen);
+               min_pen = glm::min(min_pen, local_pen);
+               max_pen = glm::max(max_pen, local_pen);
        }
        glm::vec3 pen(0.0f);
        // only apply correction for axes where penetration is only in one direction
        glm::vec3 &col,
        glm::vec3 &amb
 ) {
-       BlockLookup center(chunks.Get(e.ChunkCoords()), e.Position());
+       BlockLookup center(chunks.Get(e.ChunkCoords()), RoughLocation::Fine(e.Position()));
        if (!center) {
                // chunk unavailable, so make it really dark and from
                // some arbitrary direction
        PrimitiveMesh debug_mesh;
        PlainColor &prog = viewport.WorldColorProgram();
        for (const Entity &entity : entities) {
-               debug_buf.OutlineBox(entity.Bounds(), glm::tvec4<unsigned char>(255, 0, 0, 255));
+               debug_buf.OutlineBox(entity.Bounds(), TVEC4<unsigned char, glm::precision(0)>(255, 0, 0, 255));
                debug_mesh.Update(debug_buf);
                prog.SetM(entity.Transform(players.front().GetEntity().ChunkCoords()));
                debug_mesh.DrawLines();
 
        );
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
                "bad intersection normal (with rotation)",
-               glm::vec3(1, 0, 0), abs(normal) // normal can be in + or - x, therefore abs()
+               glm::vec3(1, 0, 0), glm::abs(normal) // normal can be in + or - x, therefore abs()
        );
 
        Mb = glm::translate(glm::vec3(3, 0, 0)); // 3 to the right
 
 #define BLANK_TEST_GEOMETRY_LOCATIONTEST_HPP_
 
 #include "geometry/Location.hpp"
+#include "graphics/glm.hpp"
 
 #include <string>
-#include <glm/glm.hpp>
 #include <cppunit/extensions/HelperMacros.h>
 
 
 
 
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
                "bad component type for vec2i",
-               GLenum(GL_INT), gl_traits<glm::tvec2<int>>::type
+               GLenum(GL_INT), gl_traits<glm::ivec2>::type
        );
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
                "bad component type for vec3i",
-               GLenum(GL_INT), gl_traits<glm::tvec3<int>>::type
+               GLenum(GL_INT), gl_traits<glm::ivec3>::type
        );
        CPPUNIT_ASSERT_EQUAL_MESSAGE(
                "bad component type for vec4i",
-               GLenum(GL_INT), gl_traits<glm::tvec4<int>>::type
+               GLenum(GL_INT), gl_traits<glm::ivec4>::type
        );
 }
 
 
        EntityState write_state;
        write_state.pos = { { 7, 2, -3 }, { 1.5f, 0.9f, 12.0f } };
        write_state.velocity = { 0.025f, 0.001f, 0.0f };
-       write_state.orient = normalize(glm::quat(0.863f, 0.0f, 0.505f, 0.0f));
+       write_state.orient = glm::normalize(glm::quat(0.863f, 0.0f, 0.505f, 0.0f));
        write_state.pitch = 0.3f;
        write_state.yaw = -2.3f;
        write_entity.SetState(write_state);
 
 #define BLANK_TEST_NET_PACKETTEST_HPP_
 
 #include "geometry/primitive.hpp"
+#include "graphics/glm.hpp"
 #include "net/Packet.hpp"
 #include "world/EntityState.hpp"
 
 #include <limits>
 #include <string>
 #include <SDL_net.h>
-#include <glm/glm.hpp>
 #include <cppunit/extensions/HelperMacros.h>
 
 
 
 #ifndef BLANK_TEST_RAND_STABILITYTEST_HPP
 #define BLANK_TEST_RAND_STABILITYTEST_HPP
 
-#include <glm/glm.hpp>
+#include "graphics/glm.hpp"
+
 #include <cppunit/extensions/HelperMacros.h>