Browse code

Add Texture

Robert Cranston authored on 28/02/2023 02:21:38
Showing 4 changed files

... ...
@@ -29,6 +29,21 @@ These constants are provided in `GLTraits::Value<glm::uvec3>`. Of course, this
29 29
 becomes even more valuable when `glm::uvec3` is replaced by some unknown
30 30
 template parameter.
31 31
 
32
+The function call seen in the video
33
+
34
+```cpp
35
+glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32UI, WindowWidth, WindowHeight, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, NULL);
36
+```
37
+
38
+can be replaced with
39
+
40
+```cpp
41
+GLTraits::Texture<2>::tex_image<glm::uvec3>(GL_TEXTURE_2D, {WindowWidth, WindowHeight});
42
+```
43
+
44
+It is recommended to use a library based on `gltraits` that abstracts this
45
+further.
46
+
32 47
 [`gltraits`]: https://git.rcrnstn.net/rcrnstn/gltraits
33 48
 [C++11]: https://en.wikipedia.org/wiki/C++11
34 49
 [OpenGL]: https://en.wikipedia.org/wiki/OpenGL
... ...
@@ -204,6 +219,170 @@ For `object_types` equal to  `GL_SHADER`, `GL_PROGRAM`, and
204 219
 specializations of `GLTraits::Object`. Consult the source for the definitions
205 220
 and usage examples.
206 221
 
222
+### Texture
223
+
224
+The [empty][] `struct GLTraits::Texture<std::size_t N>` is template specialized
225
+on the following values.
226
+
227
+-   `1`. 1D textures.
228
+-   `2`. 2D textures.
229
+-   `3`. 3D textures.
230
+
231
+`GLTraits::Texture` contains the following type definitions.
232
+
233
+-   `Size`. An alias for `std::array<GLsizei, N>`.
234
+-   `Offset`. An alias for `std::array<GLsizei, N>`.
235
+-   `CopySize`. An alias for `std::array<GLsizei, min(N, 2)>`.
236
+-   `CopyOffset`. An alias for `std::array<GLsizei, 2>`.
237
+
238
+`GLTraits::Texture` contains the following `static constexpr` member variables.
239
+
240
+-   `default_target`. This is the default target, but many other targets can be
241
+    used with the member functions described below. E.g. for `N = 2`
242
+    `default_target` is `GL_TEXTURE_2D`, but valid `target` function arguments
243
+    are `GL_{,PROXY}_TEXTURE_{2D,RECTANGLE,1D_ARRAY}`,
244
+    `GL_TEXTURE_CUBE_MAP_{POSITIVE,NEGATIVE}_{X,Y,Z}`, and
245
+    `GL_PROXY_TEXTURE_CUBE_MAP`.
246
+-   `default_binding`. Likewise, this is the default binding.
247
+
248
+`GLTraits::Texture` contains the following `static` member functions.
249
+
250
+-   ```cpp
251
+    template<typename Value = GLubyte>
252
+    void tex_image(
253
+        GLenum        target,
254
+        Size          size,
255
+        GLenum        internal_format = 0,
256
+        Value const * data            = nullptr,
257
+        GLenum        format          = 0,
258
+        GLenum        type            = 0,
259
+        GLint         level           = 0,
260
+        GLint         border          = 0
261
+    )
262
+    ```
263
+
264
+    Generalization of `glTexImage{1,2,3}D`.
265
+
266
+    OpenGL requires that `format` matches the kind of [image format][]
267
+    specified by `internal_format` (even if `data` is `nullptr`!). Moreover, if
268
+    `internal_format` specifies an unsized image format, `type` may be used by
269
+    the implementation when choosing a size (perhaps even if that size is
270
+    slow!). Therefore, if `format` and/or `type` is `0` (the default) sensible
271
+    values will be chosen based on the given (or automatically chosen, see
272
+    below) `internal_format` (note that there is no requirement that the number
273
+    of color components of `internal_format` and `format` match):
274
+
275
+    -   [Color formats][]: `GLTraits::Value<Value>` member variables.
276
+    -   [Depth/stencil formats][]: `GL_DEPTH_STENCIL`, `GL_UNSIGNED_INT_24_8`.
277
+    -   [Depth formats][]: `GL_DEPTH_COMPONENT`, `GL_UNSIGNED_INT`.
278
+    -   [Stencil formats][]: `GL_STENCIL_INDEX`, `GL_UNSIGNED_BYTE`.
279
+
280
+-   ```cpp
281
+    template<typename Value = GLubyte>
282
+    void {tex,texture}_storage(
283
+        {GLenum,GLuint} {target,texture},
284
+        Size            size,
285
+        GLenum          internal_format = 0,
286
+        GLsizei         levels          = 1
287
+    )
288
+    ```
289
+
290
+    Generalizations of `gl{Tex,Texture}Storage{1,2,3}D`, which both use
291
+    [immutable storage][], where the latter uses [Direct State Access][].
292
+
293
+-   ```cpp
294
+    template<typename Value = GLubyte>
295
+    void {tex,texture}_sub_image(
296
+        {GLenum,GLuint} {target,texture},
297
+        Size            size,
298
+        Value const *   data,
299
+        GLenum          format = 0,
300
+        GLenum          type   = 0,
301
+        Offset          offset = {},
302
+        GLint           level  = 0
303
+    )
304
+    ```
305
+
306
+    Generalizations of `gl{Tex,Texture}SubImage{1,2,3}D`, where the latter uses
307
+    [Direct State Access][].
308
+
309
+-   ```cpp
310
+    void copy_{tex,texture}_sub_image(
311
+        {GLenum,GLuint} {target,texture},
312
+        CopySize        copy_size,
313
+        CopyOffset      copy_offset = {},
314
+        Offset          offset      = {},
315
+        GLint           level       = 0
316
+    )
317
+    ```
318
+
319
+    Generalizations of `glCopy{Tex,Texture}SubImage{1,2,3}D`, where the latter
320
+    uses [Direct State Access][].
321
+
322
+-   ```cpp
323
+    void compressed_tex_image(
324
+        GLenum       target,
325
+        Size         size,
326
+        GLenum       internal_format,
327
+        GLsizei      data_size = 0,
328
+        void const * data      = nullptr,
329
+        GLint        level     = 0,
330
+        GLint        border    = 0
331
+    )
332
+    ```
333
+
334
+    Generalization of `glCompressedTexImage{1,2,3}D`.
335
+
336
+-   ```cpp
337
+    void compressed_{tex,texture}_sub_image(
338
+        {GLenum,GLuint} {target,texture},
339
+        Size            size,
340
+        GLsizei         data_size,
341
+        void const *    data,
342
+        GLenum          internal_format,
343
+        Offset          offset = {},
344
+        GLint           level  = 0
345
+    )
346
+    ```
347
+
348
+    Generalizations of `glCompressed{Tex,Texture}SubImage{1,2,3}D`, where the
349
+    latter uses [Direct State Access][].
350
+
351
+For the member functions that are template parameterized on `Value`, when
352
+`internal_format`, `format` and/or `type` is `0` (the default), the value used
353
+will be taken from the corresponding `GLTraits::Value<Value>` member variable.
354
+
355
+Note that when the `Value` template type parameter is deduced from `data` the
356
+automatically chosen `format` may not be correct. E.g. it is reasonable for
357
+`data` to be a `GLubyte` pointer to RGBA values in which case `format` must be
358
+manually specified as `GL_RGBA` since the automatically chosen `format` would
359
+be `GL_RED`.
360
+
361
+Note that the [pixel transfer parameters][] are not modified, this must be
362
+handled manually if required.
363
+
364
+(There is no `copy_tex_image(...)` because OpenGL does not provide
365
+`glCopyTexImage3D`, only `glCopyTexImage{1,2}D`.)
366
+
367
+(There is no `{tex_image,tex_storage,texture_storage}_multisample(...)` because
368
+OpenGL does not provide `gl{TexImage,TexStorage,TextureStorage}1DMultisample`,
369
+only `gl{TexImage,TexStorage,TextureStorage}{2,3}DMultisample`.)
370
+
371
+(There is no `compressed_texture_image(...)` because OpenGL does not provide
372
+`glCompressedTextureImage{1,2,3}D`, only the `Sub` variants.)
373
+
374
+(There is no `framebuffer_texture(...)` because OpenGL provides incompatible
375
+signatures for `glFramebufferTexture1D` and `glFramebufferTexture{2,3}D`.)
376
+
377
+[image format]: https://www.khronos.org/opengl/wiki/Image_Format
378
+[color formats]: https://www.khronos.org/opengl/wiki/Image_Format#Color_formats
379
+[depth/stencil formats]: https://www.khronos.org/opengl/wiki/Image_Format#Depth_stencil_formats
380
+[depth formats]: https://www.khronos.org/opengl/wiki/Image_Format#Depth_formats
381
+[stencil formats]: https://www.khronos.org/opengl/wiki/Image_Format#Stencil_only
382
+[Direct State Access]: https://www.khronos.org/opengl/wiki/Direct_State_Access
383
+[immutable storage]: https://www.khronos.org/opengl/wiki/Texture_Storage#Immutable_storage
384
+[pixel transfer parameters]: https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_transfer_parameters
385
+
207 386
 ## Building
