const T *Bindable<T>::cur_obj;
+/**
+A helper class for Bindables that revert to a default object on unbind.
+*/
+template<typename T>
+class BindableWithDefault: protected Bindable<T>
+{
+protected:
+ BindableWithDefault() { }
+
+public:
+ static const T *current()
+ {
+ if(!Bindable<T>::cur_obj)
+ Bindable<T>::cur_obj = &default_object();
+ return Bindable<T>::cur_obj;
+ }
+
+ static void unbind()
+ {
+ default_object().bind();
+ }
+
+ static const T &default_object()
+ {
+ static T obj;
+ return obj;
+ }
+};
+
+
/**
RAII class for binding things. Binds the thing upon construction and unbinds
it upon destruction. If a null pointer is given, unbinds upon construction and
case Graphics::LUMINANCE: return LUMINANCE;
case Graphics::LUMINANCE_ALPHA: return LUMINANCE_ALPHA;
case Graphics::RGB: return RGB;
+ case Graphics::RGBX:
case Graphics::RGBA: return RGBA;
case Graphics::BGR: return BGR;
+ case Graphics::BGRX:
case Graphics::BGRA: return BGRA;
default: throw invalid_argument("pixelformat_from_graphics");
}
}
+PixelFormat storage_pixelformat_from_graphics(Graphics::PixelFormat pf)
+{
+ switch(pf)
+ {
+ case Graphics::RGBX:
+ case Graphics::BGR:
+ case Graphics::BGRX: return RGB;
+ case Graphics::BGRA: return RGBA;
+ default: return pixelformat_from_graphics(pf);
+ }
+}
+
PixelFormat get_base_pixelformat(PixelFormat pf)
{
switch(pf)
}
}
+unsigned get_component_count(PixelFormat pf)
+{
+ switch(get_base_pixelformat(pf))
+ {
+ case COLOR_INDEX:
+ case STENCIL_INDEX:
+ case DEPTH_COMPONENT:
+ case RED:
+ case GREEN:
+ case BLUE:
+ case LUMINANCE:
+ return 1;
+ case LUMINANCE_ALPHA:
+ return 2;
+ case RGB:
+ case BGR:
+ return 3;
+ case RGBA:
+ case BGRA:
+ return 4;
+ default:
+ throw invalid_argument("get_pixelformat_component_count");
+ }
+}
+
void require_pixelformat(PixelFormat pf)
{
switch(pf)
void operator>>(const LexicalConverter &, PixelFormat &);
PixelFormat pixelformat_from_graphics(Graphics::PixelFormat);
+PixelFormat storage_pixelformat_from_graphics(Graphics::PixelFormat);
PixelFormat get_base_pixelformat(PixelFormat);
+unsigned get_component_count(PixelFormat);
void require_pixelformat(PixelFormat);
--- /dev/null
+#include <algorithm>
+#include "gl.h"
+#include "pixelformat.h"
+#include "pixelstore.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+PixelStore::PixelStore():
+ row_length(0),
+ image_height(0),
+ skip_pixels(0),
+ skip_rows(0),
+ skip_images(0),
+ alignment(4)
+{ }
+
+PixelStore PixelStore::from_image(const Graphics::Image &img)
+{
+ PixelStore pstore;
+ unsigned stride = img.get_stride();
+ unsigned ncomp = get_component_count(pixelformat_from_graphics(img.get_format()));
+ pstore.set_canvas_size(img.get_stride()/ncomp, 0);
+ pstore.set_alignment(min(stride&~(stride-1), 8U));
+ return pstore;
+}
+
+void PixelStore::set_canvas_size(unsigned w, unsigned h)
+{
+ row_length = w;
+ image_height = h;
+}
+
+void PixelStore::set_origin(unsigned x, unsigned y, unsigned z)
+{
+ skip_pixels = x;
+ skip_rows = y;
+ skip_images = z;
+}
+
+void PixelStore::set_alignment(unsigned a)
+{
+ alignment = a;
+}
+
+void PixelStore::bind() const
+{
+ if(set_current(this))
+ {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, image_height);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
+ glPixelStorei(GL_UNPACK_SKIP_IMAGES, skip_images);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+ }
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_PIXELSTORE_H_
+#define MSP_GL_PIXELSTORE_H_
+
+#include <msp/graphics/image.h>
+#include "bindable.h"
+
+namespace Msp {
+namespace GL {
+
+class PixelStore: public BindableWithDefault<PixelStore>
+{
+private:
+ unsigned row_length;
+ unsigned image_height;
+ unsigned skip_pixels;
+ unsigned skip_rows;
+ unsigned skip_images;
+ unsigned alignment;
+
+public:
+ PixelStore();
+
+ static PixelStore from_image(const Graphics::Image &);
+
+ void set_canvas_size(unsigned, unsigned);
+ void set_origin(unsigned, unsigned, unsigned);
+ void set_alignment(unsigned);
+
+ void bind() const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
#include <msp/io/memory.h>
#include "bindable.h"
#include "error.h"
+#include "pixelstore.h"
#include "texture2d.h"
using namespace std;
unsigned h = img.get_height();
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
- storage(fmt, w, h);
+ storage(storage_pixelformat_from_graphics(img.get_format()), w, h);
else if(w!=width || h!=height)
throw incompatible_data("Texture2D::image");
+ PixelStore pstore = PixelStore::from_image(img);
+ Bind _bind_ps(pstore, true);
+
image(0, fmt, UNSIGNED_BYTE, img.get_data());
}
#include <msp/graphics/image.h>
#include "bindable.h"
#include "error.h"
+#include "pixelstore.h"
#include "texture3d.h"
using namespace std;
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
- storage(fmt, w, h, d);
+ storage(storage_pixelformat_from_graphics(img.get_format()), w, h, d);
else if(w!=width || h!=height || d!=depth)
throw incompatible_data("Texture3D::load_image");
- image(0, fmt, UNSIGNED_INT, img.get_data());
+ PixelStore pstore = PixelStore::from_image(img);
+ Bind _bind_ps(pstore, true);
+
+ image(0, fmt, UNSIGNED_BYTE, img.get_data());
}
void Texture3D::get_level_size(unsigned level, unsigned &w, unsigned &h, unsigned &d)
#include <msp/strings/format.h>
#include "bindable.h"
#include "error.h"
+#include "pixelstore.h"
#include "texturecube.h"
using namespace std;
if(size==0)
{
if(w==h)
- storage(fmt, w);
+ storage(storage_pixelformat_from_graphics(img.get_format()), w);
else
throw incompatible_data("TextureCube::image");
}
else if(w!=size || h!=size)
throw incompatible_data("TextureCube::image");
+ PixelStore pstore = PixelStore::from_image(img);
+ Bind _bind_ps(pstore, true);
+
image(face, 0, fmt, UNSIGNED_BYTE, img.get_data());
}