From 44f886c961bd32e9a5c75e84a7fdf0945a73a468 Mon Sep 17 00:00:00 2001 From: jrassa Date: Thu, 23 Feb 2017 20:42:35 -0500 Subject: [PATCH] implement maxSize for videos implement maxSize for videos --- es-core/src/ThemeData.cpp | 1 + es-core/src/components/VideoComponent.cpp | 98 ++++++++++++++++++++--- es-core/src/components/VideoComponent.h | 19 +++++ 3 files changed, 108 insertions(+), 10 deletions(-) diff --git a/es-core/src/ThemeData.cpp b/es-core/src/ThemeData.cpp index 871e7dead..cd35d06a6 100644 --- a/es-core/src/ThemeData.cpp +++ b/es-core/src/ThemeData.cpp @@ -86,6 +86,7 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign:: ("video", makeMap(boost::assign::map_list_of ("pos", NORMALIZED_PAIR) ("size", NORMALIZED_PAIR) + ("maxSize", NORMALIZED_PAIR) ("origin", NORMALIZED_PAIR) ("default", PATH) ("delay", FLOAT) diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 6f41ffd78..268a45316 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -39,7 +39,10 @@ VideoComponent::VideoComponent(Window* window) : mVideoWidth(0), mStartDelayed(false), mIsPlaying(false), - mShowing(false) + mShowing(false), + mTargetIsMax(false), + mOrigin(0, 0), + mTargetSize(0, 0) { memset(&mContext, 0, sizeof(mContext)); @@ -69,12 +72,89 @@ void VideoComponent::setOrigin(float originX, float originY) mStaticImage.setOrigin(originX, originY); } +void VideoComponent::setResize(float width, float height) +{ + mTargetSize << width, height; + mTargetIsMax = false; + mStaticImage.setResize(width, height); + resize(); +} + +void VideoComponent::setMaxSize(float width, float height) +{ + mTargetSize << width, height; + mTargetIsMax = true; + mStaticImage.setMaxSize(width, height); + resize(); +} + Eigen::Vector2f VideoComponent::getCenter() const { return Eigen::Vector2f(mPosition.x() - (getSize().x() * mOrigin.x()) + getSize().x() / 2, mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2); } +void VideoComponent::resize() +{ + if(!mTexture) + return; + + const Eigen::Vector2f textureSize(mVideoWidth, mVideoHeight); + + if(textureSize.isZero()) + return; + + // SVG rasterization is determined by height (see SVGResource.cpp), and rasterization is done in terms of pixels + // if rounding is off enough in the rasterization step (for images with extreme aspect ratios), it can cause cutoff when the aspect ratio breaks + // so, we always make sure the resultant height is an integer to make sure cutoff doesn't happen, and scale width from that + // (you'll see this scattered throughout the function) + // this is probably not the best way, so if you're familiar with this problem and have a better solution, please make a pull request! + + if(mTargetIsMax) + { + + mSize = textureSize; + + Eigen::Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); + + if(resizeScale.x() < resizeScale.y()) + { + mSize[0] *= resizeScale.x(); + mSize[1] *= resizeScale.x(); + }else{ + mSize[0] *= resizeScale.y(); + mSize[1] *= resizeScale.y(); + } + + // for SVG rasterization, always calculate width from rounded height (see comment above) + mSize[1] = round(mSize[1]); + mSize[0] = (mSize[1] / textureSize.y()) * textureSize.x(); + + }else{ + // if both components are set, we just stretch + // if no components are set, we don't resize at all + mSize = mTargetSize.isZero() ? textureSize : mTargetSize; + + // if only one component is set, we resize in a way that maintains aspect ratio + // for SVG rasterization, we always calculate width from rounded height (see comment above) + if(!mTargetSize.x() && mTargetSize.y()) + { + mSize[1] = round(mTargetSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); + }else if(mTargetSize.x() && !mTargetSize.y()) + { + mSize[1] = round((mTargetSize.x() / textureSize.x()) * textureSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); + } + } + + // mSize.y() should already be rounded + mTexture->rasterizeAt((int)round(mSize.x()), (int)round(mSize.y())); + + onSizeChanged(); +} + + void VideoComponent::onSizeChanged() { // Update the embeded static image @@ -111,8 +191,6 @@ void VideoComponent::setImage(std::string path) return; mStaticImage.setImage(path); - // Make the image stretch to fill the video region - mStaticImage.setSize(getSize()); mFadeIn = 0.0f; mStaticImagePath = path; } @@ -243,11 +321,15 @@ void VideoComponent::applyTheme(const std::shared_ptr& theme, const s { Eigen::Vector2f denormalized = elem->get("pos").cwiseProduct(scale); setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0)); + mStaticImage.setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0)); } - if ((properties & ThemeFlags::SIZE) && elem->has("size")) + if(properties & ThemeFlags::SIZE) { - setSize(elem->get("size").cwiseProduct(scale)); + if(elem->has("size")) + setResize(elem->get("size").cwiseProduct(scale)); + else if(elem->has("maxSize")) + setMaxSize(elem->get("maxSize").cwiseProduct(scale)); } // position + size also implies origin @@ -265,11 +347,6 @@ void VideoComponent::applyTheme(const std::shared_ptr& theme, const s if (elem->has("showSnapshotDelay")) mConfig.showSnapshotDelay = elem->get("showSnapshotDelay"); - - // Update the embeded static image - mStaticImage.setPosition(getPosition()); - mStaticImage.setMaxSize(getSize()); - mStaticImage.setSize(getSize()); } std::vector VideoComponent::getHelpPrompts() @@ -287,6 +364,7 @@ void VideoComponent::setupContext() mContext.surface = SDL_CreateRGBSurface(SDL_SWSURFACE, (int)mVideoWidth, (int)mVideoHeight, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); mContext.mutex = SDL_CreateMutex(); mContext.valid = true; + resize(); } } diff --git a/es-core/src/components/VideoComponent.h b/es-core/src/components/VideoComponent.h index f8376cfe9..14179defa 100644 --- a/es-core/src/components/VideoComponent.h +++ b/es-core/src/components/VideoComponent.h @@ -55,6 +55,19 @@ public: void onSizeChanged() override; void setOpacity(unsigned char opacity) override; + // Resize the video to fit this size. If one axis is zero, scale that axis to maintain aspect ratio. + // If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing. + // Can be set before or after a video is loaded. + // setMaxSize() and setResize() are mutually exclusive. + void setResize(float width, float height); + inline void setResize(const Eigen::Vector2f& size) { setResize(size.x(), size.y()); } + + // Resize the video to be as large as possible but fit within a box of this size. + // Can be set before or after a video is loaded. + // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. + void setMaxSize(float width, float height); + inline void setMaxSize(const Eigen::Vector2f& size) { setMaxSize(size.x(), size.y()); } + void render(const Eigen::Affine3f& parentTrans) override; virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; @@ -67,6 +80,10 @@ public: virtual void update(int deltaTime); private: + // Calculates the correct mSize from our resizing information (set by setResize/setMaxSize). + // Used internally whenever the resizing parameters or texture change. + void resize(); + // Start the video Immediately void startVideo(); // Start the video after any configured delay @@ -94,6 +111,7 @@ private: unsigned mVideoWidth; unsigned mVideoHeight; Eigen::Vector2f mOrigin; + Eigen::Vector2f mTargetSize; std::shared_ptr mTexture; float mFadeIn; std::string mStaticImagePath; @@ -105,6 +123,7 @@ private: unsigned mStartTime; bool mIsPlaying; bool mShowing; + bool mTargetIsMax; Configuration mConfig; };