Browse code

Add implementation

Robert Cranston authored on 29/12/2021 16:30:02
Showing 1 changed files
1 1
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
+}