text: /*
   * This source file is part of MyGUI. For the latest info, see http://mygui.info/
   * Distributed under the MIT License
   * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
   */
  
  #include "MyGUI_Precompiled.h"
  #include "MyGUI_SubSkin.h"
  #include "MyGUI_RenderItem.h"
  #include "MyGUI_SkinManager.h"
  #include "MyGUI_LanguageManager.h"
  #include "MyGUI_LayerNode.h"
  #include "MyGUI_CommonStateInfo.h"
  #include "MyGUI_RenderManager.h"
  #include "MyGUI_TextureUtility.h"
  
  namespace MyGUI
  {
  
  	SubSkin::SubSkin() :
  		ISubWidgetRect(),
  		mEmptyView(false),
  		mCurrentColour(0xFFFFFFFF),
  		mNode(nullptr),
  		mRenderItem(nullptr),
  		mSeparate(false)
  	{
  		mVertexFormat = RenderManager::getInstance().getVertexFormat();
  	}
  
  	void SubSkin::setVisible(bool _visible)
  	{
  		if (mVisible == _visible)
  			return;
  		mVisible = _visible;
  
  		if (nullptr != mNode)
  			mNode->outOfDate(mRenderItem);
  	}
  
  	void SubSkin::setAlpha(float _alpha)
  	{
  		uint32 alpha = ((uint8)(_alpha * 255) << 24);
  		mCurrentColour = (mCurrentColour & 0x00FFFFFF) | (alpha & 0xFF000000);
  
  		if (nullptr != mNode)
  			mNode->outOfDate(mRenderItem);
  	}
  
  	void SubSkin::_correctView()
  	{
  		if (nullptr != mNode)
  			mNode->outOfDate(mRenderItem);
  	}
  
  	void SubSkin::_setAlign(const IntSize& _oldsize)
  	{
  		// необходимо разобраться
  		bool need_update = true;//_update;
  
  		// первоначальное выравнивание
  		if (mAlign.isHStretch())
  		{
  			// растягиваем
  			mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
  			need_update = true;
  			mIsMargin = true; // при изменении размеров все пересчитывать
  		}
  		else if (mAlign.isRight())
  		{
  			// двигаем по правому краю
  			mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
  			need_update = true;
  		}
  		else if (mAlign.isHCenter())
  		{
  			// выравнивание по горизонтали без растяжения
  			mCoord.left = (mCroppedParent->getWidth() - mCoord.width) / 2;
  			need_update = true;
  		}
  
  		if (mAlign.isVStretch())
  		{
  			// растягиваем
  			mCoord.height = mCoord.height + (mCroppedParent->getHeight() - _oldsize.height);
  			need_update = true;
  			mIsMargin = true; // при изменении размеров все пересчитывать
  		}
  		else if (mAlign.isBottom())
  		{
  			// двигаем по нижнему краю
  			mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
  			need_update = true;
  		}
  		else if (mAlign.isVCenter())
  		{
  			// выравнивание по вертикали без растяжения
  			mCoord.top = (mCroppedParent->getHeight() - mCoord.height) / 2;
  			need_update = true;
  		}
  
  		if (need_update)
  		{
  			mCurrentCoord = mCoord;
  			_updateView();
  		}
  	}
  
  	void SubSkin::_updateView()
  	{
  		//mAbsolutePosition = mCroppedParent->getAbsolutePosition() + mCoord.point();
  		bool margin = _checkMargin();
  
  		mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
  
  		mCurrentCoord.left = mCoord.left + mMargin.left;
  		mCurrentCoord.top = mCoord.top + mMargin.top;
  
  		// вьюпорт стал битым
  		if (margin)
  		{
  			// проверка на полный выход за границу
  			if (_checkOutside())
  			{
  				// запоминаем текущее состояние
  				mIsMargin = margin;
  
  				// обновить перед выходом
  				if (nullptr != mNode)
  					mNode->outOfDate(mRenderItem);
  				return;
  			}
  		}
  
  		// мы обрезаны или были обрезаны
  		if (mIsMargin || margin)
  		{
  			mCurrentCoord.width = _getViewWidth();
  			mCurrentCoord.height = _getViewHeight();
  
  			if ((mCurrentCoord.width > 0) && (mCurrentCoord.height > 0))
  			{
  				// теперь смещаем текстуру
  				float UV_lft = mMargin.left / (float)mCoord.width;
  				float UV_top = mMargin.top / (float)mCoord.height;
  				float UV_rgt = (mCoord.width - mMargin.right) / (float)mCoord.width;
  				float UV_btm = (mCoord.height - mMargin.bottom) / (float)mCoord.height;
  
  				float UV_sizeX = mRectTexture.right - mRectTexture.left;
  				float UV_sizeY = mRectTexture.bottom - mRectTexture.top;
  
  				float UV_lft_total = mRectTexture.left + UV_lft * UV_sizeX;
  				float UV_top_total = mRectTexture.top + UV_top * UV_sizeY;
  				float UV_rgt_total = mRectTexture.right - (1 - UV_rgt) * UV_sizeX;
  				float UV_btm_total = mRectTexture.bottom - (1 - UV_btm) * UV_sizeY;
  
  				mCurrentTexture.set(UV_lft_total, UV_top_total, UV_rgt_total, UV_btm_total);
  			}
  		}
  
  		if (mIsMargin && !margin)
  		{
  			// мы не обрезаны, но были, ставим базовые координаты
  			mCurrentTexture = mRectTexture;
  		}
  
  		// запоминаем текущее состояние
  		mIsMargin = margin;
  
  		if (nullptr != mNode)
  			mNode->outOfDate(mRenderItem);
  	}
  
  	void SubSkin::createDrawItem(ITexture* _texture, ILayerNode* _node)
  	{
  		MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
  
  		mNode = _node;
  		mRenderItem = mNode->addToRenderItem(_texture, true, mSeparate);
  		mRenderItem->addDrawItem(this, VertexQuad::VertexCount);
  	}
  
  	void SubSkin::destroyDrawItem()
  	{
  		MYGUI_ASSERT(mRenderItem, "mRenderItem must be not nullptr");
  
  		mNode = nullptr;
  		mRenderItem->removeDrawItem(this);
  		mRenderItem = nullptr;
  	}
  
  	void SubSkin::_setUVSet(const FloatRect& _rect)
  	{
  		if (mRectTexture == _rect)
  			return;
  		mRectTexture = _rect;
  
  		// если обрезаны, то просчитываем с учето обрезки
  		if (mIsMargin)
  		{
  			float UV_lft = mMargin.left / (float)mCoord.width;
  			float UV_top = mMargin.top / (float)mCoord.height;
  			float UV_rgt = (mCoord.width - mMargin.right) / (float)mCoord.width;
  			float UV_btm = (mCoord.height - mMargin.bottom) / (float)mCoord.height;
  
  			float UV_sizeX = mRectTexture.right - mRectTexture.left;
  			float UV_sizeY = mRectTexture.bottom - mRectTexture.top;
  
  			float UV_lft_total = mRectTexture.left + UV_lft * UV_sizeX;
  			float UV_top_total = mRectTexture.top + UV_top * UV_sizeY;
  			float UV_rgt_total = mRectTexture.right - (1 - UV_rgt) * UV_sizeX;
  			float UV_btm_total = mRectTexture.bottom - (1 - UV_btm) * UV_sizeY;
  
  			mCurrentTexture.set(UV_lft_total, UV_top_total, UV_rgt_total, UV_btm_total);
  		}
  		// мы не обрезаны, базовые координаты
  		else
  		{
  			mCurrentTexture = mRectTexture;
  		}
  
  		if (nullptr != mNode)
  			mNode->outOfDate(mRenderItem);
  	}
  
  	void SubSkin::doRender()
  	{
  		if (!mVisible || mEmptyView)
  			return;
  
  		VertexQuad* quad = reinterpret_cast<VertexQuad*>(mRenderItem->getCurrentVertexBuffer());
  
  		const RenderTargetInfo& info = mRenderItem->getRenderTarget()->getInfo();
  
  		float vertex_z = mNode->getNodeDepth();
  
  		float vertex_left = ((info.pixScaleX * (float)(mCurrentCoord.left + mCroppedParent->getAbsoluteLeft() - info.leftOffset) + info.hOffset) * 2) - 1;
  		float vertex_right = vertex_left + (info.pixScaleX * (float)mCurrentCoord.width * 2);
  		float vertex_top = -(((info.pixScaleY * (float)(mCurrentCoord.top + mCroppedParent->getAbsoluteTop() - info.topOffset) + info.vOffset) * 2) - 1);
  		float vertex_bottom = vertex_top - (info.pixScaleY * (float)mCurrentCoord.height * 2);
  
  		quad->set(
  			vertex_left,
  			vertex_top,
  			vertex_right,
  			vertex_bottom,
  			vertex_z,
  			mCurrentTexture.left,
  			mCurrentTexture.top,
  			mCurrentTexture.right,
  			mCurrentTexture.bottom,
  			mCurrentColour);
  
  		mRenderItem->setLastVertexCount(VertexQuad::VertexCount);
  	}
  
  	void SubSkin::_setColour(const Colour& _value)
  	{
  		uint32 colour = texture_utility::toColourARGB(_value);
  		texture_utility::convertColour(colour, mVertexFormat);
  		mCurrentColour = (colour & 0x00FFFFFF) | (mCurrentColour & 0xFF000000);
  
  		if (nullptr != mNode)
  			mNode->outOfDate(mRenderItem);
  	}
  
  	void SubSkin::setStateData(IStateInfo* _data)
  	{
  		_setUVSet(_data->castType<SubSkinStateInfo>()->getRect());
  	}
  
  } // namespace MyGUI
  