]> git.localhorst.tv Git - tacos.git/commitdiff
isolate some GL stuff master
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 18 Mar 2016 11:15:53 +0000 (12:15 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 18 Mar 2016 11:55:50 +0000 (12:55 +0100)
src/graphics/buffer.hpp [new file with mode: 0644]
src/graphics/gl_traits.cpp [new file with mode: 0644]
src/graphics/gl_traits.hpp [new file with mode: 0644]
src/graphics/vao.hpp [new file with mode: 0644]
src/world/Cursor.hpp
src/world/world.cpp

diff --git a/src/graphics/buffer.hpp b/src/graphics/buffer.hpp
new file mode 100644 (file)
index 0000000..288cdc8
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef TACOS_GRAPHICS_BUFFER_HPP_
+#define TACOS_GRAPHICS_BUFFER_HPP_
+
+#include "../app/error.hpp"
+
+#include <algorithm>
+#include <GL/glew.h>
+
+
+namespace tacos {
+
+template<class T>
+class MappedBuffer {
+
+public:
+       MappedBuffer(GLenum target, GLenum access)
+       : buf(reinterpret_cast<T *>(glMapBuffer(target, access)))
+       , target(target) {
+               if (!buf) {
+                       throw GLError("failed to map buffer");
+               }
+       }
+       MappedBuffer()
+       : buf(nullptr)
+       , target(0) {
+       }
+       ~MappedBuffer() noexcept {
+               if (buf) {
+                       glUnmapBuffer(target);
+               }
+       }
+
+       MappedBuffer(MappedBuffer<T> &&other) noexcept
+       : buf(other.buf)
+       , target(other.target) {
+               other.buf = nullptr;
+       }
+       MappedBuffer<T> &operator =(MappedBuffer<T> &&other) noexcept {
+               std::swap(buf, other.buf);
+               std::swap(target, other.target);
+       }
+
+       MappedBuffer(const MappedBuffer<T> &) = delete;
+       MappedBuffer<T> &operator =(const MappedBuffer<T> &) = delete;
+
+       explicit operator bool() const noexcept { return buf; }
+
+public:
+       T &operator [](std::size_t i) noexcept { return buf[i]; }
+       const T &operator [](std::size_t i) const noexcept { return buf[i]; }
+
+private:
+       T *buf;
+       GLenum target;
+
+};
+
+}
+
+#endif
diff --git a/src/graphics/gl_traits.cpp b/src/graphics/gl_traits.cpp
new file mode 100644 (file)
index 0000000..1dd35e7
--- /dev/null
@@ -0,0 +1,30 @@
+#include "gl_traits.hpp"
+
+
+namespace tacos {
+
+constexpr GLint gl_traits<signed char>::size;
+constexpr GLenum gl_traits<signed char>::type;
+
+constexpr GLint gl_traits<unsigned char>::size;
+constexpr GLenum gl_traits<unsigned char>::type;
+
+constexpr GLint gl_traits<short>::size;
+constexpr GLenum gl_traits<short>::type;
+
+constexpr GLint gl_traits<unsigned short>::size;
+constexpr GLenum gl_traits<unsigned short>::type;
+
+constexpr GLint gl_traits<int>::size;
+constexpr GLenum gl_traits<int>::type;
+
+constexpr GLint gl_traits<unsigned int>::size;
+constexpr GLenum gl_traits<unsigned int>::type;
+
+constexpr GLint gl_traits<float>::size;
+constexpr GLenum gl_traits<float>::type;
+
+constexpr GLint gl_traits<double>::size;
+constexpr GLenum gl_traits<double>::type;
+
+}
diff --git a/src/graphics/gl_traits.hpp b/src/graphics/gl_traits.hpp
new file mode 100644 (file)
index 0000000..43caf03
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef TACOS_GRAPHICS_GL_TRAITS_HPP_
+#define TACOS_GRAPHICS_GL_TRAITS_HPP_
+
+#include <GL/glew.h>
+#include <glm/glm.hpp>
+
+
+namespace tacos {
+
+template<class T>
+struct gl_traits {
+
+       /// number of components per generic attribute
+       /// must be 1, 2, 3, 4
+       // static constexpr GLint size;
+
+       /// component type
+       /// accepted values are:
+       ///   GL_BYTE, GL_UNSIGNED_BYTE,
+       ///   GL_SHORT, GL_UNSIGNED_SHORT,
+       ///   GL_INT, GL_UNSIGNED_INT,
+       ///   GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE,
+       ///   GL_FIXED, GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV
+       // static constexpr GLenum type;
+
+};
+
+
+// basic types
+
+template<> struct gl_traits<signed char> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_BYTE;
+};
+
+template<> struct gl_traits<unsigned char> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_UNSIGNED_BYTE;
+};
+
+template<> struct gl_traits<short> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_SHORT;
+};
+
+template<> struct gl_traits<unsigned short> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_UNSIGNED_SHORT;
+};
+
+template<> struct gl_traits<int> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_INT;
+};
+
+template<> struct gl_traits<unsigned int> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_UNSIGNED_INT;
+};
+
+template<> struct gl_traits<float> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_FLOAT;
+};
+
+template<> struct gl_traits<double> {
+       static constexpr GLint size = 1;
+       static constexpr GLenum type = GL_DOUBLE;
+};
+
+// composite types
+
+template<>
+template<class T, glm::precision P>
+struct gl_traits<glm::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;
+template<class T, glm::precision P>
+constexpr GLenum gl_traits<glm::tvec1<T, P>>::type;
+
+template<>
+template<class T, glm::precision P>
+struct gl_traits<glm::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;
+template<class T, glm::precision P>
+constexpr GLenum gl_traits<glm::tvec2<T, P>>::type;
+
+template<>
+template<class T, glm::precision P>
+struct gl_traits<glm::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;
+template<class T, glm::precision P>
+constexpr GLenum gl_traits<glm::tvec3<T, P>>::type;
+
+template<>
+template<class T, glm::precision P>
+struct gl_traits<glm::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;
+template<class T, glm::precision P>
+constexpr GLenum gl_traits<glm::tvec4<T, P>>::type;
+
+}
+
+#endif
diff --git a/src/graphics/vao.hpp b/src/graphics/vao.hpp
new file mode 100644 (file)
index 0000000..debed55
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef TACOS_GRAPHICS_VAO_HPP_
+#define TACOS_GRAPHICS_VAO_HPP_
+
+#include "buffer.hpp"
+#include "gl_traits.hpp"
+
+#include <GL/glew.h>
+
+
+namespace tacos {
+
+/// Simple vertex array object based on indexed draw calls with attributes
+/// interleaved in a single buffer.
+template<class Attributes, class Element>
+class SimpleVAO {
+
+public:
+       SimpleVAO()
+       : vao(0)
+       , buffers{0} {
+               glGenVertexArrays(1, &vao);
+               glGenBuffers(2, buffers);
+       }
+       ~SimpleVAO() noexcept {
+               glDeleteBuffers(2, buffers);
+               glDeleteVertexArrays(1, &vao);
+       }
+
+       SimpleVAO(const SimpleVAO &) = delete;
+       SimpleVAO &operator =(const SimpleVAO &) = delete;
+
+public:
+       void Bind() const noexcept {
+               glBindVertexArray(vao);
+       }
+       void Unbind() const noexcept {
+               glBindVertexArray(0);
+       }
+       void BindAttributes() const noexcept {
+               glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       }
+       void BindElements() const noexcept {
+               glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
+       }
+       void EnableAttribute(GLuint index) noexcept {
+               glEnableVertexAttribArray(index);
+       }
+       void DisableAttribute(GLuint index) noexcept {
+               glDisableVertexAttribArray(index);
+       }
+       template<class Attribute>
+       void AttributePointer(GLuint index, bool normalized, std::size_t offset) noexcept {
+               glVertexAttribPointer(
+                       index,
+                       gl_traits<Attribute>::size,
+                       gl_traits<Attribute>::type,
+                       normalized,
+                       sizeof(Attributes),
+                       reinterpret_cast<const void *>(offset)
+               );
+       }
+       void ReserveAttributes(std::size_t size, GLenum usage) noexcept {
+               glBufferData(GL_ARRAY_BUFFER, size * sizeof(Attributes), nullptr, usage);
+       }
+       MappedBuffer<Attributes> MapAttributes(GLenum access) {
+               return MappedBuffer<Attributes>(GL_ARRAY_BUFFER, access);
+       }
+       void ReserveElements(std::size_t size, GLenum usage) noexcept {
+               glBufferData(GL_ELEMENT_ARRAY_BUFFER, size * sizeof(Element), nullptr, usage);
+       }
+       MappedBuffer<Element> MapElements(GLenum access) {
+               return MappedBuffer<Element>(GL_ELEMENT_ARRAY_BUFFER, access);
+       }
+       void DrawTriangles(std::size_t size, std::size_t offset = 0) const noexcept {
+               glDrawElements(GL_TRIANGLES, size, gl_traits<Element>::type, ((Element *) nullptr) + offset);
+       }
+
+private:
+       GLuint vao;
+       GLuint buffers[2];
+
+};
+
+}
+
+#endif
index 828e411209b89cb6022a997a689e7b5d83a70a4a..74603194ae45cfe5efa9dbd6426d7f1855db5962 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef TACOS_WORLD_CURSOR_HPP_
 #define TACOS_WORLD_CURSOR_HPP_
 