208 387
 
209 388
 See [`BUILDING.md`][].
... ...
@@ -7,6 +7,33 @@ class GLTraits
7 7
     template <GLenum id> struct ValueID;
8 8
 
9 9
     template <GLenum object_type> struct Object;
10
+
11
+    template <std::size_t N> struct Texture;
12
+
13
+  private:
14
+    template <std::size_t... Is> struct Indices
15
+    {
16
+    };
17
+
18
+    template <std::size_t N, std::size_t... Is>
19
+    struct MakeIndices_ : MakeIndices_<N - 1, N - 1, Is...>
20
+    {
21
+    };
22
+
23
+    template <std::size_t... Is> struct MakeIndices_<0, Is...>
24
+    {
25
+        using Indices_ = Indices<Is...>;
26
+    };
27
+
28
+    template <std::size_t N>
29
+    using MakeIndices = typename MakeIndices_<N>::Indices_;
30
+
31
+    template <
32
+        std::size_t N,
33
+        typename Indices,
34
+        typename CopySizeIndices,
35
+        typename CopyOffsetIndices>
36
+    struct Texture_;
10 37
 };
11 38
 
12 39
 template <> struct GLTraits::Value<GLfloat>
... ...
@@ -2633,3 +2660,734 @@ template <> struct GLTraits::Object<GL_PROGRAM_PIPELINE>
2633 2660
     }
2634 2661
 };
2635 2662
 
