1 #include <msp/datafile/rawdata.h>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_texture_storage.h>
4 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
5 #include <msp/graphics/imageloader.h>
9 #include "texture2d_backend.h"
16 class OpenGLTexture2D::AsyncLoader: public Resource::AsyncLoader
22 char *mapped_address = 0;
23 Graphics::Image image;
24 Graphics::ImageLoader *img_loader = 0;
25 DataFile::RawData *raw_data = 0;
30 AsyncLoader(Texture2D &, IO::Seekable &);
33 virtual bool needs_sync() const;
34 virtual bool process();
38 OpenGLTexture2D::OpenGLTexture2D():
39 Texture(GL_TEXTURE_2D)
42 void OpenGLTexture2D::allocate()
44 unsigned width = static_cast<const Texture2D *>(this)->width;
45 unsigned height = static_cast<const Texture2D *>(this)->height;
46 unsigned levels = static_cast<const Texture2D *>(this)->levels;
51 GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
52 if(ARB_texture_storage)
54 if(ARB_direct_state_access)
55 glTextureStorage2D(id, levels, gl_fmt, width, height);
59 glTexStorage2D(target, levels, gl_fmt, width, height);
65 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
66 GLenum comp = get_gl_components(get_components(storage_fmt));
67 GLenum type = get_gl_type(get_component_type(storage_fmt));
68 for(unsigned i=0; i<levels; ++i)
70 auto lv_size = static_cast<const Texture2D *>(this)->get_level_size(i);
71 glTexImage2D(target, i, gl_fmt, lv_size.x, lv_size.y, 0, comp, type, 0);
78 void OpenGLTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
80 GLenum comp = get_gl_components(get_components(storage_fmt));
81 GLenum type = get_gl_type(get_component_type(storage_fmt));
82 if(ARB_direct_state_access)
83 glTextureSubImage2D(id, level, x, y, wd, ht, comp, type, data);
87 glTexSubImage2D(target, level, x, y, wd, ht, comp, type, data);
91 void OpenGLTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const Buffer &buffer, unsigned offset)
93 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer.id);
94 sub_image(level, x, y, wd, ht, reinterpret_cast<void *>(offset));
95 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
98 Resource::AsyncLoader *OpenGLTexture2D::load(IO::Seekable &io, const Resources *)
100 return new AsyncLoader(static_cast<Texture2D &>(*this), io);
103 uint64_t OpenGLTexture2D::get_data_size() const
108 unsigned width = static_cast<const Texture2D *>(this)->width;
109 unsigned height = static_cast<const Texture2D *>(this)->height;
110 unsigned levels = static_cast<const Texture2D *>(this)->levels;
112 size_t level_size = width*height*get_pixel_size(format);
113 size_t total_size = level_size;
114 for(unsigned i=0; i<levels; ++i, level_size>>=2)
115 total_size += level_size;
119 void OpenGLTexture2D::unload()
121 glDeleteTextures(1, &id);
126 OpenGLTexture2D::AsyncLoader::AsyncLoader(Texture2D &t, IO::Seekable &i):
132 io.seek(0, IO::S_BEG);
134 if(DataFile::RawData::detect_signature(string(magic, 4)))
136 raw_data = new DataFile::RawData;
137 raw_data->open_io(io, "async");
140 img_loader = Graphics::ImageLoader::open_io(io);
143 OpenGLTexture2D::AsyncLoader::~AsyncLoader()
146 pixel_buffer.unmap();
151 bool OpenGLTexture2D::AsyncLoader::needs_sync() const
156 bool OpenGLTexture2D::AsyncLoader::process()
161 n_bytes = raw_data->get_size();
164 image.load_headers(*img_loader);
165 n_bytes = image.get_stride()*image.get_height();
170 pixel_buffer.storage(n_bytes);
171 mapped_address = reinterpret_cast<char *>(pixel_buffer.map());
176 raw_data->load_into(mapped_address);
178 image.load_into(*img_loader, mapped_address);
183 if(!pixel_buffer.unmap())
194 unsigned w = image.get_width();
195 unsigned h = image.get_height();
196 texture.storage(pixelformat_from_image(image, texture.use_srgb_format), w, h);
198 texture.OpenGLTexture2D::sub_image(0, 0, 0, texture.width, texture.height, pixel_buffer, 0);
200 if(texture.auto_gen_mipmap)
201 texture.generate_mipmap();