summaryrefslogtreecommitdiff
path: root/src/gl/texture.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gl/texture.h')
-rw-r--r--src/gl/texture.h259
1 files changed, 259 insertions, 0 deletions
diff --git a/src/gl/texture.h b/src/gl/texture.h
new file mode 100644
index 0000000..17541e0
--- /dev/null
+++ b/src/gl/texture.h
@@ -0,0 +1,259 @@
+// Copyright 2021 Benjamin Barenblat
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Texture objects.
+
+#ifndef GLPLANET_SRC_GL_TEXTURE_H_
+#define GLPLANET_SRC_GL_TEXTURE_H_
+
+#include "src/gl/error.h"
+#include "src/util.h"
+#include "third_party/glew/include/GL/glew.h"
+
+namespace gl {
+
+class Texture2d;
+
+// A generic texture. You can't instantiate this directly; instead, instantiate
+// one of its derived classes with an explicit dimensionality.
+class Texture {
+ public:
+ // Options for the texture's sample format.
+ enum class Format : GLenum {
+ kR8 = GL_R8,
+ kR8Snorm = GL_R8_SNORM,
+ kR16 = GL_R16,
+ kR16Snorm = GL_R16_SNORM,
+ kRg8 = GL_RG8,
+ kRg8Snorm = GL_RG8_SNORM,
+ kRg16 = GL_RG16,
+ kRg16Snorm = GL_RG16_SNORM,
+ kR3G3B2 = GL_R3_G3_B2,
+ kRgb4 = GL_RGB4,
+ kRgb5 = GL_RGB5,
+ kRgb8 = GL_RGB8,
+ kRgb8Snorm = GL_RGB8_SNORM,
+ kRgb10 = GL_RGB10,
+ kRgb12 = GL_RGB12,
+ kRgb16Snorm = GL_RGB16_SNORM,
+ kRgba2 = GL_RGBA2,
+ kRgba4 = GL_RGBA4,
+ kRgb5A1 = GL_RGB5_A1,
+ kRgba8 = GL_RGBA8,
+ kRgba8Snorm = GL_RGBA8_SNORM,
+ kRgb10A2 = GL_RGB10_A2,
+ kRgb10A2Ui = GL_RGB10_A2UI,
+ kRgba12 = GL_RGBA12,
+ kRgba16 = GL_RGBA16,
+ kSrgb8 = GL_SRGB8,
+ kSrgb8Alpha8 = GL_SRGB8_ALPHA8,
+ kR16f = GL_R16F,
+ kRg16f = GL_RG16F,
+ kRgb16f = GL_RGB16F,
+ kRgba16f = GL_RGBA16F,
+ kR32f = GL_R32F,
+ kRg32f = GL_RG32F,
+ kRgb32f = GL_RGB32F,
+ kRgba32f = GL_RGBA32F,
+ kR11fG11fB10f = GL_R11F_G11F_B10F,
+ kRgb9E5 = GL_RGB9_E5,
+ kR8i = GL_R8I,
+ kR8ui = GL_R8UI,
+ kR16i = GL_R16I,
+ kR16ui = GL_R16UI,
+ kR32i = GL_R32I,
+ kR32ui = GL_R32UI,
+ kRg8i = GL_RG8I,
+ kRg8ui = GL_RG8UI,
+ kRg16i = GL_RG16I,
+ kRg16ui = GL_RG16UI,
+ kRg32i = GL_RG32I,
+ kRg32ui = GL_RG32UI,
+ kRgb8i = GL_RGB8I,
+ kRgb8ui = GL_RGB8UI,
+ kRgb16i = GL_RGB16I,
+ kRgb16ui = GL_RGB16UI,
+ kRgb32i = GL_RGB32I,
+ kRgb32ui = GL_RGB32UI,
+ kRgba8i = GL_RGBA8I,
+ kRgba8ui = GL_RGBA8UI,
+ kRgba16i = GL_RGBA16I,
+ kRgba16ui = GL_RGBA16UI,
+ kRgba32i = GL_RGBA32I,
+ kRgba32ui = GL_RGBA32UI,
+ };
+
+ // Pixel order.
+ enum class PixelFormat : GLenum {
+ kRed = GL_RED,
+ kRg = GL_RG,
+ kRgb = GL_RGB,
+ kBgr = GL_BGR,
+ kRgba = GL_RGBA,
+ kBgra = GL_BGRA,
+ };
+
+ // Bits per pixel and subpixel.
+ enum class PixelType : GLenum {
+ kUnsignedByte = GL_UNSIGNED_BYTE,
+ kByte = GL_BYTE,
+ kUnsignedShort = GL_UNSIGNED_SHORT,
+ kShort = GL_SHORT,
+ kUnsignedInt = GL_UNSIGNED_INT,
+ kInt = GL_INT,
+ kFloat = GL_FLOAT,
+ kUnsignedByte332 = GL_UNSIGNED_BYTE_3_3_2,
+ kUnsignedByte233Rev = GL_UNSIGNED_BYTE_2_3_3_REV,
+ kUnsignedShort565 = GL_UNSIGNED_SHORT_5_6_5,
+ kUnsignedShort565Rev = GL_UNSIGNED_SHORT_5_6_5_REV,
+ kUnsignedShort4444 = GL_UNSIGNED_SHORT_4_4_4_4,
+ kUnsignedShort4444Rev = GL_UNSIGNED_SHORT_4_4_4_4_REV,
+ kUnsignedShort5551 = GL_UNSIGNED_SHORT_5_5_5_1,
+ kUnsignedShort1555Rev = GL_UNSIGNED_SHORT_1_5_5_5_REV,
+ kUnsignedInt8888 = GL_UNSIGNED_INT_8_8_8_8,
+ kUnsignedInt8888Rev = GL_UNSIGNED_INT_8_8_8_8_REV,
+ kUnsignedInt10x10x10x2 = GL_UNSIGNED_INT_10_10_10_2,
+ kUnsignedInt2x10x10x10Rev = GL_UNSIGNED_INT_2_10_10_10_REV,
+ };
+
+ // Filtering techniques.
+ enum class MinFilter : GLenum {
+ kNearest = GL_NEAREST,
+ kLinear = GL_LINEAR,
+ kNearestMipmapNearest = GL_NEAREST_MIPMAP_NEAREST,
+ kLinearMipmapNearest = GL_LINEAR_MIPMAP_NEAREST,
+ kNearestMipmapLinear = GL_NEAREST_MIPMAP_LINEAR,
+ kLinearMipmapLinear = GL_LINEAR_MIPMAP_LINEAR,
+ };
+ enum class MagFilter : GLenum {
+ kNearest = GL_NEAREST,
+ kLinear = GL_LINEAR,
+ };
+
+ // Wrapping techniques.
+ enum class Wrap : GLenum {
+ kClampToEdge = GL_CLAMP_TO_EDGE,
+ kClampToBorder = GL_CLAMP_TO_BORDER,
+ kMirroredRepeat = GL_MIRRORED_REPEAT,
+ kRepeat = GL_REPEAT,
+ kMirrorClampToEdge = GL_MIRROR_CLAMP_TO_EDGE,
+ };
+
+ Texture(Texture&&) noexcept = default;
+ Texture& operator=(Texture&&) noexcept = default;
+
+ virtual ~Texture() noexcept(!(gl_internal::kThreadSafetyChecks ||
+ gl_internal::kAggressiveErrorChecking)) {
+ gl_internal::CheckThreadSafety();
+ glDeleteTextures(1, &texture_);
+ gl_internal::UnnecessaryErrorCheck();
+ }
+
+ // The GL identifier for this texture.
+ unsigned int id() const noexcept { return texture_; }
+
+ protected:
+ int levels_;
+ GLuint texture_;
+
+ private:
+ friend class Texture2d;
+
+ explicit Texture(int levels) noexcept(!gl_internal::kThreadSafetyChecks)
+ : levels_(levels) {
+ gl_internal::CheckThreadSafety();
+ }
+};
+
+// A two-dimensional texture.
+class Texture2d final : public Texture {
+ public:
+ enum class Dimension : GLenum {
+ kS = GL_TEXTURE_WRAP_S,
+ kT = GL_TEXTURE_WRAP_T,
+ };
+
+ // Creates a two-dimensional texture with the specified pixel format, width,
+ // and height. The number of levels is equal to the number of mipmap layers
+ // for this texture; if you're not using mipmaps, you can leave it as 1.
+ explicit Texture2d(Format format, int width, int height, int levels = 1)
+ : Texture(levels), width_(width), height_(height) {
+ glCreateTextures(GL_TEXTURE_2D, 1, &texture_);
+ gl_internal::UnnecessaryErrorCheck();
+
+ glTextureStorage2D(texture_, levels, FromEnum(format), width_, height_);
+ // This error check is necessary because `format` could have been passed as
+ // an invalid GLenum.
+ gl_internal::ErrorCheck();
+ }
+
+ int width() const noexcept { return width_; }
+ int height() const noexcept { return height_; }
+
+ // Copies data from the specified buffer into GPU memory and associates it
+ // with this texture. width, height, format, and type describe the formatting
+ // of the data buffer, not this texture!
+ //
+ // There are no alignment restrictions on the buffer. It should consist of
+ // densely packed rows of pixels, left to right and top to bottom.
+ //
+ // As in the constructor, the optional level argument specifies which mipmap
+ // layer to populate. If you're not using mipmaps, you can leave it as 0.
+ void LoadSubimage(int width, int height, PixelFormat format, PixelType type,
+ const void* pixels, int level = 0);
+
+ // Fills all texture layers except layer 0 with automatically generated
+ // mipmaps. These mipmaps will generally be of lower quality than you would
+ // get if you generated them manually and loaded them with LoadSubimage.
+ // However, using them will yield a higher quality render than not using
+ // mipmaps at all.
+ void GenerateMipmaps() noexcept(!(gl_internal::kThreadSafetyChecks ||
+ gl_internal::kAggressiveErrorChecking)) {
+ gl_internal::CheckThreadSafety();
+ glGenerateTextureMipmap(texture_);
+ gl_internal::UnnecessaryErrorCheck();
+ }
+
+ void SetWrap(Dimension dimension, Wrap wrap) {
+ gl_internal::CheckThreadSafety();
+ glTexParameteri(GL_TEXTURE_2D, FromEnum(dimension), FromEnum(wrap));
+ // This error check is necessary because `dimension` or `wrap` could have
+ // been passed as an invalid GLenum.
+ gl_internal::ErrorCheck();
+ }
+
+ void SetMinFilter(MinFilter filter) {
+ gl_internal::CheckThreadSafety();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, FromEnum(filter));
+ // This error check is necessary because `filter` could have been passed as
+ // an invalid GLenum.
+ gl_internal::ErrorCheck();
+ }
+
+ void SetMagFilter(MagFilter filter) {
+ gl_internal::CheckThreadSafety();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, FromEnum(filter));
+ // This error check is necessary because `filter` could have been passed as
+ // an invalid GLenum.
+ gl_internal::ErrorCheck();
+ }
+
+ private:
+ int width_;
+ int height_;
+};
+
+} // namespace gl
+
+#endif // GLPLANET_SRC_GL_TEXTURE_H_