2663
+
2664
+template <> struct GLTraits::Texture<0>
2665
+{
2666
+  protected:
2667
+    void static defaults_(
2668
+        GLenum & internal_format,
2669
+        GLenum & format,
2670
+        GLenum & type,
2671
+        GLenum   default_internal_format,
2672
+        GLenum   default_format,
2673
+        GLenum   default_type)
2674
+    {
2675
+        if (!internal_format)
2676
+            internal_format = default_internal_format;
2677
+        switch (internal_format)
2678
+        {
2679
+        case GL_DEPTH_STENCIL:
2680
+        case GL_DEPTH24_STENCIL8:
2681
+        case GL_DEPTH32F_STENCIL8:
2682
+            if (!format)
2683
+                format = GL_DEPTH_STENCIL;
2684
+            if (!type)
2685
+                type = GL_UNSIGNED_INT_24_8;
2686
+            break;
2687
+        case GL_DEPTH_COMPONENT:
2688
+        case GL_DEPTH_COMPONENT16:
2689
+        case GL_DEPTH_COMPONENT24:
2690
+        case GL_DEPTH_COMPONENT32:
2691
+        case GL_DEPTH_COMPONENT32F:
2692
+            if (!format)
2693
+                format = GL_DEPTH_COMPONENT;
2694
+            if (!type)
2695
+                type = GL_UNSIGNED_INT;
2696
+            break;
2697
+        case GL_STENCIL_INDEX:
2698
+        case GL_STENCIL_INDEX1:
2699
+        case GL_STENCIL_INDEX4:
2700
+        case GL_STENCIL_INDEX8:
2701
+        case GL_STENCIL_INDEX16:
2702
+            if (!format)
2703
+                format = GL_STENCIL_INDEX;
2704
+            if (!type)
2705
+                type = GL_UNSIGNED_BYTE;
2706
+            break;
2707
+        default:
2708
+            if (!format)
2709
+                format = default_format;
2710
+            if (!type)
2711
+                type = default_type;
2712
+        }
2713
+    }
2714
+};
2715
+
2716
+template <
2717
+    std::size_t... Is,
2718
+    std::size_t... CopySizeIs,
2719
+    std::size_t... CopyOffsetIs>
2720
+struct GLTraits::Texture_<
2721
+    1,
2722
+    GLTraits::Indices<Is...>,
2723
+    GLTraits::Indices<CopySizeIs...>,
2724
+    GLTraits::Indices<CopyOffsetIs...>> : GLTraits::Texture<0>
2725
+{
2726
+    using Size       = std::array<GLsizei, sizeof...(Is)>;
2727
+    using Offset     = std::array<GLsizei, sizeof...(Is)>;
2728
+    using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>;
2729
+    using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>;
2730
+    auto static constexpr default_target  = GL_TEXTURE_1D;
2731
+    auto static constexpr default_binding = GL_TEXTURE_BINDING_1D;
2732
+    template <typename Value = GLubyte>
2733
+    void static tex_image(
2734
+        GLenum        target,
2735
+        Size          size,
2736
+        GLenum        internal_format = 0,
2737
+        Value const * data            = nullptr,
2738
+        GLenum        format          = 0,
2739
+        GLenum        type            = 0,
2740
+        GLint         level           = 0,
2741
+        GLint         border          = 0)
2742
+    {
2743
+        if (GLBase::debug() >= 1)
2744
+            GLBase::check_supported({1, 0}, {});
2745
+        defaults_(
2746
+            internal_format,
2747
+            format,
2748
+            type,
2749
+            GLTraits::Value<Value>::internal_format,
2750
+            GLTraits::Value<Value>::format,
2751
+            GLTraits::Value<Value>::type);
2752
+        glTexImage1D(
2753
+            target,
2754
+            level,
2755
+            (GLint)internal_format,
2756
+            std::get<Is>(size)...,
2757
+            border,
2758
+            format,
2759
+            type,
2760
+            data);
2761
+    }
2762
+    template <typename Value = GLubyte>
2763
+    void static tex_sub_image(
2764
+        GLenum        target,
2765
+        Size          size,
2766
+        Value const * data,
2767
+        GLenum        format = 0,
2768
+        GLenum        type   = 0,
2769
+        Offset        offset = {},
2770
+        GLint         level  = 0)
2771
+    {
2772
+        if (GLBase::debug() >= 1)
2773
+            GLBase::check_supported({1, 1}, {});
2774
+        if (!format)
2775
+            format = GLTraits::Value<Value>::format;
2776
+        if (!type)
2777
+            type = GLTraits::Value<Value>::type;
2778
+        glTexSubImage1D(
2779
+            target,
2780
+            level,
2781
+            std::get<Is>(offset)...,
2782
+            std::get<Is>(size)...,
2783
+            format,
2784
+            type,
2785
+            data);
2786
+    }
2787
+    void static copy_tex_sub_image(
2788
+        GLenum     target,
2789
+        CopySize   copy_size,
2790
+        CopyOffset copy_offset = {},
2791
+        Offset     offset      = {},
2792
+        GLint      level       = 0)
2793
+    {
2794
+        if (GLBase::debug() >= 1)
2795
+            GLBase::check_supported({1, 1}, {});
2796
+        glCopyTexSubImage1D(
2797
+            target,
2798
+            level,
2799
+            std::get<Is>(offset)...,
2800
+            std::get<CopyOffsetIs>(copy_offset)...,
2801
+            std::get<CopySizeIs>(copy_size)...);
2802
+    }
2803
+    void static compressed_tex_image(
2804
+        GLenum       target,
2805
+        Size         size,
2806
+        GLenum       internal_format,
2807
+        GLsizei      data_size = 0,
2808
+        void const * data      = nullptr,
2809
+        GLint        level     = 0,
2810
+        GLint        border    = 0)
2811
+    {
2812
+        if (GLBase::debug() >= 1)
2813
+            GLBase::check_supported({1, 3}, {});
2814
+        glCompressedTexImage1D(
2815
+            target,
2816
+            level,
2817
+            internal_format,
2818
+            std::get<Is>(size)...,
2819
+            border,
2820
+            data_size,
2821
+            data);
2822
+    }
2823
+    void static compressed_tex_sub_image(
2824
+        GLenum       target,
2825
+        Size         size,
2826
+        GLsizei      data_size,
2827
+        void const * data,
2828
+        GLenum       internal_format,
2829
+        Offset       offset = {},
2830
+        GLint        level  = 0)
2831
+    {
2832
+        if (GLBase::debug() >= 1)
2833
+            GLBase::check_supported({1, 3}, {});
2834
+        glCompressedTexSubImage1D(
2835
+            target,
2836
+            level,
2837
+            std::get<Is>(offset)...,
2838
+            std::get<Is>(size)...,
2839
+            internal_format,
2840
+            data_size,
2841
+            data);
2842
+    }
2843
+    template <typename Value = GLubyte>
2844
+    void static tex_storage(
2845
+        GLenum  target,
2846
+        Size    size,
2847
+        GLenum  internal_format = 0,
2848
+        GLsizei levels          = 1)
2849
+    {
2850
+        if (GLBase::debug() >= 1)
2851
+            GLBase::check_supported({4, 2}, "GL_ARB_texture_storage");
2852
+        if (!internal_format)
2853
+            internal_format = GLTraits::Value<Value>::internal_format;
2854
+        glTexStorage1D(target, levels, internal_format, std::get<Is>(size)...);
2855
+    }
2856
+    template <typename Value = GLubyte>
2857
+    void static texture_storage(
2858
+        GLuint  texture,
2859
+        Size    size,
2860
+        GLenum  internal_format = 0,
2861
+        GLsizei levels          = 1)
2862
+    {
2863
+        if (GLBase::debug() >= 1)
2864
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
2865
+        if (!internal_format)
2866
+            internal_format = GLTraits::Value<Value>::internal_format;
2867
+        glTextureStorage1D(
2868
+            texture,
2869
+            levels,
2870
+            internal_format,
2871
+            std::get<Is>(size)...);
2872
+    }
2873
+    template <typename Value = GLubyte>
2874
+    void static texture_sub_image(
2875
+        GLuint        texture,
2876
+        Size          size,
2877
+        Value const * data,
2878
+        GLenum        format = 0,
2879
+        GLenum        type   = 0,
2880
+        Offset        offset = {},
2881
+        GLint         level  = 0)
2882
+    {
2883
+        if (GLBase::debug() >= 1)
2884
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
2885
+        if (!format)
2886
+            format = GLTraits::Value<Value>::format;
2887
+        if (!type)
2888
+            type = GLTraits::Value<Value>::type;
2889
+        glTextureSubImage1D(
2890
+            texture,
2891
+            level,
2892
+            std::get<Is>(offset)...,
2893
+            std::get<Is>(size)...,
2894
+            format,
2895
+            type,
2896
+            data);
2897
+    }
2898
+    void static copy_texture_sub_image(
2899
+        GLuint     texture,
2900
+        CopySize   copy_size,
2901
+        CopyOffset copy_offset = {},
2902
+        Offset     offset      = {},
2903
+        GLint      level       = 0)
2904
+    {
2905
+        if (GLBase::debug() >= 1)
2906
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
2907
+        glCopyTextureSubImage1D(
2908
+            texture,
2909
+            level,
2910
+            std::get<Is>(offset)...,
2911
+            std::get<CopyOffsetIs>(copy_offset)...,
2912
+            std::get<CopySizeIs>(copy_size)...);
2913
+    }
2914
+    void static compressed_texture_sub_image(
2915
+        GLuint       texture,
2916
+        Size         size,
2917
+        GLsizei      data_size,
2918
+        void const * data,
2919
+        GLenum       internal_format,
2920
+        Offset       offset = {},
2921
+        GLint        level  = 0)
2922
+    {
2923
+        if (GLBase::debug() >= 1)
2924
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
2925
+        glCompressedTextureSubImage1D(
2926
+            texture,
2927
+            level,
2928
+            std::get<Is>(offset)...,
2929
+            std::get<Is>(size)...,
2930
+            internal_format,
2931
+            data_size,
2932
+            data);
2933
+    }
2934
+};
2935
+
2936
+template <>
2937
+struct GLTraits::Texture<1>
2938
+    : Texture_<1, MakeIndices<1>, MakeIndices<1 < 2 ? 1 : 2>, MakeIndices<2>>
2939
+{
2940
+};
2941
+
2942
+template <
2943
+    std::size_t... Is,
2944
+    std::size_t... CopySizeIs,
2945
+    std::size_t... CopyOffsetIs>
2946
+struct GLTraits::Texture_<
2947
+    2,
2948
+    GLTraits::Indices<Is...>,
2949
+    GLTraits::Indices<CopySizeIs...>,
2950
+    GLTraits::Indices<CopyOffsetIs...>> : GLTraits::Texture<0>
2951
+{
2952
+    using Size       = std::array<GLsizei, sizeof...(Is)>;
2953
+    using Offset     = std::array<GLsizei, sizeof...(Is)>;
2954
+    using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>;
2955
+    using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>;
2956
+    auto static constexpr default_target  = GL_TEXTURE_2D;
2957
+    auto static constexpr default_binding = GL_TEXTURE_BINDING_2D;
2958
+    template <typename Value = GLubyte>
2959
+    void static tex_image(
2960
+        GLenum        target,
2961
+        Size          size,
2962
+        GLenum        internal_format = 0,
2963
+        Value const * data            = nullptr,
2964
+        GLenum        format          = 0,
2965
+        GLenum        type            = 0,
2966
+        GLint         level           = 0,
2967
+        GLint         border          = 0)
2968
+    {
2969
+        if (GLBase::debug() >= 1)
2970
+            GLBase::check_supported({1, 0}, {});
2971
+        defaults_(
2972
+            internal_format,
2973
+            format,
2974
+            type,
2975
+            GLTraits::Value<Value>::internal_format,
2976
+            GLTraits::Value<Value>::format,
2977
+            GLTraits::Value<Value>::type);
2978
+        glTexImage2D(
2979
+            target,
2980
+            level,
2981
+            (GLint)internal_format,
2982
+            std::get<Is>(size)...,
2983
+            border,
2984
+            format,
2985
+            type,
2986
+            data);
2987
+    }
2988
+    template <typename Value = GLubyte>
2989
+    void static tex_sub_image(
2990
+        GLenum        target,
2991
+        Size          size,
2992
+        Value const * data,
2993
+        GLenum        format = 0,
2994
+        GLenum        type   = 0,
2995
+        Offset        offset = {},
2996
+        GLint         level  = 0)
2997
+    {
2998
+        if (GLBase::debug() >= 1)
2999
+            GLBase::check_supported({1, 1}, {});
3000
+        if (!format)
3001
+            format = GLTraits::Value<Value>::format;
3002
+        if (!type)
3003
+            type = GLTraits::Value<Value>::type;
3004
+        glTexSubImage2D(
3005
+            target,
3006
+            level,
3007
+            std::get<Is>(offset)...,
3008
+            std::get<Is>(size)...,
3009
+            format,
3010
+            type,
3011
+            data);
3012
+    }
3013
+    void static copy_tex_sub_image(
3014
+        GLenum     target,
3015
+        CopySize   copy_size,
3016
+        CopyOffset copy_offset = {},
3017
+        Offset     offset      = {},
3018
+        GLint      level       = 0)
3019
+    {
3020
+        if (GLBase::debug() >= 1)
3021
+            GLBase::check_supported({1, 1}, {});
3022
+        glCopyTexSubImage2D(
3023
+            target,
3024
+            level,
3025
+            std::get<Is>(offset)...,
3026
+            std::get<CopyOffsetIs>(copy_offset)...,
3027
+            std::get<CopySizeIs>(copy_size)...);
3028
+    }
3029
+    void static compressed_tex_image(
3030
+        GLenum       target,
3031
+        Size         size,
3032
+        GLenum       internal_format,
3033
+        GLsizei      data_size = 0,
3034
+        void const * data      = nullptr,
3035
+        GLint        level     = 0,
3036
+        GLint        border    = 0)
3037
+    {
3038
+        if (GLBase::debug() >= 1)
3039
+            GLBase::check_supported({1, 3}, {});
3040
+        glCompressedTexImage2D(
3041
+            target,
3042
+            level,
3043
+            internal_format,
3044
+            std::get<Is>(size)...,
3045
+            border,
3046
+            data_size,
3047
+            data);
3048
+    }
3049
+    void static compressed_tex_sub_image(
3050
+        GLenum       target,
3051
+        Size         size,
3052
+        GLsizei      data_size,
3053
+        void const * data,
3054
+        GLenum       internal_format,
3055
+        Offset       offset = {},
3056
+        GLint        level  = 0)
3057
+    {
3058
+        if (GLBase::debug() >= 1)
3059
+            GLBase::check_supported({1, 3}, {});
3060
+        glCompressedTexSubImage2D(
3061
+            target,
3062
+            level,
3063
+            std::get<Is>(offset)...,
3064
+            std::get<Is>(size)...,
3065
+            internal_format,
3066
+            data_size,
3067
+            data);
3068
+    }
3069
+    template <typename Value = GLubyte>
3070
+    void static tex_storage(
3071
+        GLenum  target,
3072
+        Size    size,
3073
+        GLenum  internal_format = 0,
3074
+        GLsizei levels          = 1)
3075
+    {
3076
+        if (GLBase::debug() >= 1)
3077
+            GLBase::check_supported({4, 2}, "GL_ARB_texture_storage");
3078
+        if (!internal_format)
3079
+            internal_format = GLTraits::Value<Value>::internal_format;
3080
+        glTexStorage2D(target, levels, internal_format, std::get<Is>(size)...);
3081
+    }
3082
+    template <typename Value = GLubyte>
3083
+    void static texture_storage(
3084
+        GLuint  texture,
3085
+        Size    size,
3086
+        GLenum  internal_format = 0,
3087
+        GLsizei levels          = 1)
3088
+    {
3089
+        if (GLBase::debug() >= 1)
3090
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3091
+        if (!internal_format)
3092
+            internal_format = GLTraits::Value<Value>::internal_format;
3093
+        glTextureStorage2D(
3094
+            texture,
3095
+            levels,
3096
+            internal_format,
3097
+            std::get<Is>(size)...);
3098
+    }
3099
+    template <typename Value = GLubyte>
3100
+    void static texture_sub_image(
3101
+        GLuint        texture,
3102
+        Size          size,
3103
+        Value const * data,
3104
+        GLenum        format = 0,
3105
+        GLenum        type   = 0,
3106
+        Offset        offset = {},
3107
+        GLint         level  = 0)
3108
+    {
3109
+        if (GLBase::debug() >= 1)
3110
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3111
+        if (!format)
3112
+            format = GLTraits::Value<Value>::format;
3113
+        if (!type)
3114
+            type = GLTraits::Value<Value>::type;
3115
+        glTextureSubImage2D(
3116
+            texture,
3117
+            level,
3118
+            std::get<Is>(offset)...,
3119
+            std::get<Is>(size)...,
3120
+            format,
3121
+            type,
3122
+            data);
3123
+    }
3124
+    void static copy_texture_sub_image(
3125
+        GLuint     texture,
3126
+        CopySize   copy_size,
3127
+        CopyOffset copy_offset = {},
3128
+        Offset     offset      = {},
3129
+        GLint      level       = 0)
3130
+    {
3131
+        if (GLBase::debug() >= 1)
3132
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3133
+        glCopyTextureSubImage2D(
3134
+            texture,
3135
+            level,
3136
+            std::get<Is>(offset)...,
3137
+            std::get<CopyOffsetIs>(copy_offset)...,
3138
+            std::get<CopySizeIs>(copy_size)...);
3139
+    }
3140
+    void static compressed_texture_sub_image(
3141
+        GLuint       texture,
3142
+        Size         size,
3143
+        GLsizei      data_size,
3144
+        void const * data,
3145
+        GLenum       internal_format,
3146
+        Offset       offset = {},
3147
+        GLint        level  = 0)
3148
+    {
3149
+        if (GLBase::debug() >= 1)
3150
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3151
+        glCompressedTextureSubImage2D(
3152
+            texture,
3153
+            level,
3154
+            std::get<Is>(offset)...,
3155
+            std::get<Is>(size)...,
3156
+            internal_format,
3157
+            data_size,
3158
+            data);
3159
+    }
3160
+};
3161
+
3162
+template <>
3163
+struct GLTraits::Texture<2>
3164
+    : Texture_<2, MakeIndices<2>, MakeIndices<2 < 2 ? 2 : 2>, MakeIndices<2>>
3165
+{
3166
+};
3167
+
3168
+template <
3169
+    std::size_t... Is,
3170
+    std::size_t... CopySizeIs,
3171
+    std::size_t... CopyOffsetIs>
3172
+struct GLTraits::Texture_<
3173
+    3,
3174
+    GLTraits::Indices<Is...>,
3175
+    GLTraits::Indices<CopySizeIs...>,
3176
+    GLTraits::Indices<CopyOffsetIs...>> : GLTraits::Texture<0>
3177
+{
3178
+    using Size       = std::array<GLsizei, sizeof...(Is)>;
3179
+    using Offset     = std::array<GLsizei, sizeof...(Is)>;
3180
+    using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>;
3181
+    using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>;
3182
+    auto static constexpr default_target  = GL_TEXTURE_3D;
3183
+    auto static constexpr default_binding = GL_TEXTURE_BINDING_3D;
3184
+    template <typename Value = GLubyte>
3185
+    void static tex_image(
3186
+        GLenum        target,
3187
+        Size          size,
3188
+        GLenum        internal_format = 0,
3189
+        Value const * data            = nullptr,
3190
+        GLenum        format          = 0,
3191
+        GLenum        type            = 0,
3192
+        GLint         level           = 0,
3193
+        GLint         border          = 0)
3194
+    {
3195
+        if (GLBase::debug() >= 1)
3196
+            GLBase::check_supported({1, 2}, {});
3197
+        defaults_(
3198
+            internal_format,
3199
+            format,
3200
+            type,
3201
+            GLTraits::Value<Value>::internal_format,
3202
+            GLTraits::Value<Value>::format,
3203
+            GLTraits::Value<Value>::type);
3204
+        glTexImage3D(
3205
+            target,
3206
+            level,
3207
+            (GLint)internal_format,
3208
+            std::get<Is>(size)...,
3209
+            border,
3210
+            format,
3211
+            type,
3212
+            data);
3213
+    }
3214
+    template <typename Value = GLubyte>
3215
+    void static tex_sub_image(
3216
+        GLenum        target,
3217
+        Size          size,
3218
+        Value const * data,
3219
+        GLenum        format = 0,
3220
+        GLenum        type   = 0,
3221
+        Offset        offset = {},
3222
+        GLint         level  = 0)
3223
+    {
3224
+        if (GLBase::debug() >= 1)
3225
+            GLBase::check_supported({1, 2}, {});
3226
+        if (!format)
3227
+            format = GLTraits::Value<Value>::format;
3228
+        if (!type)
3229
+            type = GLTraits::Value<Value>::type;
3230
+        glTexSubImage3D(
3231
+            target,
3232
+            level,
3233
+            std::get<Is>(offset)...,
3234
+            std::get<Is>(size)...,
3235
+            format,
3236
+            type,
3237
+            data);
3238
+    }
3239
+    void static copy_tex_sub_image(
3240
+        GLenum     target,
3241
+        CopySize   copy_size,
3242
+        CopyOffset copy_offset = {},
3243
+        Offset     offset      = {},
3244
+        GLint      level       = 0)
3245
+    {
3246
+        if (GLBase::debug() >= 1)
3247
+            GLBase::check_supported({1, 2}, {});
3248
+        glCopyTexSubImage3D(
3249
+            target,
3250
+            level,
3251
+            std::get<Is>(offset)...,
3252
+            std::get<CopyOffsetIs>(copy_offset)...,
3253
+            std::get<CopySizeIs>(copy_size)...);
3254
+    }
3255
+    void static compressed_tex_image(
3256
+        GLenum       target,
3257
+        Size         size,
3258
+        GLenum       internal_format,
3259
+        GLsizei      data_size = 0,
3260
+        void const * data      = nullptr,
3261
+        GLint        level     = 0,
3262
+        GLint        border    = 0)
3263
+    {
3264
+        if (GLBase::debug() >= 1)
3265
+            GLBase::check_supported({1, 3}, {});
3266
+        glCompressedTexImage3D(
3267
+            target,
3268
+            level,
3269
+            internal_format,
3270
+            std::get<Is>(size)...,
3271
+            border,
3272
+            data_size,
3273
+            data);
3274
+    }
3275
+    void static compressed_tex_sub_image(
3276
+        GLenum       target,
3277
+        Size         size,
3278
+        GLsizei      data_size,
3279
+        void const * data,
3280
+        GLenum       internal_format,
3281
+        Offset       offset = {},
3282
+        GLint        level  = 0)
3283
+    {
3284
+        if (GLBase::debug() >= 1)
3285
+            GLBase::check_supported({1, 3}, {});
3286
+        glCompressedTexSubImage3D(
3287
+            target,
3288
+            level,
3289
+            std::get<Is>(offset)...,
3290
+            std::get<Is>(size)...,
3291
+            internal_format,
3292
+            data_size,
3293
+            data);
3294
+    }
3295
+    template <typename Value = GLubyte>
3296
+    void static tex_storage(
3297
+        GLenum  target,
3298
+        Size    size,
3299
+        GLenum  internal_format = 0,
3300
+        GLsizei levels          = 1)
3301
+    {
3302
+        if (GLBase::debug() >= 1)
3303
+            GLBase::check_supported({4, 2}, "GL_ARB_texture_storage");
3304
+        if (!internal_format)
3305
+            internal_format = GLTraits::Value<Value>::internal_format;
3306
+        glTexStorage3D(target, levels, internal_format, std::get<Is>(size)...);
3307
+    }
3308
+    template <typename Value = GLubyte>
3309
+    void static texture_storage(
3310
+        GLuint  texture,
3311
+        Size    size,
3312
+        GLenum  internal_format = 0,
3313
+        GLsizei levels          = 1)
3314
+    {
3315
+        if (GLBase::debug() >= 1)
3316
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3317
+        if (!internal_format)
3318
+            internal_format = GLTraits::Value<Value>::internal_format;
3319
+        glTextureStorage3D(
3320
+            texture,
3321
+            levels,
3322
+            internal_format,
3323
+            std::get<Is>(size)...);
3324
+    }
3325
+    template <typename Value = GLubyte>
3326
+    void static texture_sub_image(
3327
+        GLuint        texture,
3328
+        Size          size,
3329
+        Value const * data,
3330
+        GLenum        format = 0,
3331
+        GLenum        type   = 0,
3332
+        Offset        offset = {},
3333
+        GLint         level  = 0)
3334
+    {
3335
+        if (GLBase::debug() >= 1)
3336
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3337
+        if (!format)
3338
+            format = GLTraits::Value<Value>::format;
3339
+        if (!type)
3340
+            type = GLTraits::Value<Value>::type;
3341
+        glTextureSubImage3D(
3342
+            texture,
3343
+            level,
3344
+            std::get<Is>(offset)...,
3345
+            std::get<Is>(size)...,
3346
+            format,
3347
+            type,
3348
+            data);
3349
+    }
3350
+    void static copy_texture_sub_image(
3351
+        GLuint     texture,
3352
+        CopySize   copy_size,
3353
+        CopyOffset copy_offset = {},
3354
+        Offset     offset      = {},
3355
+        GLint      level       = 0)
3356
+    {
3357
+        if (GLBase::debug() >= 1)
3358
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3359
+        glCopyTextureSubImage3D(
3360
+            texture,
3361
+            level,
3362
+            std::get<Is>(offset)...,
3363
+            std::get<CopyOffsetIs>(copy_offset)...,
3364
+            std::get<CopySizeIs>(copy_size)...);
3365
+    }
3366
+    void static compressed_texture_sub_image(
3367
+        GLuint       texture,
3368
+        Size         size,
3369
+        GLsizei      data_size,
3370
+        void const * data,
3371
+        GLenum       internal_format,
3372
+        Offset       offset = {},
3373
+        GLint        level  = 0)
3374
+    {
3375
+        if (GLBase::debug() >= 1)
3376
+            GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
3377
+        glCompressedTextureSubImage3D(
3378
+            texture,
3379
+            level,
3380
+            std::get<Is>(offset)...,
3381
+            std::get<Is>(size)...,
3382
+            internal_format,
3383
+            data_size,
3384
+            data);
3385
+    }
3386
+};
3387
+
3388
+template <>
3389
+struct GLTraits::Texture<3>
3390
+    : Texture_<3, MakeIndices<3>, MakeIndices<3 < 2 ? 3 : 2>, MakeIndices<2>>
3391
+{
3392
+};
3393
+
... ...
@@ -6,6 +6,7 @@
6 6
 
