summaryrefslogtreecommitdiff
path: root/gfx/gl/glTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl/glTexture.cpp')
-rw-r--r--gfx/gl/glTexture.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/gfx/gl/glTexture.cpp b/gfx/gl/glTexture.cpp
new file mode 100644
index 0000000..51a27ed
--- /dev/null
+++ b/gfx/gl/glTexture.cpp
@@ -0,0 +1,195 @@
+#include "glTexture.h"
+#include "config/types.h"
+#include "filesystem.h"
+#include "gfx/models/tga.h"
+#include "maths.h"
+#include <fcntl.h>
+#include <ranges>
+#include <sys/mman.h>
+
+void
+Impl::glTextureBase::bind(const GLuint unit) const
+{
+ glBindTextureUnit(unit, name);
+}
+
+void
+Impl::glTextureBase::generateMipmap()
+{
+ glGenerateTextureMipmap(name);
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+glm::vec<Dims, GLsizei>
+Impl::glTextureDims<Dims>::getSize() const
+{
+ static constexpr std::array<GLenum, 3> PARAMS {GL_TEXTURE_WIDTH, GL_TEXTURE_HEIGHT, GL_TEXTURE_DEPTH};
+ glm::vec<Dims, GLsizei> size {};
+ for (auto [dim, param] : std::views::enumerate(PARAMS) | std::views::take(Dims)) {
+ glGetTextureLevelParameteriv(name, 0, param, &size[static_cast<glm::length_t>(dim)]);
+ }
+ return size;
+}
+
+template<>
+void
+Impl::glTextureDims<1>::storage(const GLsizei levels, const GLenum internalformat, glm::vec<1, GLsizei> dims)
+{
+ glTextureStorage1D(name, levels, internalformat, dims.x);
+}
+
+template<>
+void
+Impl::glTextureDims<2>::storage(const GLsizei levels, const GLenum internalformat, glm::vec<2, GLsizei> dims)
+{
+ glTextureStorage2D(name, levels, internalformat, dims.x, dims.y);
+}
+
+template<>
+void
+Impl::glTextureDims<3>::storage(const GLsizei levels, const GLenum internalformat, glm::vec<3, GLsizei> dims)
+{
+ glTextureStorage3D(name, levels, internalformat, dims.x, dims.y, dims.z);
+}
+
+template<>
+void
+Impl::glTextureDims<1>::subImage(
+ glm::vec<1, GLint> offset, glm::vec<1, GLint> size, const GLenum format, const GLenum type, const void * pixels)
+{
+ glTextureSubImage1D(name, 0, offset.x, size.x, format, type, pixels);
+}
+
+template<>
+void
+Impl::glTextureDims<2>::subImage(
+ glm::vec<2, GLint> offset, glm::vec<2, GLint> size, const GLenum format, const GLenum type, const void * pixels)
+{
+ glTextureSubImage2D(name, 0, offset.x, offset.y, size.x, size.y, format, type, pixels);
+}
+
+template<>
+void
+Impl::glTextureDims<3>::subImage(
+ glm::vec<3, GLint> offset, glm::vec<3, GLint> size, const GLenum format, const GLenum type, const void * pixels)
+{
+ glTextureSubImage3D(name, 0, offset.x, offset.y, offset.z, size.x, size.y, size.z, format, type, pixels);
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+void
+Impl::glTextureDims<Dims>::image(
+ glm::vec<Dims, GLint> size, const GLenum format, const GLenum type, const void * pixels)
+{
+ subImage({}, size, format, type, pixels);
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+void
+Impl::glTextureDims<Dims>::image(const GLenum format, const GLenum type, const void * pixels)
+{
+ image(getSize(), format, type, pixels);
+}
+
+namespace {
+ template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+ size_t
+ areaOf(glm::vec<Dims, GLsizei> size)
+ {
+ size_t area = 1;
+ for (auto dim = 0; dim < Dims; ++dim) {
+ area *= static_cast<size_t>(size[dim]);
+ }
+ return area;
+ }
+
+ template<glm::length_t Dims, glm::length_t channels>
+ requires(Dims >= 1 && Dims <= 3)
+ void
+ save(const Impl::glTextureDims<Dims> & texture, const GLenum format, const GLenum type, const char * path,
+ uint8_t tgaFormat)
+ {
+ const auto size = texture.getSize();
+ const auto area = areaOf(size);
+ size_t dataSize = area * channels;
+ const size_t fileSize = dataSize + sizeof(TGAHead<channels>);
+
+ filesystem::fh out {path, O_RDWR | O_CREAT, 0660};
+ out.truncate(fileSize);
+ auto tga = out.mmap(fileSize, 0, PROT_WRITE, MAP_SHARED);
+ auto outTga = tga.get<TGAHead<channels>>();
+ *outTga = {
+ .format = tgaFormat,
+ .size = {size.x, (area / static_cast<size_t>(size.x))},
+ };
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glGetTextureImage(texture, 0, format, type, static_cast<GLsizei>(dataSize), outTga->data);
+ tga.msync(MS_ASYNC);
+ }
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+void
+Impl::glTextureDims<Dims>::saveColour(const char * path) const
+{
+ save<Dims, 3>(*this, GL_BGR, GL_UNSIGNED_BYTE, path, 2);
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+void
+Impl::glTextureDims<Dims>::savePosition(const char * path) const
+{
+ const auto size = getSize();
+ const auto area = areaOf(size);
+ size_t dataSize = area * sizeof(TGAHead<3>::PixelType);
+ const size_t fileSize = dataSize + sizeof(TGAHead<3>);
+
+ filesystem::fh out {path, O_RDWR | O_CREAT, 0660};
+ out.truncate(fileSize);
+ auto tga = out.mmap(fileSize, 0, PROT_WRITE, MAP_SHARED);
+ auto outTga = tga.get<TGAHead<3>>();
+ *outTga = {
+ .format = 2,
+ .size = {size.x, (area / static_cast<size_t>(size.x))},
+ };
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ std::vector<RelativePosition3D> raw {area};
+ glGetTextureImage(name, 0, GL_BGR, GL_FLOAT, static_cast<GLsizei>(sizeof(GlobalPosition3D) * area), raw.data());
+ using Comp = RelativePosition3D (*)(const RelativePosition3D &, const RelativePosition3D &);
+ auto notZero = std::views::filter([](const RelativePosition3D & pos) {
+ return pos != RelativePosition3D {};
+ });
+ const auto minPos = *std::ranges::fold_left_first(raw | notZero, static_cast<Comp>(&glm::min));
+ const auto maxPos = *std::ranges::fold_left_first(raw | notZero, static_cast<Comp>(&glm::max));
+ const auto rangePos = difference(maxPos, minPos);
+ std::ranges::transform(raw, outTga->data, [minPos, rangePos](const auto & pos) {
+ return 255.F * ((pos - minPos) / rangePos);
+ });
+ tga.msync(MS_ASYNC);
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+void
+Impl::glTextureDims<Dims>::saveDepth(const char * path) const
+{
+ save<Dims, 1>(*this, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, path, 3);
+}
+
+template<glm::length_t Dims>
+ requires(Dims >= 1 && Dims <= 3)
+void
+Impl::glTextureDims<Dims>::saveNormal(const char * path) const
+{
+ save<Dims, 3>(*this, GL_BGR, GL_BYTE, path, 2);
+}
+
+template struct Impl::glTextureDims<1>;
+template struct Impl::glTextureDims<2>;
+template struct Impl::glTextureDims<3>;