Browse code

Add implementation

Robert Cranston authored on 29/12/2021 16:30:02
Showing 13 changed files

... ...
@@ -8,6 +8,20 @@ A [C++11][]/[OpenGL][] [\>=2.0][] [texture][] library.
8 8
 [\>=2.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history
9 9
 [texture]: https://www.khronos.org/opengl/wiki/Texture
10 10
 
11
+## Usage
12
+
13
+### Texture units
14
+
15
+**Note** that since the allocation of texture units is handled automatically
16
+the only texture unit that is free for use by clients is `GL_TEXTURE0`.
17
+
18
+## Implementation notes
19
+
20
+The [Common mistakes][] article on the Khronos OpenGL Wiki has some good
21
+texture-related content.
22
+
23
+[Common mistakes]: https://www.khronos.org/opengl/wiki/Common_Mistakes
24
+
11 25
 ## Build system
12 26
 
13 27
 This project supports [CMake][] and uses [`cmake-common`][]. There are several
14 28
new file mode 100644
... ...
@@ -0,0 +1,193 @@
1
+#ifndef GLTEXTURE_HPP_
2
+#define GLTEXTURE_HPP_
3
+
4
+
5
+#include <cstddef>
6
+#include <string>
7
+#include <vector>
8
+
9
+#include <globject.hpp>
10
+
11
+
12
+/// Class
13
+
14
+class GLTexture : public GLObject<GL_TEXTURE, glGenTextures, glDeleteTextures>
15
+{
16
+public:
17
+
18
+    /// Special member functions
19
+
20
+    explicit GLTexture(
21
+        std::string object_label,
22
+        GLenum      target,
23
+        GLenum      binding,
24
+        GLenum      internal_format = 0,
25
+        GLenum      wrap            = 0,
26
+        GLenum      min_filter      = 0,
27
+        GLenum      mag_filter      = 0
28
+    );
29
+
30
+    /// Core
31
+
32
+    GLOBJECT_ACCESS_THREAD(GLfloat, anisotropy)
33
+
34
+    GLint unit(bool force_active = false) const;
35
+
36
+    template<typename Data = GLubyte>
37
+    std::vector<Data> data(
38
+        GLenum target    = 0,
39
+        GLenum format    = DataTraits<Data>::format,
40
+        GLint  alignment = 1
41
+    ) const;
42
+
43
+    template<typename Data = GLubyte>
44
+    GLTexture & data(
45
+        std::vector<Data> const & data,
46
+        GLenum                    target    = 0,
47
+        GLenum                    format    = DataTraits<Data>::format,
48
+        GLint                     alignment = 1
49
+    );
50
+
51
+    template<typename Data = GLubyte>
52
+    GLTexture & clear(
53
+        Data   value     = Data{},
54
+        GLenum target    = 0,
55
+        GLenum format    = DataTraits<Data>::format,
56
+        GLint  alignment = 1
57
+    );
58
+
59
+    /// Path
60
+
61
+    GLOBJECT_ACCESS_THREAD(Path, prefix)
62
+
63
+protected:
64
+
65
+    /// Core
66
+
67
+    template<typename GLTextureDerived>
68
+    GLTextureDerived static const & empty_();
69
+
70
+    bool min_filter_mipmap_() const;
71
+
72
+    std::size_t virtual data_size_() const = 0;
73
+
74
+    void virtual data_(
75
+        void const * data,
76
+        GLenum       target,
77
+        GLenum       format,
78
+        GLenum       type
79
+    ) = 0;
80
+
81
+    /// Check
82
+
83
+    void check_unit_active_() const;
84
+    void check_unit_texture_() const;
85
+    void check_data_size_(std::size_t data_size) const;
86
+
87
+    /// String
88
+
89
+    std::string static str_target_(GLenum target);
90
+
91
+protected:
92
+
93
+    GLenum const target_;
94
+
95
+private:
96
+
97
+    /// Core
98
+
99
+    GLfloat static thread_local anisotropy_;
100
+
101
+    GLenum const   binding_;
102
+    GLenum const   min_filter_;
103
+    GLuint mutable unit_;
104
+
105
+    /// Path
106
+
107
+    Path static thread_local prefix_;
108
+};
109
+
110
+
111
+/// Core
112
+
113
+template<typename Data>
114
+inline std::vector<Data> GLTexture::data(
115
+    GLenum target,
116
+    GLenum format,
117
+    GLint  alignment
118
+) const
119
+try
120
+{
121
+    if (!target)
122
+        target = target_;
123
+    auto data = std::vector<Data>(data_size_());
124
+    unit(true);
125
+    glPixelStorei(GL_PACK_ALIGNMENT, alignment);
126
+    glGetTexImage(target, 0, format, DataTraits<Data>::type, data.data());
127
+    GLOBJECT_DEBUG_IF(1)
128
+        check_error_(glGetError());
129
+    return data;
130
+}
131
+catch (...)
132
+{
133
+    fail_action_("get data of");
134
+}
135
+
136
+template<typename Data>
137
+inline GLTexture & GLTexture::data(
138
+    std::vector<Data> const & data,
139
+    GLenum                    target,
140
+    GLenum                    format,
141
+    GLint                     alignment
142
+)
143
+try
144
+{
145
+    if (!target)
146
+        target = target_;
147
+    check_data_size_(data.size());
148
+    unit(true);
149
+    glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
150
+    data_(data.data(), target, format, DataTraits<Data>::type);
151
+    GLOBJECT_DEBUG_IF(1)
152
+        check_error_(glGetError());
153
+    if (min_filter_mipmap_())
154
+        if (supported({3, 0}, "GL_ARB_framebuffer_object"))
155
+            glGenerateMipmap(target);
156
+    return *this;
157
+}
158
+catch (...)
159
+{
160
+    fail_action_("set data of");
161
+}
162
+
163
+template<typename Data>
164
+GLTexture & GLTexture::clear(
165
+    Data   value,
166
+    GLenum target,
167
+    GLenum format,
168
+    GLint  alignment
169
+)
170
+{
171
+    auto static clear = std::vector<Data>{};
172
+    clear.resize(data_size_());
173
+    std::fill(clear.begin(), clear.end(), value);
174
+    data(clear, target, format, alignment);
175
+    return *this;
176
+}
177
+
178
+template<typename GLTextureDerived>
179
+inline GLTextureDerived const & GLTexture::empty_()
180
+{
181
+    auto static const empty = []()
182
+    {
183
+        auto size = typename GLTextureDerived::Size{};
184
+        size.fill(1);
185
+        auto tmp = GLTextureDerived("empty", size);
186
+        tmp.clear();
187
+        return tmp;
188
+    }();
189
+    return empty;
190
+}
191
+
192
+
193
+#endif // GLTEXTURE_HPP_
0 194
new file mode 100644
... ...
@@ -0,0 +1,107 @@
1
+#ifndef GLTEXTURE1D_HPP_
2
+#define GLTEXTURE1D_HPP_
3
+
4
+
5
+#include <string>
6
+#include <utility>
7
+
8
+#include <gltexturend.hpp>
9
+
10
+
11
+/// Class
12
+
13
+class GLTexture1D : public GLTextureND<1>
14
+{
15
+public:
16
+
17
+    /// Special member functions
18
+
19
+    explicit GLTexture1D(
20
+        std::string object_label,
21
+        Size        size,
22
+        GLenum      internal_format = GL_RGBA8,
23
+        GLenum      wrap            = GL_CLAMP_TO_EDGE,
24
+        GLenum      min_filter      = GL_LINEAR,
25
+        GLenum      mag_filter      = GL_LINEAR
26
+    );
27
+
28
+    /// Core
29
+
30
+    GLTexture1D static const & empty();
31
+
32
+private:
33
+
34
+    /// Core
35
+
36
+    void virtual data_(
37
+        void const * data,
38
+        GLenum       target,
39
+        GLenum       format,
40
+        GLenum       type
41
+    ) override;
42
+};
43
+
44
+
45
+/// Special member functions
46
+
47
+inline GLTexture1D::GLTexture1D(
48
+    std::string object_label,
49
+    Size        size,
50
+    GLenum      internal_format,
51
+    GLenum      wrap,
52
+    GLenum      min_filter,
53
+    GLenum      mag_filter
54
+)
55
+:
56
+    GLTextureND(
57
+        std::move(object_label),
58
+        GL_TEXTURE_1D,
59
+        GL_TEXTURE_BINDING_1D,
60
+        GL_MAX_TEXTURE_SIZE,
61
+        size,
62
+        internal_format,
63
+        wrap,
64
+        min_filter,
65
+        mag_filter
66
+    )
67
+{
68
+    try
69
+    {
70
+        glTexImage1D(
71
+            target_, 0,
72
+            (GLint)internal_format,
73
+            size[0], 0,
74
+            GL_RED, GL_UNSIGNED_BYTE, nullptr
75
+        );
76
+        check_error_(glGetError());
77
+    }
78
+    catch (...)
79
+    {
80
+        fail_action_("create");
81
+    }
82
+}
83
+
84
+/// Core
85
+
86
+inline GLTexture1D const & GLTexture1D::empty()
87
+{
88
+    return empty_<GLTexture1D>();
89
+}
90
+
91
+inline void GLTexture1D::data_(
92
+    void const * data,
93
+    GLenum       target,
94
+    GLenum       format,
95
+    GLenum       type
96
+)
97
+{
98
+    glTexSubImage1D(
99
+        target, 0,
100
+        0,
101
+        size()[0],
102
+        format, type, data
103
+    );
104
+}
105
+
106
+
107
+#endif // GLTEXTURE1D_HPP_
0 108
new file mode 100644
... ...
@@ -0,0 +1,124 @@
1
+#ifndef GLTEXTURE2D_HPP_
2
+#define GLTEXTURE2D_HPP_
3
+
4
+
5
+#include <string>
6
+#include <utility>
7
+
8
+#include <globject.hpp>
9
+#include <gltexturend.hpp>
10
+
11
+
12
+/// Class
13
+
14
+class GLTexture2D : public GLTextureND<2>
15
+{
16
+public:
17
+
18
+    /// Special member functions
19
+
20
+    explicit GLTexture2D(
21
+        std::string object_label,
22
+        Size        size,
23
+        GLenum      internal_format = GL_RGBA8,
24
+        GLenum      wrap            = GL_REPEAT,
25
+        GLenum      min_filter      = GL_LINEAR_MIPMAP_LINEAR,
26
+        GLenum      mag_filter      = GL_LINEAR
27
+    );
28
+
29
+    /// Core
30
+
31
+    GLTexture2D static const & empty();
32
+
33
+    /// TGA
34
+
35
+    GLTexture2D static tga_read(
36
+        Path const & path,
37
+        GLenum       format          = GL_BGRA,
38
+        GLenum       internal_format = GL_SRGB8_ALPHA8,
39
+        GLenum       wrap            = GL_REPEAT,
40
+        GLenum       min_filter      = GL_LINEAR_MIPMAP_LINEAR,
41
+        GLenum       mag_filter      = GL_LINEAR
42
+    );
43
+
44
+    void tga_write(
45
+        Path const & path,
46
+        GLenum       format = GL_BGRA
47
+    ) const;
48
+
49
+private:
50
+
51
+    /// Core
52
+
53
+    void virtual data_(
54
+        void const * data,
55
+        GLenum       target,
56
+        GLenum       format,
57
+        GLenum       type
58
+    ) override;
59
+};
60
+
61
+
62
+/// Special member functions
63
+
64
+inline GLTexture2D::GLTexture2D(
65
+    std::string object_label,
66
+    Size        size,
67
+    GLenum      internal_format,
68
+    GLenum      wrap,
69
+    GLenum      min_filter,
70
+    GLenum      mag_filter
71
+)
72
+:
73
+    GLTextureND(
74
+        std::move(object_label),
75
+        GL_TEXTURE_2D,
76
+        GL_TEXTURE_BINDING_2D,
77
+        GL_MAX_TEXTURE_SIZE,
78
+        size,
79
+        internal_format,
80
+        wrap,
81
+        min_filter,
82
+        mag_filter
83
+    )
84
+{
85
+    try
86
+    {
87
+        glTexImage2D(
88
+            target_, 0,
89
+            (GLint)internal_format,
90
+            size[0], size[1], 0,
91
+            GL_RED, GL_UNSIGNED_BYTE, nullptr
92
+        );
93
+        check_error_(glGetError());
94
+    }
95
+    catch (...)
96
+    {
97
+        fail_action_("create");
98
+    }
99
+}
100
+
101
+/// Core
102
+
103
+inline GLTexture2D const & GLTexture2D::empty()
104
+{
105
+    return empty_<GLTexture2D>();
106
+}
107
+
108
+inline void GLTexture2D::data_(
109
+    void const * data,
110
+    GLenum       target,
111
+    GLenum       format,
112
+    GLenum       type
113
+)
114
+{
115
+    glTexSubImage2D(
116
+        target, 0,
117
+        0, 0,
118
+        size()[0], size()[1],
119
+        format, type, data
120
+    );
121
+}
122
+
123
+
124
+#endif // GLTEXTURE2D_HPP_
0 125
new file mode 100644
... ...
@@ -0,0 +1,107 @@
1
+#ifndef GLTEXTURE3D_HPP_
2
+#define GLTEXTURE3D_HPP_
3
+
4
+
5
+#include <string>
6
+#include <utility>
7
+
8
+#include <gltexturend.hpp>
9
+
10
+
11
+/// Class
12
+
13
+class GLTexture3D : public GLTextureND<3>
14
+{
15
+public:
16
+
17
+    /// Special member functions
18
+
19
+    explicit GLTexture3D(
20
+        std::string object_label,
21
+        Size        size,
22
+        GLenum      internal_format = GL_RGBA8,
23
+        GLenum      wrap            = GL_CLAMP_TO_EDGE,
24
+        GLenum      min_filter      = GL_LINEAR,
25
+        GLenum      mag_filter      = GL_LINEAR
26
+    );
27
+
28
+    /// Core
29
+
30
+    GLTexture3D static const & empty();
31
+
32
+private:
33
+
34
+    /// Core
35
+
36
+    void virtual data_(
37
+        void const * data,
38
+        GLenum       target,
39
+        GLenum       format,
40
+        GLenum       type
41
+    ) override;
42
+};
43
+
44
+
45
+/// Special member functions
46
+
47
+inline GLTexture3D::GLTexture3D(
48
+    std::string object_label,
49
+    Size        size,
50
+    GLenum      internal_format,
51
+    GLenum      wrap,
52
+    GLenum      min_filter,
53
+    GLenum      mag_filter
54
+)
55
+:
56
+    GLTextureND(
57
+        std::move(object_label),
58
+        GL_TEXTURE_3D,
59
+        GL_TEXTURE_BINDING_3D,
60
+        GL_MAX_3D_TEXTURE_SIZE,
61
+        size,
62
+        internal_format,
63
+        wrap,
64
+        min_filter,
65
+        mag_filter
66
+    )
67
+{
68
+    try
69
+    {
70
+        glTexImage3D(
71
+            target_, 0,
72
+            (GLint)internal_format,
73
+            size[0], size[1], size[2], 0,
74
+            GL_RED, GL_UNSIGNED_BYTE, nullptr
75
+        );
76
+        check_error_(glGetError());
77
+    }
78
+    catch (...)
79
+    {
80
+        fail_action_("create");
81
+    }
82
+}
83
+
84
+/// Core
85
+
86
+inline GLTexture3D const & GLTexture3D::empty()
87
+{
88
+    return empty_<GLTexture3D>();
89
+}
90
+
91
+inline void GLTexture3D::data_(
92
+    void const * data,
93
+    GLenum       target,
94
+    GLenum       format,
95
+    GLenum       type
96
+)
97
+{
98
+    glTexSubImage3D(
99
+        target, 0,
100
+        0, 0, 0,
101
+        size()[0], size()[1], size()[2],
102
+        format, type, data
103
+    );
104
+}
105
+
106
+
107
+#endif // GLTEXTURE3D_HPP_
0 108
new file mode 100644
... ...
@@ -0,0 +1,153 @@
1
+#ifndef GLTEXTUREBUFFER_HPP_
2
+#define GLTEXTUREBUFFER_HPP_
3
+
4
+
5
+#include <string>
6
+#include <utility>
7
+
8
+#include <gltexturend.hpp>
9
+
10
+
11
+/// Class
12
+
13
+template<typename Data>
14
+class GLTextureBuffer : public GLTextureND<1>
15
+{
16
+public:
17
+
18
+    /// Special member functions
19
+
20
+    explicit GLTextureBuffer(
21
+        std::string object_label,
22
+        Size        size,
23
+        GLenum      usage           = GL_STATIC_DRAW,
24
+        GLenum      internal_format = DataTraits<Data>::internal_format
25
+    );
26
+    GLTextureBuffer(GLTextureBuffer && other) noexcept;
27
+    virtual ~GLTextureBuffer();
28
+
29
+    /// Core
30
+
31
+    GLTextureBuffer static const & empty();
32
+
33
+    GLOBJECT_GET(GLuint, buffer)
34
+
35
+protected:
36
+
37
+    /// Core
38
+
39
+    void data_(
40
+        void const * data,
41
+        GLenum       target,
42
+        GLenum       format,
43
+        GLenum       type
44
+    ) override;
45
+
46
+    GLsizeiptr buffer_size_() const;
47
+
48
+private:
49
+
50
+    /// Core
51
+
52
+    GLuint buffer_;
53
+};
54
+
55
+
56
+/// Special member functions
57
+
58
+template<typename Data>
59
+inline GLTextureBuffer<Data>::GLTextureBuffer(
60
+    std::string object_label,
61
+    Size        size,
62
+    GLenum      usage,
63
+    GLenum      internal_format
64
+)
65
+:
66
+    GLTextureND(
67
+        std::move(object_label),
68
+        GL_TEXTURE_BUFFER,
69
+        GL_TEXTURE_BINDING_BUFFER,
70
+        GL_MAX_TEXTURE_BUFFER_SIZE,
71
+        size,
72
+        internal_format
73
+    ),
74
+    buffer_{0}
75
+{
76
+    try
77
+    {
78
+        check_supported_({3, 1}, "GL_ARB_texture_buffer_object");
79
+        switch (internal_format)
80
+        {
81
+            case GL_RGB32F:
82
+            case GL_RGB32I:
83
+            case GL_RGB32UI:
84
+                check_supported_({4, 0}, "GL_ARB_texture_buffer_object_rgb32");
85
+        }
86
+        glGenBuffers(1, &buffer_);
87
+        glBindBuffer(GL_TEXTURE_BUFFER, buffer_);
88
+        glBufferData(
89
+            GL_TEXTURE_BUFFER,
90
+            buffer_size_(),
91
+            nullptr,
92
+            usage
93
+        );
94
+        glTexBuffer(target_, internal_format, buffer_);
95
+        check_error_(glGetError());
96
+    }
97
+    catch (...)
98
+    {
99
+        glDeleteBuffers(1, &buffer_);
100
+        fail_action_("create");
101
+    }
102
+}
103
+
104
+template<typename Data>
105
+inline GLTextureBuffer<Data>::GLTextureBuffer(
106
+    GLTextureBuffer && other
107
+) noexcept
108
+:
109
+    buffer_{other.buffer_}
110
+{
111
+    other.buffer_ = 0;
112
+}
113
+
114
+template<typename Data>
115
+inline GLTextureBuffer<Data>::~GLTextureBuffer()
116
+{
117
+    glDeleteBuffers(1, &buffer_);
118
+}
119
+
120
+/// Core
121
+
122
+template<typename Data>
123
+inline GLTextureBuffer<Data> const & GLTextureBuffer<Data>::empty()
124
+{
125
+    return empty_<GLTextureBuffer>();
126
+}
127
+
128
+template<typename Data>
129
+inline void GLTextureBuffer<Data>::data_(
130
+    void const * data,
131
+    GLenum       target,
132
+    GLenum       format,
133
+    GLenum       type
134
+)
135
+{
136
+    check_format_(format, DataTraits<Data>::format);
137
+    check_type_  (type,   DataTraits<Data>::type);
138
+    glBufferSubData(
139
+        target,
140
+        0,
141
+        buffer_size_(),
142
+        data
143
+    );
144
+}
145
+
146
+template<typename Data>
147
+inline GLsizeiptr GLTextureBuffer<Data>::buffer_size_() const
148
+{
149
+    return (GLsizeiptr)(data_size_() * sizeof(Data));
150
+}
151
+
152
+
153
+#endif // GLTEXTUREBUFFER_HPP_
0 154
new file mode 100644
... ...
@@ -0,0 +1,141 @@
1
+#ifndef GLTEXTURECUBEMAP_HPP_
2
+#define GLTEXTURECUBEMAP_HPP_
3
+
4
+
5
+#include <string>
6
+#include <utility>
7
+
8
+#include <globject.hpp>
9
+#include <gltexturend.hpp>
10
+
11
+
12
+/// Class
13
+
14
+class GLTextureCubemap : public GLTextureND<2>
15
+{
16
+public:
17
+
18
+    /// Special member functions
19
+
20
+    explicit GLTextureCubemap(
21
+        std::string object_label,
22
+        Size        size,
23
+        GLenum      internal_format = GL_RGB8,
24
+        GLenum      wrap            = GL_CLAMP_TO_EDGE,
25
+        GLenum      min_filter      = GL_LINEAR,
26
+        GLenum      mag_filter      = GL_LINEAR
27
+    );
28
+
29
+    /// Core
30
+
31
+    GLTextureCubemap static const & empty();
32
+
33
+    /// TGA
34
+
35
+    GLTextureCubemap static tga_read(
36
+        Paths const & paths,
37
+        GLenum        format          = GL_BGRA,
38
+        GLenum        internal_format = GL_SRGB8_ALPHA8,
39
+        GLenum        wrap            = GL_CLAMP_TO_EDGE,
40
+        GLenum        min_filter      = GL_LINEAR,
41
+        GLenum        mag_filter      = GL_LINEAR
42
+    );
43
+
44
+    void tga_write(
45
+        Paths const & paths,
46
+        GLenum        format = GL_BGRA
47
+    ) const;
48
+
49
+protected:
50
+
51
+    /// Core
52
+
53
+    void virtual data_(
54
+        void const * data,
55
+        GLenum       target,
56
+        GLenum       format,
57
+        GLenum       type
58
+    ) override;
59
+
60
+    /// Check
61
+
62
+    void static check_cubemap_paths_(Paths const & paths);
63
+    void        check_cubemap_size_() const;
64
+
65
+private:
66
+
67
+    /// Core
68
+
69
+    auto static constexpr faces_ = GLuint{6};
70
+};
71
+
72
+
73
+/// Special member functions
74
+
75
+inline GLTextureCubemap::GLTextureCubemap(
76
+    std::string object_label,
77
+    Size        size,
78
+    GLenum      internal_format,
79
+    GLenum      wrap,
80
+    GLenum      min_filter,
81
+    GLenum      mag_filter
82
+)
83
+:
84
+    GLTextureND(
85
+        std::move(object_label),
86
+        GL_TEXTURE_CUBE_MAP,
87
+        GL_TEXTURE_BINDING_CUBE_MAP,
88
+        GL_MAX_CUBE_MAP_TEXTURE_SIZE,
89
+        size,
90
+        internal_format,
91
+        wrap,
92
+        min_filter,
93
+        mag_filter
94
+    )
95
+{
96
+    try
97
+    {
98
+        check_cubemap_size_();
99
+        for (auto face = GLuint{0}; face < faces_; ++face)
100
+        {
101
+            glTexImage2D(
102
+                GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0,
103
+                (GLint)internal_format,
104
+                size[0], size[1], 0,
105
+                GL_RED, GL_UNSIGNED_BYTE, nullptr
106
+            );
107
+            check_error_(glGetError());
108
+        }
109
+        if (supported({3, 2}, "GL_ARB_seamless_cube_map"))
110
+            glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
111
+    }
112
+    catch (...)
113
+    {
114
+        fail_action_("create");
115
+    }
116
+}
117
+
118
+/// Core
119
+
120
+inline GLTextureCubemap const & GLTextureCubemap::empty()
121
+{
122
+    return empty_<GLTextureCubemap>();
123
+}
124
+
125
+inline void GLTextureCubemap::data_(
126
+    void const * data,
127
+    GLenum       target,
128
+    GLenum       format,
129
+    GLenum       type
130
+)
131
+{
132
+    glTexSubImage2D(
133
+        target, 0,
134
+        0, 0,
135
+        size()[0], size()[1],
136
+        format, type, data
137
+    );
138
+}
139
+
140
+
141
+#endif // GLTEXTURECUBEMAP_HPP_
0 142
new file mode 100644
... ...
@@ -0,0 +1,69 @@
1
+#ifndef GLTEXTUREND_HPP_
2
+#define GLTEXTUREND_HPP_
3
+
4
+
5
+#include <array>
6
+#include <cstddef>
7
+#include <string>
8
+
9
+#include <globject.hpp>
10
+#include <gltexture.hpp>
11
+
12
+
13
+/// Class
14
+
15
+template<std::size_t N>
16
+class GLTextureND : public GLTexture
17
+{
18
+public:
19
+
20
+    /// Special member functions
21
+
22
+    using Size = std::array<GLsizei, N>;
23
+
24
+    explicit GLTextureND(
25
+        std::string object_label,
26
+        GLenum      target,
27
+        GLenum      binding,
28
+        GLenum      size_max_name,
29
+        Size        size,
30
+        GLenum      internal_format = 0,
31
+        GLenum      wrap            = 0,
32
+        GLenum      min_filter      = 0,
33
+        GLenum      mag_filter      = 0
34
+    );
35
+
36
+    /// Core
37
+
38
+    GLOBJECT_GET(Size, size);
39
+
40
+protected:
41
+
42
+    /// Core
43
+
44
+    std::size_t virtual data_size_() const override;
45
+
46
+    /// Check
47
+
48
+    void check_size_max_(GLenum size_max_name);
49
+
50
+    /// String
51
+
52
+    std::string static str_size_(Size size);
53
+
54
+private:
55
+
56
+    /// Core
57
+
58
+    Size const size_;
59
+};
60
+
61
+
62
+/// Explicit template instantiation
63
+
64
+extern template class GLTextureND<1>;
65
+extern template class GLTextureND<2>;
66
+extern template class GLTextureND<3>;
67
+
68
+
69
+#endif // GLTEXTUREND_HPP_
0 70
new file mode 100644
... ...
@@ -0,0 +1,196 @@
1
+#include <gltexture.hpp>
2
+
3
+#include <algorithm>
4
+#include <ostream>
5
+#include <utility>
6
+
7
+#include <globject.hpp>
8
+
9
+// NOLINTNEXTLINE
10
+#define STR_EXCEPTION GLObject<>::Exception
11
+#include <str.hpp>
12
+
13
+
14
+/// Special member functions
15
+
16
+
17
+GLTexture::GLTexture(
18
+    // NOLINTNEXTLINE
19
+    std::string object_label,
20
+    GLenum      target,
21
+    GLenum      binding,
22
+    GLenum      internal_format,
23
+    GLenum      wrap,
24
+    GLenum      min_filter,
25
+    GLenum      mag_filter
26
+)
27
+:
28
+    GLObject(STR_JOIN(" ", it, it, {
29
+        str_target_(target),
30
+        str_internal_format_(internal_format),
31
+        std::move(object_label)
32
+    })),
33
+    target_    {target},
34
+    binding_   {binding},
35
+    min_filter_{min_filter},
36
+    unit_      {0}
37
+{
38
+    // check_internal_format_(internal_format);
39
+    unit(true);
40
+    if (wrap)
41
+    {
42
+        glTexParameteri(target_, GL_TEXTURE_WRAP_S, (GLint)wrap);
43
+        glTexParameteri(target_, GL_TEXTURE_WRAP_T, (GLint)wrap);
44
+        glTexParameteri(target_, GL_TEXTURE_WRAP_R, (GLint)wrap);
45
+    }
46
+    if (min_filter)
47
+        glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, (GLint)min_filter);
48
+    if (mag_filter)
49
+        glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, (GLint)mag_filter);
50
+    if (min_filter_mipmap_())
51
+        if (!supported({3, 0}, "GL_ARB_framebuffer_object"))
52
+            glTexParameteri(target_, GL_GENERATE_MIPMAP, GL_TRUE);
53
+    if (target_ == GL_TEXTURE_2D)
54
+        // NOLINTNEXTLINE
55
+        if (supported({4, 6}, "GL_ARB_texture_filter_anisotropic"))
56
+            // TODO(rcrnstn): Remove the `_EXT` suffix when the headers are
57
+            // updated.
58
+            glTexParameterf(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy_);
59
+}
60
+
61
+
62
+/// Core
63
+
64
+
65
+GLOBJECT_THREAD(GLTexture::anisotropy_, {1.0F})
66
+
67
+
68
+GLint GLTexture::unit(bool force_active) const
69
+try
70
+{
71
+    auto static const unit_count = (GLuint)integer(
72
+        GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
73
+    );
74
+    auto static units       = std::vector<GLuint>(unit_count);
75
+    auto static textures    = std::vector<GLuint>(unit_count);
76
+    auto static targets     = std::vector<GLenum>(unit_count);
77
+    auto static unit_next   = GLuint{1};
78
+    auto static unit_active = GLuint{0};
79
+
80
+    if (!unit_ || textures[unit_] != object())
81
+    {
82
+        if (unit_next < unit_count)
83
+            units.back() = unit_ = unit_next++;
84
+        else
85
+            unit_ = units.back();
86
+        std::rotate(units.begin(), units.end() - 1, units.end());
87
+    }
88
+
89
+    if (force_active || unit_active != unit_)
90
+    {
91
+        glActiveTexture(GL_TEXTURE0 + unit_);
92
+        unit_active = unit_;
93
+    }
94
+
95
+    if (textures[unit_] != object())
96
+    {
97
+        GLOBJECT_DEBUG_IF(1)
98
+            check_unit_active_();
99
+        GLOBJECT_DEBUG_IF(1)
100
+        {
101
+            glBindTexture(targets[unit_], 0);
102
+            targets[unit_] = target_;
103
+        }
104
+        glBindTexture(target_, object());
105
+        textures[unit_] = object();
106
+    }
107
+    GLOBJECT_DEBUG_IF(1)
108
+        check_unit_texture_();
109
+
110
+    return (GLint)unit_;
111
+}
112
+catch (...)
113
+{
114
+    fail_action_("allocate texture unit for");
115
+}
116
+
117
+
118
+bool GLTexture::min_filter_mipmap_() const
119
+{
120
+    switch (min_filter_)
121
+    {
122
+        case GL_NEAREST_MIPMAP_NEAREST:
123
+        case GL_NEAREST_MIPMAP_LINEAR:
124
+        case GL_LINEAR_MIPMAP_NEAREST:
125
+        case GL_LINEAR_MIPMAP_LINEAR:
126
+            return true;
127
+        default:
128
+            return false;
129
+    }
130
+}
131
+
132
+
133
+/// Path
134
+
135
+
136
+GLOBJECT_THREAD(GLTexture::prefix_, {"assets/textures"})
137
+
138
+
139
+/// Check
140
+
141
+
142
+void GLTexture::check_unit_active_() const
143
+{
144
+    auto unit_active = (GLuint)integer(GL_ACTIVE_TEXTURE) - GL_TEXTURE0;
145
+    if (unit_active != unit_)
146
+        STR_THROW(
147
+            "Expected active unit " << unit_        << ", " <<
148
+            "got "                  << unit_active  << "."
149
+        );
150
+}
151
+
152
+
153
+void GLTexture::check_unit_texture_() const
154
+{
155
+    auto unit_texture = (GLuint)integer(binding_);
156
+    if (unit_texture != object())
157
+        STR_THROW(
158
+            "Expected unit "  << unit_        << " "   <<
159
+            "to be bound to " << debug_name() << ", "  <<
160
+            "got "            << unit_texture << "."
161
+        );
162
+}
163
+
164
+
165
+void GLTexture::check_data_size_(std::size_t data_size) const
166
+{
167
+    if (data_size != data_size_())
168
+        STR_THROW(
169
+            "Expected data size " << data_size_() << ", " <<
170
+            "got "                << data_size    << "."
171
+        );
172
+}
173
+
174
+
175
+/// String
176
+
177
+
178
+std::string GLTexture::str_target_(GLenum target)
179
+{
180
+    switch (target)
181
+    {
182
+        STR_CASE(GL_TEXTURE_1D)
183
+        STR_CASE(GL_TEXTURE_2D)
184
+        STR_CASE(GL_TEXTURE_3D)
185
+        STR_CASE(GL_TEXTURE_1D_ARRAY)
186
+        STR_CASE(GL_TEXTURE_2D_ARRAY)
187
+        STR_CASE(GL_TEXTURE_RECTANGLE)
188
+        STR_CASE(GL_TEXTURE_CUBE_MAP)
189
+        STR_CASE(GL_TEXTURE_CUBE_MAP_ARRAY)
190
+        STR_CASE(GL_TEXTURE_BUFFER)
191
+        STR_CASE(GL_TEXTURE_2D_MULTISAMPLE)
192
+        STR_CASE(GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
193
+        default:
194
+            return str_enum_(target);
195
+    }
196
+}
0 197
new file mode 100644
... ...
@@ -0,0 +1,62 @@
1
+#include <gltexture2d.hpp>
2
+
3
+#include <ostream>
4
+
5
+#include <globject.hpp>
6
+
7
+// NOLINTNEXTLINE
8
+#define STR_EXCEPTION GLObject<>::Exception
9
+#include <str.hpp>
10
+
11
+
12
+/// TGA
13
+
14
+
15
+GLTexture2D GLTexture2D::tga_read(
16
+    Path const & path,
17
+    GLenum       format,
18
+    GLenum       internal_format,
19
+    GLenum       wrap,
20
+    GLenum       min_filter,
21
+    GLenum       mag_filter
22
+)
23
+try
24
+{
25
+    auto texture = GLTexture2D(
26
+        str_path_(path),
27
+        TGA::read(path).size(),
28
+        internal_format,
29
+        wrap,
30
+        min_filter,
31
+        mag_filter
32
+    );
33
+    texture.data(
34
+        TGA::read(path_prefix_(path, prefix())).data(),
35
+        GL_TEXTURE_2D,
36
+        format
37
+    );
38
+    return texture;
39
+}
40
+catch (...)
41
+{
42
+    STR_THROW_NESTED(
43
+        "Failed to read GLTexture2D TGA " << str_path_(path) << ":"
44
+    );
45
+}
46
+
47
+
48
+void GLTexture2D::tga_write(
49
+    Path const & path,
50
+    GLenum       format
51
+) const
52
+try
53
+{
54
+    TGA(size(), data(GL_TEXTURE_2D, format))
55
+        .write(path_prefix_(path, prefix()));
56
+}
57
+catch (...)
58
+{
59
+    STR_THROW_NESTED(
60
+        "Failed to write GLTexture2D TGA " << str_path_(path) << ":"
61
+    );
62
+}
0 63
new file mode 100644
... ...
@@ -0,0 +1,90 @@
1
+#include <gltexturecubemap.hpp>
2
+
3
+#include <ostream>
4
+
5
+#include <globject.hpp>
6
+#include <gltexturend.hpp>
7
+
8
+// NOLINTNEXTLINE
9
+#define STR_EXCEPTION GLObject<>::Exception
10
+#include <str.hpp>
11
+
12
+
13
+/// TGA
14
+
15
+
16
+GLTextureCubemap GLTextureCubemap::tga_read(
17
+    Paths const & paths,
18
+    GLenum        format,
19
+    GLenum        internal_format,
20
+    GLenum        wrap,
21
+    GLenum        min_filter,
22
+    GLenum        mag_filter
23
+)
24
+try
25
+{
26
+    check_cubemap_paths_(paths);
27
+    auto texture = GLTextureCubemap(
28
+        str_paths_(paths),
29
+        TGA::read(paths[0]).size(),
30
+        internal_format,
31
+        wrap,
32
+        min_filter,
33
+        mag_filter
34
+    );
35
+    for (auto face = GLuint{0}; face < faces_; ++face)
36
+        texture.data(
37
+            TGA::read(path_prefix_(paths[face], prefix())).data(),
38
+            GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
39
+            format
40
+        );
41
+    return texture;
42
+}
43
+catch (...)
44
+{
45
+    STR_THROW_NESTED(
46
+        "Failed to read GLTextureCubemap TGA " << str_paths_(paths) << ":"
47
+    );
48
+}
49
+
50
+
51
+void GLTextureCubemap::tga_write(
52
+    Paths const & paths,
53
+    GLenum        format
54
+) const
55
+try
56
+{
57
+    check_cubemap_paths_(paths);
58
+    for (auto face = GLuint{0}; face < faces_; ++face)
59
+        TGA(size(), data(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, format))
60
+            .write(path_prefix_(paths[face], prefix()));
61
+}
62
+catch (...)
63
+{
64
+    STR_THROW_NESTED(
65
+        "Failed to write GLTextureCubemap TGA " << str_paths_(paths) << ":"
66
+    );
67
+}
68
+
69
+
70
+/// Check
71
+
72
+
73
+void GLTextureCubemap::check_cubemap_paths_(Paths const & paths)
74
+{
75
+    if (paths.size() != faces_)
76
+        STR_THROW(
77
+            "Expected number of paths " << GLuint{faces_} << ", " <<
78
+            "got "                      << paths.size()   << "."
79
+        );
80
+}
81
+
82
+
83
+void GLTextureCubemap::check_cubemap_size_() const
84
+{
85
+    if (size()[0] != size()[1])
86
+        STR_THROW(
87
+            "Expected size " << "to be square"    << ", " <<
88
+            "got "           << str_size_(size()) << "."
89
+        );
90
+}
0 91
new file mode 100644
... ...
@@ -0,0 +1,96 @@
1
+#include <gltexturend.hpp>
2
+
3
+#include <functional>
4
+#include <numeric>
5
+#include <utility>
6
+
7
+#include <globject.hpp>
8
+#include <gltexture.hpp>
9
+
10
+// NOLINTNEXTLINE
11
+#define STR_EXCEPTION GLObject<>::Exception
12
+#include <str.hpp>
13
+
14
+
15
+/// Special member functions
16
+
17
+
18
+template<std::size_t N>
19
+inline GLTextureND<N>::GLTextureND(
20
+    // NOLINTNEXTLINE
21
+    std::string object_label,
22
+    GLenum      target,
23
+    GLenum      binding,
24
+    GLenum      size_max_name,
25
+    Size        size,
26
+    GLenum      internal_format,
27
+    GLenum      wrap,
28
+    GLenum      min_filter,
29
+    GLenum      mag_filter
30
+)
31
+:
32
+    GLTexture(
33
+        STR_JOIN(" ", it, it, {
34
+            str_size_(size),
35
+            std::move(object_label)
36
+        }),
37
+        target,
38
+        binding,
39
+        internal_format,
40
+        wrap,
41
+        min_filter,
42
+        mag_filter
43
+    ),
44
+    size_{size}
45
+{
46
+    check_size_max_(size_max_name);
47
+}
48
+
49
+
50
+/// Core
51
+
52
+
53
+template<std::size_t N>
54
+std::size_t GLTextureND<N>::data_size_() const
55
+{
56
+    return std::accumulate(
57
+        size_.begin(),
58
+        size_.end(),
59
+        std::size_t{1},
60
+        std::multiplies<std::size_t>{}
61
+    );
62
+}
63
+
64
+
65
+/// Check
66
+
67
+
68
+template<std::size_t N>
69
+void GLTextureND<N>::check_size_max_(GLenum size_max_name)
70
+{
71
+    auto static const size_max = integer(size_max_name);
72
+    for (auto size : size_)
73
+        if (size > size_max)
74
+            STR_THROW(
75
+                "Expected max size " << size_max         << ", " <<
76
+                "got "               << str_size_(size_) << "."
77
+            );
78
+}
79
+
80
+
81
+/// String
82
+
83
+
84
+template<std::size_t N>
85
+std::string GLTextureND<N>::str_size_(Size size)
86
+{
87
+    return STR("{" << STR_JOIN(", ", it, it, size) << "}");
88
+}
89
+
90
+
91
+/// Explicit template instantiation
92
+
93
+
94
+template class GLTextureND<1>;
95
+template class GLTextureND<2>;
96
+template class GLTextureND<3>;
0 97
new file mode 100644
... ...
@@ -0,0 +1,39 @@
1
+#include <string>
2
+
3
+#include <gltexture.hpp>
4
+#include <gltexture1d.hpp>
5
+#include <gltexture2d.hpp>
6
+#include <gltexture3d.hpp>
7
+#include <gltexturebuffer.hpp>
8
+#include <gltexturecubemap.hpp>
9
+
10
+
11
+constexpr auto size = 128;
12
+
13
+
14
+template<typename Data>
15
+void texture(GLuint program, GLTexture * texture0)
16
+{
17
+    // NOLINTNEXTLINE
18
+    GLTexture::anisotropy(4.0F);
19
+
20
+    glUniform1i(
21
+        glGetUniformLocation(program, "texture0"),
22
+        texture0->unit()
23
+    );
24
+
25
+    auto const data = texture0->data<Data>();
26
+    (void)data;
27
+    texture0->data({1, 2, 3, 4});
28
+    texture0->clear();
29
+}
30
+
31
+
32
+int main()
33
+{
34
+    GLTexture1D              texture1d     ("", {size});
35
+    GLTexture2D              texture2d     ("", {size, size});
36
+    GLTexture3D              texture3d     ("", {size, size, size});
37
+    GLTextureBuffer<GLfloat> texturebuffer ("", {size});
38
+    GLTextureCubemap         texturecubemap("", {size, size});
39
+}