7 7
 /// Includes
8 8
 
9
+#include <array>
9 10
 #include <cstddef>
10 11
 #include <string>
11 12
 
... ...
@@ -32,6 +33,44 @@ public:
32 33
     template<GLenum object_type>
33 34
     struct Object;
34 35
 
36
+    //// Texture
37
+
38
+    template<std::size_t N>
39
+    struct Texture;
40
+
41
+private:
42
+
43
+    //// Helpers
44
+
45
+    // Stripped down version of C++14's `std::{,make_}index_sequence`.
46
+
47
+    template<std::size_t... Is>
48
+    struct Indices
49
+    {};
50
+
51
+    template<std::size_t N, std::size_t... Is>
52
+    struct MakeIndices_ : MakeIndices_<N - 1, N - 1, Is...>
53
+    {};
54
+
55
+    template<std::size_t... Is>
56
+    struct MakeIndices_<0, Is...>
57
+    {
58
+        using Indices_ = Indices<Is...>;
59
+    };
60
+
61
+    template<std::size_t N>
62
+    using MakeIndices = typename MakeIndices_<N>::Indices_;
63
+
64
+    //// Texture
65
+
66
+    template <
67
+        std::size_t N,
68
+        typename    Indices,
69
+        typename    CopySizeIndices,
70
+        typename    CopyOffsetIndices
71
+    >
72
+    struct Texture_;
73
+
35 74
 };
