]> git.tdb.fi Git - libs/gl.git/blob - source/core/texture3d.cpp
Remove the separate allocation step from textures and buffers
[libs/gl.git] / source / core / texture3d.cpp
1 #include <cmath>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_texture_storage.h>
4 #include <msp/gl/extensions/ext_texture3d.h>
5 #include <msp/gl/extensions/ext_texture_array.h>
6 #include <msp/graphics/image.h>
7 #include "error.h"
8 #include "texture3d.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 Texture3D::Texture3D(GLenum t):
16         Texture(t),
17         width(0),
18         height(0),
19         depth(0)
20 { }
21
22 Texture3D::Texture3D():
23         Texture(GL_TEXTURE_3D),
24         width(0),
25         height(0),
26         depth(0)
27 {
28         static Require _req(EXT_texture3D);
29 }
30
31 void Texture3D::storage(PixelFormat fmt, unsigned wd, unsigned ht, unsigned dp, unsigned lv)
32 {
33         if(width>0)
34         {
35                 if(fmt!=format || wd!=width || ht!=height || dp!=depth || (lv && lv!=levels))
36                         throw incompatible_data("Texture3D::storage");
37                 return;
38         }
39         if(wd==0 || ht==0 || dp==0)
40                 throw invalid_argument("Texture3D::storage");
41
42         set_format(fmt);
43         width = wd;
44         height = ht;
45         depth = dp;
46         levels = get_n_levels();
47         if(lv>0)
48                 levels = min(levels, lv);
49
50         GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
51         if(ARB_texture_storage)
52         {
53                 if(ARB_direct_state_access)
54                         glTextureStorage3D(id, levels, gl_fmt, width, height, depth);
55                 else
56                 {
57                         bind_scratch();
58                         glTexStorage3D(target, levels, gl_fmt, width, height, depth);
59                 }
60         }
61         else
62         {
63                 bind_scratch();
64                 GLenum comp = get_gl_components(get_components(storage_fmt));
65                 GLenum type = get_gl_type(get_component_type(storage_fmt));
66                 for(unsigned i=0; i<levels; ++i)
67                 {
68                         LinAl::Vector<unsigned, 3> lv_size = get_level_size(i);
69                         glTexImage3D(target, i, gl_fmt, lv_size.x, lv_size.y, lv_size.z, 0, comp, type, 0);
70                 }
71                 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
72         }
73
74         apply_swizzle();
75 }
76
77 void Texture3D::image(unsigned level, const void *data)
78 {
79         LinAl::Vector<unsigned, 3> size = get_level_size(level);
80         return sub_image(level, 0, 0, 0, size.x, size.y, size.z, data);
81 }
82
83 void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, const void *data)
84 {
85         if(width==0 || height==0 || depth==0)
86                 throw invalid_operation("Texture3D::sub_image");
87         if(level>=levels)
88                 throw out_of_range("Texture3D::sub_image");
89
90         GLenum comp = get_gl_components(get_components(storage_fmt));
91         GLenum type = get_gl_type(get_component_type(storage_fmt));
92         if(ARB_direct_state_access)
93                 glTextureSubImage3D(id, level, x, y, z, wd, ht, dp, comp, type, data);
94         else
95         {
96                 bind_scratch();
97                 glTexSubImage3D(target, level, x, y, z, wd, ht, dp, comp, type, data);
98         }
99 }
100
101 void Texture3D::image(const Graphics::Image &img, unsigned lv)
102 {
103         unsigned w = img.get_width();
104         unsigned h = img.get_height();
105
106         if(h%w)
107                 throw incompatible_data("Texture3D::load_image");
108         unsigned d = h/w;
109         h = w;
110
111         PixelFormat fmt = pixelformat_from_image(img);
112         storage(make_pixelformat(get_components(fmt), get_component_type(fmt), use_srgb_format), w, h, d, lv);
113
114         image(0, img.get_pixels());
115 }
116
117 unsigned Texture3D::get_n_levels() const
118 {
119         unsigned s = max(width, height);
120         if(target!=GL_TEXTURE_2D_ARRAY)
121                 s = max(s, depth);
122         unsigned n = 0;
123         for(; s; s>>=1, ++n) ;
124         return n;
125 }
126
127 LinAl::Vector<unsigned, 3> Texture3D::get_level_size(unsigned level) const
128 {
129         unsigned w = width>>level;
130         unsigned h = height>>level;
131         unsigned d = depth;
132         if(target!=GL_TEXTURE_2D_ARRAY)
133                 d >>= level;
134
135         if(!w && (h || d))
136                 w = 1;
137         if(!h && (w || d))
138                 h = 1;
139         if(!d && (w || h))
140                 d = 1;
141
142         return LinAl::Vector<unsigned, 3>(w, h, d);
143 }
144
145 uint64_t Texture3D::get_data_size() const
146 {
147         return id ? width*height*depth*get_pixel_size(storage_fmt) : 0;
148 }
149
150
151 Texture3D::Loader::Loader(Texture3D &t):
152         DataFile::DerivedObjectLoader<Texture3D, Texture::Loader>(t)
153 {
154         init();
155 }
156
157 Texture3D::Loader::Loader(Texture3D &t, Collection &c):
158         DataFile::DerivedObjectLoader<Texture3D, Texture::Loader>(t, c)
159 {
160         init();
161 }
162
163 void Texture3D::Loader::init()
164 {
165         add("raw_data", &Loader::raw_data);
166         add("storage", &Loader::storage);
167         add("storage", &Loader::storage_levels);
168 }
169
170 void Texture3D::Loader::raw_data(const string &data)
171 {
172         obj.image(0, data.data());
173 }
174
175 void Texture3D::Loader::storage(PixelFormat fmt, unsigned w, unsigned h, unsigned d)
176 {
177         obj.storage(fmt, w, h, d);
178 }
179
180 void Texture3D::Loader::storage_levels(PixelFormat fmt, unsigned w, unsigned h, unsigned d, unsigned l)
181 {
182         obj.storage(fmt, w, h, d, l);
183 }
184
185 } // namespace GL
186 } // namespace Msp