diff --git a/src/bluecadet/views/ImageView.cpp b/src/bluecadet/views/ImageView.cpp index 92e9990..1b08162 100644 --- a/src/bluecadet/views/ImageView.cpp +++ b/src/bluecadet/views/ImageView.cpp @@ -14,8 +14,12 @@ ImageView::ImageView() : BaseView(), mTexture(nullptr), mTextureScale(1.0f), mScaleMode(sDefaultScaleMode), -mTopDown(false) +mTopDown(false), +mHasCustomTexCoords(false), +mTexCoordsAreDirty(true) { + mDefaultTexCoords = { vec2(0.0f, 0.0f), vec2(1.0f, 0.0f), vec2(1.0f, 1.0f), vec2(0.0f, 1.0f) }; + mTexCoords = mDefaultTexCoords; } ImageView::~ImageView() { @@ -27,6 +31,18 @@ void ImageView::reset() { setScaleMode(sDefaultScaleMode); } +void ImageView::setTexCoords(std::vector coords ) { + mUserTexCoords = coords; + mHasCustomTexCoords = true; + mTexCoordsAreDirty = true; + invalidate(false, true); +} + +void ImageView::setTexture(ci::gl::TextureRef texture, std::vector coords, const bool resizeToTexture) { + setTexCoords(coords); + setTexture(texture, resizeToTexture); +} + void ImageView::setTexture(ci::gl::TextureRef texture, const bool resizeToTexture) { mTexture = texture; @@ -41,6 +57,7 @@ void ImageView::setTexture(ci::gl::TextureRef texture, const bool resizeToTextur } invalidate(false, true); + } void ImageView::validateContent() { @@ -70,19 +87,26 @@ void ImageView::validateContent() { break; } } -} -void ImageView::draw() { - if (!mTexture) return; - - BaseView::draw(); + //use the appropriate tex coords + if (!mHasCustomTexCoords) { + mTexCoords = mDefaultTexCoords; + } else { + mTexCoords = mUserTexCoords; + } + //flip the tex coords if we're not using top down + if (!mTopDown) { + swap(mTexCoords[0], mTexCoords[3]); + swap(mTexCoords[1], mTexCoords[2]); + } + + //setup static shader once for all instances static gl::GlslProgRef shader = nullptr; - static gl::BatchRef batch = nullptr; if (!shader) { - shader = gl::GlslProg::create(gl::GlslProg::Format() - .vertex(CI_GLSL(150, + shader = gl::GlslProg::create(gl::GlslProg::Format().vertex(CI_GLSL(150, + uniform mat4 ciModelViewProjection; uniform vec2 uSize; in vec4 ciPosition; @@ -97,17 +121,17 @@ void ImageView::draw() { vec4 pos = ciPosition * vec4(uSize, 0, 1); gl_Position = ciModelViewProjection * pos; } + )).fragment(CI_GLSL(150, + uniform sampler2D uTex0; uniform vec2 uTexScale; - uniform int uTopDown; in vec2 vTexCoord0; in vec4 vColor; out vec4 oColor; void main(void) { vec2 texCoord = vTexCoord0; - texCoord.y = uTopDown != 0 ? 1.0 - texCoord.y : texCoord.y; // flip y if necessary texCoord = (texCoord - vec2(0.5)) * uTexScale + vec2(0.5); // scale around center if (texCoord.x < 0 || texCoord.y < 0 || texCoord.x > 1.0 || texCoord.y > 1.0) { @@ -118,16 +142,37 @@ void ImageView::draw() { oColor.rgb /= oColor.a; oColor *= vColor; } + ))); + } + + // make the batch only if: it hasn't been made and the shader is ready, + //or if the tex coords need updating + if ( (!mBatch && shader) || mTexCoordsAreDirty ) { + + auto rect = geom::Rect().rect(Rectf(0, 0, 1.0f, 1.0f)) + .texCoords( mTexCoords[0], + mTexCoords[1], + mTexCoords[2], + mTexCoords[3] ); + mTexCoordsAreDirty = false; + + mBatch = gl::Batch::create(rect, shader); - batch = gl::Batch::create(geom::Rect().rect(Rectf(0, 0, 1.0f, 1.0f)), shader); } +} + +void ImageView::draw() { + + if (!mTexture || !mBatch) return; + + BaseView::draw(); + mTexture->bind(0); - shader->uniform("uTexScale", mTextureScale); - shader->uniform("uSize", mTextureSize); - shader->uniform("uTopDown", mTopDown ? 1 : 0); - batch->draw(); + mBatch->getGlslProg()->uniform("uTexScale", mTextureScale); + mBatch->getGlslProg()->uniform("uSize", mTextureSize); + mBatch->draw(); } } diff --git a/src/bluecadet/views/ImageView.h b/src/bluecadet/views/ImageView.h index 675ad12..21d61e5 100644 --- a/src/bluecadet/views/ImageView.h +++ b/src/bluecadet/views/ImageView.h @@ -34,15 +34,27 @@ class ImageView : public BaseView { void reset() override; inline ci::gl::TextureRef getTexture() const { return mTexture; } - inline void setTexture(const ci::gl::TextureRef value, const bool resizeToTexture = true); + inline void setTexture(const ci::gl::TextureRef value, const bool resizeToTexture = true); + + //overloaded setup for applying custom texcoords + void setTexture(const ci::gl::TextureRef value, const std::vector coords, const bool resizeToTexture = true); + + //for updating the texCoords after initialization + std::vector getTexCoords() { return mTexCoords; } + void setTexCoords( const std::vector coords ); + + //setting the default texture coordinates also causes + //the image to re-validate with the new texcoords + void setDefaultTexCoords(const std::vector coords) { mDefaultTexCoords = coords; setTexCoords(mDefaultTexCoords); } + std::vector getDefaultTexCoords() { return mDefaultTexCoords; } //! Defaults to getDefaultScaleMode() - inline ScaleMode getScaleMode() const { return mScaleMode; } - inline void setScaleMode(const ScaleMode scaleMode) { mScaleMode = scaleMode; invalidate(false, true); } + inline ScaleMode getScaleMode() const { return mScaleMode; } + inline void setScaleMode(const ScaleMode scaleMode) { mScaleMode = scaleMode; invalidate(false, true); } //! Defaults to STRETCH - static ScaleMode getDefaultScaleMode() { return sDefaultScaleMode; } - static void setDefaultScaleMode(const ScaleMode scaleMode) { sDefaultScaleMode = scaleMode; } + static ScaleMode getDefaultScaleMode() { return sDefaultScaleMode; } + static void setDefaultScaleMode(const ScaleMode scaleMode) { sDefaultScaleMode = scaleMode; } //! Defaults to false. Can be set independently of the texture's top-down setting in case you have less control over that. void setTopDown(const bool value) { mTopDown = value; } @@ -55,11 +67,20 @@ class ImageView : public BaseView { static ScaleMode sDefaultScaleMode; + ci::gl::BatchRef mBatch; ci::gl::TextureRef mTexture; ci::vec2 mTextureScale; ci::vec2 mTextureSize; ScaleMode mScaleMode; bool mTopDown; + + //normalized texture coordinates, clockwise starting at upper left + std::vector mDefaultTexCoords; + std::vector mTexCoords; + std::vector mUserTexCoords; + bool mHasCustomTexCoords; + bool mTexCoordsAreDirty; + }; }