36 75
 
37 76
 //// Helpers
... ...
@@ -251,6 +290,285 @@ GLTRAITS_OBJECT(     SAMPLER,            Sampler,           Samplers,
251 290
 GLTRAITS_OBJECT(     TRANSFORM_FEEDBACK, TransformFeedback, TransformFeedbacks, OMIT, 4, 0, "GL_ARB_transform_feedback2")
252 291
 GLTRAITS_OBJECT(     PROGRAM_PIPELINE,   ProgramPipeline,   ProgramPipelines,   KEEP, 4, 1, "GL_ARB_separate_shader_objects")
253 292
 
293
+//// Texture
294
+
295
+template<>
296
+struct GLTraits::Texture<0>
297
+{
298
+protected:
299
+    void static defaults_(
300
+        GLenum & internal_format,
301
+        GLenum & format,
302
+        GLenum & type,
303
+        GLenum   default_internal_format,
304
+        GLenum   default_format,
305
+        GLenum   default_type
306
+    )
307
+    {
308
+        if (!internal_format) internal_format = default_internal_format;
309
+        switch (internal_format)
310
+        {
311
+            case GL_DEPTH_STENCIL:
312
+            case GL_DEPTH24_STENCIL8:
313
+            case GL_DEPTH32F_STENCIL8:
314
+                if (!format) format = GL_DEPTH_STENCIL;
315
+                if (!type)   type   = GL_UNSIGNED_INT_24_8;
316
+                break;
317
+            case GL_DEPTH_COMPONENT:
318
+            case GL_DEPTH_COMPONENT16:
319
+            case GL_DEPTH_COMPONENT24:
320
+            case GL_DEPTH_COMPONENT32:
321
+            case GL_DEPTH_COMPONENT32F:
322
+                if (!format) format = GL_DEPTH_COMPONENT;
323
+                if (!type)   type   = GL_UNSIGNED_INT;
324
+                break;
325
+            case GL_STENCIL_INDEX:
326
+            case GL_STENCIL_INDEX1:
327
+            case GL_STENCIL_INDEX4:
328
+            case GL_STENCIL_INDEX8:
329
+            case GL_STENCIL_INDEX16:
330
+                if (!format) format = GL_STENCIL_INDEX;
331
+                if (!type)   type   = GL_UNSIGNED_BYTE;
332
+                break;
333
+            default:
334
+                if (!format) format = default_format;
335
+                if (!type)   type   = default_type;
336
+        }
337
+    }
338
+};
339
+
340
+#define GLTRAITS_TEXTURE_IMAGE( \
341
+    N, \
342
+    TEXTURE, TEXTURE_LOWER, \
343
+    TYPE, NAME, \
344
+    V1, V2, EXT \
345
+) \
346
+    template<typename Value = GLubyte> \
347
+    void static TEXTURE_LOWER##_image( \
348
+        TYPE          NAME, \
349
+        Size          size, \
350
+        GLenum        internal_format = 0, \
351
+        Value const * data            = nullptr, \
352
+        GLenum        format          = 0, \
353
+        GLenum        type            = 0, \
354
+        GLint         level           = 0, \
355
+        GLint         border          = 0 \
356
+    ) \
357
+    { \
358
+        if (GLBase::debug() >= 1) \
359
+            GLBase::check_supported({V1, V2}, EXT); \
360
+        defaults_( \
361
+            internal_format, \
362
+            format, \
363
+            type, \
364
+            GLTraits::Value<Value>::internal_format, \
365
+            GLTraits::Value<Value>::format, \
366
+            GLTraits::Value<Value>::type \
367
+        ); \
368
+        gl##TEXTURE##Image##N##D( \
369
+            NAME, \
370
+            level, \
371
+            (GLint)internal_format, \
372
+            std::get<Is>(size)..., \
373
+            border, \
374
+            format, \
375
+            type, \
376
+            data \
377
+        ); \
378
+    }
379
+
380
+#define GLTRAITS_TEXTURE_STORAGE( \
381
+    N, \
382
+    TEXTURE, TEXTURE_LOWER, \
383
+    TYPE, NAME, \
384
+    V1, V2, EXT \
385
+) \
386
+    template<typename Value = GLubyte> \
387
+    void static TEXTURE_LOWER##_storage( \
388
+        TYPE    NAME, \
389
+        Size    size, \
390
+        GLenum  internal_format = 0, \
391
+        GLsizei levels          = 1 \
392
+    ) \
393
+    { \
394
+        if (GLBase::debug() >= 1) \
395
+            GLBase::check_supported({V1, V2}, EXT); \
396
+        if (!internal_format) \
397
+            internal_format = GLTraits::Value<Value>::internal_format; \
398
+        gl##TEXTURE##Storage##N##D( \
399
+            NAME, \
400
+            levels, \
401
+            internal_format, \
402
+            std::get<Is>(size)... \
403
+        ); \
404
+    }
405
+
406
+#define GLTRAITS_TEXTURE_SUB_IMAGE( \
407
+    N, \
408
+    TEXTURE, TEXTURE_LOWER, \
409
+    TYPE, NAME, \
410
+    V1, V2, EXT \
411
+) \
412
+    template<typename Value = GLubyte> \
413
+    void static TEXTURE_LOWER##_sub_image( \
414
+        TYPE          NAME, \
415
+        Size          size, \
416
+        Value const * data, \
417
+        GLenum        format = 0, \
418
+        GLenum        type   = 0, \
419
+        Offset        offset = {}, \
420
+        GLint         level  = 0 \
421
+    ) \
422
+    { \
423
+        if (GLBase::debug() >= 1) \
424
+            GLBase::check_supported({V1, V2}, EXT); \
425
+        if (!format) format = GLTraits::Value<Value>::format; \
426
+        if (!type)   type   = GLTraits::Value<Value>::type; \
427
+        gl##TEXTURE##SubImage##N##D( \
428
+            NAME, \
429
+            level, \
430
+            std::get<Is>(offset)..., \
431
+            std::get<Is>(size)  ..., \
432
+            format, \
433
+            type, \
434
+            data \
435
+        ); \
436
+    }
437
+
438
+#define GLTRAITS_TEXTURE_COPY_SUB_IMAGE( \
439
+    N, \
440
+    TEXTURE, TEXTURE_LOWER, \
441
+    TYPE, NAME, \
442
+    V1, V2, EXT \
443
+) \
444
+    void static copy_##TEXTURE_LOWER##_sub_image( \
445
+        TYPE       NAME, \
446
+        CopySize   copy_size, \
447
+        CopyOffset copy_offset = {}, \
448
+        Offset     offset      = {}, \
449
+        GLint      level       = 0 \
450
+    ) \
451
+    { \
452
+        if (GLBase::debug() >= 1) \
453
+            GLBase::check_supported({V1, V2}, EXT); \
454
+        glCopy##TEXTURE##SubImage##N##D( \
455
+            NAME, \
456
+            level, \
457
+            std::get<Is>          (offset)     ..., \
458
+            std::get<CopyOffsetIs>(copy_offset)..., \
459
+            std::get<CopySizeIs>  (copy_size)  ... \
460
+        ); \
461
+    }
462
+
463
+#define GLTRAITS_TEXTURE_COMPRESSED_IMAGE( \
464
+    N, \
465
+    TEXTURE, TEXTURE_LOWER, \
466
+    TYPE, NAME, \
467
+    V1, V2, EXT \
468
+) \
469
+    void static compressed_##TEXTURE_LOWER##_image( \
470
+        TYPE         NAME, \
471
+        Size         size, \
472
+        GLenum       internal_format, \
473
+        GLsizei      data_size = 0, \
474
+        void const * data      = nullptr, \
475
+        GLint        level     = 0, \
476
+        GLint        border    = 0 \
477
+    ) \
478
+    { \
479
+        if (GLBase::debug() >= 1) \
480
+            GLBase::check_supported({V1, V2}, EXT); \
481
+        glCompressed##TEXTURE##Image##N##D( \
482
+            NAME, \
483
+            level, \
484
+            internal_format, \
485
+            std::get<Is>(size)..., \
486
+            border, \
487
+            data_size, \
488
+            data \
489
+        ); \
490
+    }
491
+
492
+#define GLTRAITS_TEXTURE_COMPRESSED_SUB_IMAGE( \
493
+    N, \
494
+    TEXTURE, TEXTURE_LOWER, \
495
+    TYPE, NAME, \
496
+    V1, V2, EXT \
497
+) \
498
+    void static compressed_##TEXTURE_LOWER##_sub_image( \
499
+        TYPE         NAME, \
500
+        Size         size, \
501
+        GLsizei      data_size, \
502
+        void const * data, \
503
+        GLenum       internal_format, \
504
+        Offset       offset = {}, \
505
+        GLint        level  = 0 \
506
+    ) \
507
+    { \
508
+        if (GLBase::debug() >= 1) \
509
+            GLBase::check_supported({V1, V2}, EXT); \
510
+        glCompressed##TEXTURE##SubImage##N##D( \
511
+            NAME, \
512
+            level, \
513
+            std::get<Is>(offset)..., \
514
+            std::get<Is>(size)  ..., \
515
+            internal_format, \
516
+            data_size, \
517
+            data \
518
+        ); \
519
+    }
520
+
521
+#define GLTRAITS_TEXTURE( \
522
+    N, \
523
+    V1_1, V2_1, \
524
+    V1_2, V2_2 \
525
+) \
526
+    template< \
527
+        std::size_t... Is, \
528
+        std::size_t... CopySizeIs, \
529
+        std::size_t... CopyOffsetIs \
530
+    > \
531
+    struct GLTraits::Texture_< \
532
+        N, \
533
+        GLTraits::Indices<Is...>, \
534
+        GLTraits::Indices<CopySizeIs...>, \
535
+        GLTraits::Indices<CopyOffsetIs...> \
536
+    > \
537
+    : \
538
+        GLTraits::Texture<0> \
539
+    { \
540
+        using Size       = std::array<GLsizei, sizeof...(Is)>; \
541
+        using Offset     = std::array<GLsizei, sizeof...(Is)>; \
542
+        using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>; \
543
+        using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>; \
544
+        auto static constexpr default_target  = GL_TEXTURE_##N##D; \
545
+        auto static constexpr default_binding = GL_TEXTURE_BINDING_##N##D; \
546
+        GLTRAITS_TEXTURE_IMAGE(               N, Tex,     tex,     GLenum, target,  V1_1, V2_1, {}) \
547
+        GLTRAITS_TEXTURE_SUB_IMAGE(           N, Tex,     tex,     GLenum, target,  V1_2, V2_2, {}) \
548
+        GLTRAITS_TEXTURE_COPY_SUB_IMAGE(      N, Tex,     tex,     GLenum, target,  V1_2, V2_2, {}) \
549
+        GLTRAITS_TEXTURE_COMPRESSED_IMAGE(    N, Tex,     tex,     GLenum, target,  1,    3,    {}) \
550
+        GLTRAITS_TEXTURE_COMPRESSED_SUB_IMAGE(N, Tex,     tex,     GLenum, target,  1,    3,    {}) \
551
+        GLTRAITS_TEXTURE_STORAGE(             N, Tex,     tex,     GLenum, target,  4,    2,    "GL_ARB_texture_storage") \
552
+        GLTRAITS_TEXTURE_STORAGE(             N, Texture, texture, GLuint, texture, 4,    5,    "GL_ARB_direct_state_access") \
553
+        GLTRAITS_TEXTURE_SUB_IMAGE(           N, Texture, texture, GLuint, texture, 4,    5,    "GL_ARB_direct_state_access") \
554
+        GLTRAITS_TEXTURE_COPY_SUB_IMAGE(      N, Texture, texture, GLuint, texture, 4,    5,    "GL_ARB_direct_state_access") \
555
+        GLTRAITS_TEXTURE_COMPRESSED_SUB_IMAGE(N, Texture, texture, GLuint, texture, 4,    5,    "GL_ARB_direct_state_access") \
556
+    }; \
557
+    template<> \
558
+    struct GLTraits::Texture<N> \
559
+    : \
560
+        Texture_< \
561
+            N, \
562
+            MakeIndices<N>, \
563
+            MakeIndices<N < 2 ? N : 2>, \
564
+            MakeIndices<2> \
565
+        > \
566
+    {};
567
+
568
+GLTRAITS_TEXTURE(1, 1, 0, 1, 1)
569
+GLTRAITS_TEXTURE(2, 1, 0, 1, 1)
570
+GLTRAITS_TEXTURE(3, 1, 2, 1, 2)
571
+
254 572
 