-#include <GL/glew.h>
-#include <glm/glm.hpp>
+#include "../graphics/vao.hpp"
 
 
 namespace tacos {
@@ -13,10 +12,6 @@ class Cursor {
 
 public:
        Cursor();
-       ~Cursor();
-
-       Cursor(const Cursor &) = delete;
-       Cursor &operator =(const Cursor &) = delete;
 
        /// hide cursor
        void Hide() noexcept;
@@ -27,8 +22,11 @@ public:
        void Draw() const noexcept;
 
 private:
-       GLuint vao;
-       GLuint buffers[2];
+       struct Attributes {
+               glm::vec3 position;
+       };
+
+       SimpleVAO<Attributes, unsigned char> vao;
 
        // side length in vertices (make sure it's between 2 and 8 inclusive)
        int size;
@@ -40,10 +38,6 @@ private:
                FLOOR,
        } mode;
 
-       struct Attributes {
-               glm::vec3 position;
-       };
-
 };
 
 }
index b7037f0c157723ebc574d9416d15b277beeba7b1..03ff1975e4db620c3517d423a2e0e46a888f6d2d 100644 (file)
@@ -1,6 +1,8 @@
 #include "Cursor.hpp"
 #include "Floor.hpp"
 
+#include "../graphics/buffer.hpp"
+
 #include <iostream>
 #include <glm/gtx/io.hpp>
 
 namespace tacos {
 
 Cursor::Cursor()
-: vao(0)
-, buffers{0}
+: vao()
 , size(3)
 , offset(0.1f)
 , mode(HIDDEN) {
-       glGenVertexArrays(1, &vao);
-       glGenBuffers(2, buffers);
-
-       glBindVertexArray(vao);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glEnableVertexAttribArray(0);
-       glVertexAttribPointer(0, 3, GL_FLOAT, 0, sizeof(Attributes), reinterpret_cast<const void *>(offsetof(Attributes, position)));
-       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
-       glBindVertexArray(0);
-}
-
-Cursor::~Cursor() {
-       glDeleteBuffers(2, buffers);
-       glDeleteVertexArrays(1, &vao);
+       vao.Bind();
+       vao.BindAttributes();
+       vao.EnableAttribute(0);
+       vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
+       vao.BindElements();
+       vao.Unbind();
 }
 
 void Cursor::Hide() noexcept {
@@ -42,37 +35,39 @@ void Cursor::FloorTile(const Floor &floor, int tile_x, int tile_z) {
        int z_begin = glm::clamp(tile_z, 0, floor.Depth() - size);
        int z_end = z_begin + size;
 
-       glBindVertexArray(vao);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glBufferData(GL_ARRAY_BUFFER, size * size * sizeof(Attributes), nullptr, GL_DYNAMIC_DRAW);
-       Attributes *attrib = reinterpret_cast<Attributes *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
-       for (int z = z_begin, index = 0; z < z_end; ++z) {
-               for (int x = x_begin; x < x_end; ++x, ++index) {
-                       attrib[index].position = glm::vec3(x, floor.GetElevation(x, z) + offset, z);
+       vao.Bind();
+       vao.BindAttributes();
+       vao.ReserveAttributes(size * size, GL_DYNAMIC_DRAW);
+       {
+               MappedBuffer<Attributes> attrib(vao.MapAttributes(GL_WRITE_ONLY));
+               for (int z = z_begin, index = 0; z < z_end; ++z) {
+                       for (int x = x_begin; x < x_end; ++x, ++index) {
+                               attrib[index].position = glm::vec3(x, floor.GetElevation(x, z) + offset, z);
+                       }
                }
        }
-       glUnmapBuffer(GL_ARRAY_BUFFER);
-
-       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
-       glBufferData(GL_ELEMENT_ARRAY_BUFFER, (size - 1) * (size - 1) * 6, nullptr, GL_DYNAMIC_DRAW);
-       unsigned char *element = reinterpret_cast<unsigned char *>(glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY));
-       for (int z = 0, index = 0; z < size - 1; ++z) {
-               for (int x = 0; x < size - 1; ++x, ++index) {
-                       element[index * 6 + 0] = (z + 0) * size + (x + 0);
-                       element[index * 6 + 1] = (z + 0) * size + (x + 1);
-                       element[index * 6 + 2] = (z + 1) * size + (x + 0);
-                       element[index * 6 + 3] = (z + 0) * size + (x + 1);
-                       element[index * 6 + 4] = (z + 1) * size + (x + 1);
-                       element[index * 6 + 5] = (z + 1) * size + (x + 0);
+
+       vao.BindElements();
+       vao.ReserveElements((size - 1) * (size - 1) * 6, GL_DYNAMIC_DRAW);
+       {
+               MappedBuffer<unsigned char> element(vao.MapElements(GL_WRITE_ONLY));
+               for (int z = 0, index = 0; z < size - 1; ++z) {
+                       for (int x = 0; x < size - 1; ++x, ++index) {
+                               element[index * 6 + 0] = (z + 0) * size + (x + 0);
+                               element[index * 6 + 1] = (z + 0) * size + (x + 1);
+                               element[index * 6 + 2] = (z + 1) * size + (x + 0);
+                               element[index * 6 + 3] = (z + 0) * size + (x + 1);
+                               element[index * 6 + 4] = (z + 1) * size + (x + 1);
+                               element[index * 6 + 5] = (z + 1) * size + (x + 0);
+                       }
                }
        }
-       glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
-       glBindVertexArray(0);
+       vao.Unbind();
 }
 
 void Cursor::Draw() const noexcept {
-       glBindVertexArray(vao);
-       glDrawElements(GL_TRIANGLES, (size - 1) * (size - 1) * 6, GL_UNSIGNED_BYTE, nullptr);
+       vao.Bind();
+       vao.DrawTriangles((size - 1) * (size - 1) * 6);
 }
 
 
@@ -145,9 +140,7 @@ void Floor::FillElementBuffer(GLuint which, int tile_width, int tile_depth) {
        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, which);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, tile_width * tile_depth * sizeof(short) * 6, nullptr, GL_STATIC_DRAW);
-       // TODO: this can return null on error (out of memory in this case)
-       //       might be worth checking eventually
-       short *data = reinterpret_cast<short *>(glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY));
+       MappedBuffer<short> data(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
        for (int z = 0, i = 0; z < tile_depth; ++z) {
                for (int x = 0; x < tile_width; ++x, ++i) {
                        data[i * 6 + 0] = (z + 0) * (tile_width + 1) + (x + 0);
@@ -158,12 +151,11 @@ void Floor::FillElementBuffer(GLuint which, int tile_width, int tile_depth) {
                        data[i * 6 + 5] = (z + 1) * (tile_width + 1) + (x + 0);
                }
        }
-       glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
 }
 
 void Floor::FillAttribBuffer(int vao_x, int vao_z) {
        glBindBuffer(GL_ARRAY_BUFFER, buffers[vao_z * vao_width + vao_x]);
-       Attributes *data = reinterpret_cast<Attributes *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
+       MappedBuffer<Attributes> data(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
        glm::ivec2 tiles(Tiles(vao_x, vao_z));
        for (int z = 0, abs_z = vao_z * VAO_DIVISOR, i = 0; z < tiles.y + 1; ++z, ++abs_z) {
                for (int x = 0, abs_x = vao_x * VAO_DIVISOR; x < tiles.x + 1; ++x, ++abs_x, ++i) {
@@ -171,7 +163,6 @@ void Floor::FillAttribBuffer(int vao_x, int vao_z) {
                        data[i].normal = GetNormal(abs_x, abs_z);
                }
        }
-       glUnmapBuffer(GL_ARRAY_BUFFER);
 }
 
 glm::vec3 Floor::GetNormal(int x, int z) const noexcept {