+Cursor::Cursor()
+: vao(0)
+, buffers{0}
+, 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);
+}
+
+void Cursor::Hide() noexcept {
+ mode = HIDDEN;
+}
+
+void Cursor::FloorTile(const Floor &floor, int tile_x, int tile_z) {
+ // TODO: only update if changed
+ mode = FLOOR;
+
+ int x_begin = glm::clamp(tile_x, 0, floor.Width() - size);
+ int x_end = x_begin + size;
+ 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);
+ }
+ }
+ 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);
+ }
+ }
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ glBindVertexArray(0);
+}
+
+void Cursor::Draw() const noexcept {
+ glBindVertexArray(vao);
+ glDrawElements(GL_TRIANGLES, (size - 1) * (size - 1) * 6, GL_UNSIGNED_BYTE, nullptr);
+}
+
+