255 573
 /// Guards
256 574
 
... ...
@@ -81,6 +81,33 @@ struct GLTraitsTest : protected GLBase
81 81
             GLTRAITS_TEST_OBJECT(info_log);
82 82
     }
83 83
 
84
+    template<std::size_t N>
85
+    void static test_texture()
86
+    {
87
+        using Traits = GLTraits::Texture<N>;
88
+        static_assert(
89
+            std::is_empty<Traits>::value,
90
+            "GLTraits::Texture must be empty"
91
+        );
92
+        #define GLTRAITS_TEST_TEXTURE(NAME) \
93
+            << std::left << std::setw(32) \
94
+            << "  " #NAME ":" \
95
+            << (void *)Traits::NAME \
96
+            << "\n"
97
+        std::cout
98
+            << "Texture<" << N << ">" << "\n"
99
+            GLTRAITS_TEST_TEXTURE(template tex_image<>)
100
+            GLTRAITS_TEST_TEXTURE(template tex_storage<>)
101
+            GLTRAITS_TEST_TEXTURE(template texture_storage<>)
102
+            GLTRAITS_TEST_TEXTURE(template tex_sub_image<>)
103
+            GLTRAITS_TEST_TEXTURE(template texture_sub_image<>)
104
+            GLTRAITS_TEST_TEXTURE(copy_tex_sub_image)
105
+            GLTRAITS_TEST_TEXTURE(copy_texture_sub_image)
106
+            GLTRAITS_TEST_TEXTURE(compressed_tex_image)
107
+            GLTRAITS_TEST_TEXTURE(compressed_tex_sub_image)
108
+            GLTRAITS_TEST_TEXTURE(compressed_texture_sub_image);
109
+    }
110
+
84 111
 };
85 112
 
86 113
 
... ...
@@ -104,4 +131,8 @@ int main()
104 131
 
105 132
     GLTraitsTest::test_object<GL_SHADER, GLenum>();
106 133
     GLTraitsTest::test_object<GL_PROGRAM_PIPELINE>();
134
+
135
+    GLTraitsTest::test_texture<1>();
136
+    GLTraitsTest::test_texture<2>();
137
+    GLTraitsTest::test_texture<3>();
107 138
 }