+ if(width==0 || height==0 || depth==0)
+ throw invalid_operation("Texture3D::image");
+
+ unsigned w = width;
+ unsigned h = height;
+ unsigned d = depth;
+ get_level_size(level, w, h, d);
+
+ if(ARB_texture_storage)
+ return sub_image(level, 0, 0, 0, w, h, d, fmt, type, data);
+
+ BindRestore _bind(this);
+ glTexImage3D(target, level, ifmt, width, height, depth, 0, get_upload_format(fmt), type, data);
+
+ allocated |= 1<<level;
+ if(auto_gen_mipmap && level==0)
+ {
+ generate_mipmap();
+ allocated |= (1<<get_n_levels())-1;
+ }
+}
+
+void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, PixelFormat fmt, DataType type, const void *data)
+{
+ if(width==0 || height==0 || depth==0)
+ throw invalid_operation("Texture3D::image");
+
+ Conditional<BindRestore> _bind(!ARB_direct_state_access, this);
+ allocate(level);
+
+ fmt = get_upload_format(fmt);
+ if(ARB_direct_state_access)
+ glTextureSubImage3D(id, level, x, y, z, wd, ht, dp, fmt, type, data);
+ else
+ glTexSubImage3D(target, level, x, y, z, wd, ht, dp, fmt, type, data);
+
+ if(auto_gen_mipmap && level==0)
+ generate_mipmap();