From 055f553b1a75f44e72f3c2b5a1c98c1e1e8f3f30 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 11 Oct 2013 14:51:41 +0300 Subject: [PATCH] Deal with nontrivial image configurations --- source/bindable.h | 30 ++++++++++++++++++++ source/pixelformat.cpp | 39 ++++++++++++++++++++++++++ source/pixelformat.h | 2 ++ source/pixelstore.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++ source/pixelstore.h | 35 ++++++++++++++++++++++++ source/texture2d.cpp | 6 +++- source/texture3d.cpp | 8 ++++-- source/texturecube.cpp | 6 +++- 8 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 source/pixelstore.cpp create mode 100644 source/pixelstore.h diff --git a/source/bindable.h b/source/bindable.h index 76c2fb52..bde5e85a 100644 --- a/source/bindable.h +++ b/source/bindable.h @@ -33,6 +33,36 @@ template const T *Bindable::cur_obj; +/** +A helper class for Bindables that revert to a default object on unbind. +*/ +template +class BindableWithDefault: protected Bindable +{ +protected: + BindableWithDefault() { } + +public: + static const T *current() + { + if(!Bindable::cur_obj) + Bindable::cur_obj = &default_object(); + return Bindable::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 diff --git a/source/pixelformat.cpp b/source/pixelformat.cpp index 836012f9..26600b33 100644 --- a/source/pixelformat.cpp +++ b/source/pixelformat.cpp @@ -48,13 +48,27 @@ PixelFormat pixelformat_from_graphics(Graphics::PixelFormat pf) 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) @@ -75,6 +89,31 @@ PixelFormat get_base_pixelformat(PixelFormat 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) diff --git a/source/pixelformat.h b/source/pixelformat.h index 4dabcbb5..c232da1e 100644 --- a/source/pixelformat.h +++ b/source/pixelformat.h @@ -42,8 +42,10 @@ enum PixelFormat 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); diff --git a/source/pixelstore.cpp b/source/pixelstore.cpp new file mode 100644 index 00000000..c32cf609 --- /dev/null +++ b/source/pixelstore.cpp @@ -0,0 +1,62 @@ +#include +#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 diff --git a/source/pixelstore.h b/source/pixelstore.h new file mode 100644 index 00000000..0c430300 --- /dev/null +++ b/source/pixelstore.h @@ -0,0 +1,35 @@ +#ifndef MSP_GL_PIXELSTORE_H_ +#define MSP_GL_PIXELSTORE_H_ + +#include +#include "bindable.h" + +namespace Msp { +namespace GL { + +class PixelStore: public BindableWithDefault +{ +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 diff --git a/source/texture2d.cpp b/source/texture2d.cpp index 0e9b40c6..7a9701f5 100644 --- a/source/texture2d.cpp +++ b/source/texture2d.cpp @@ -1,6 +1,7 @@ #include #include "bindable.h" #include "error.h" +#include "pixelstore.h" #include "texture2d.h" using namespace std; @@ -81,10 +82,13 @@ void Texture2D::image(const Graphics::Image &img) 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()); } diff --git a/source/texture3d.cpp b/source/texture3d.cpp index 73c4b817..3d322d4b 100644 --- a/source/texture3d.cpp +++ b/source/texture3d.cpp @@ -3,6 +3,7 @@ #include #include "bindable.h" #include "error.h" +#include "pixelstore.h" #include "texture3d.h" using namespace std; @@ -110,11 +111,14 @@ void Texture3D::load_image(const string &fn, int dp) 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) diff --git a/source/texturecube.cpp b/source/texturecube.cpp index eb7448c3..38d99367 100644 --- a/source/texturecube.cpp +++ b/source/texturecube.cpp @@ -3,6 +3,7 @@ #include #include "bindable.h" #include "error.h" +#include "pixelstore.h" #include "texturecube.h" using namespace std; @@ -78,13 +79,16 @@ void TextureCube::image(TextureCubeFace face, const Graphics::Image &img) 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()); } -- 2.43.0