MyGUI  3.2.1
MyGUI_RotatingSkin.cpp
Go to the documentation of this file.
00001 /*
00002  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
00003  * Distributed under the MIT License
00004  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
00005  */
00006 
00007 #include "MyGUI_Precompiled.h"
00008 #include "MyGUI_RotatingSkin.h"
00009 #include "MyGUI_RenderItem.h"
00010 #include "MyGUI_CommonStateInfo.h"
00011 #include "MyGUI_RenderManager.h"
00012 #include "MyGUI_GeometryUtility.h"
00013 
00014 namespace MyGUI
00015 {
00016 
00017     RotatingSkin::RotatingSkin() :
00018         mGeometryOutdated(false),
00019         mAngle(0.0f),
00020         mEmptyView(false),
00021         mCurrentColour(0xFFFFFFFF),
00022         mNode(nullptr),
00023         mRenderItem(nullptr)
00024     {
00025         mVertexFormat = RenderManager::getInstance().getVertexFormat();
00026     }
00027 
00028     RotatingSkin::~RotatingSkin()
00029     {
00030     }
00031 
00032     void RotatingSkin::setAngle(float _angle)
00033     {
00034         mAngle = _angle;
00035         mGeometryOutdated = true;
00036 
00037         if (nullptr != mNode)
00038             mNode->outOfDate(mRenderItem);
00039     }
00040 
00041     void RotatingSkin::setCenter(const IntPoint& _center)
00042     {
00043         mCenterPos = _center;
00044         mGeometryOutdated = true;
00045 
00046         if (nullptr != mNode)
00047             mNode->outOfDate(mRenderItem);
00048     }
00049 
00050     IntPoint RotatingSkin::getCenter(bool _local) const
00051     {
00052         return mCenterPos + (_local ? IntPoint() : mCroppedParent->getAbsolutePosition());
00053     }
00054 
00055     void RotatingSkin::setVisible(bool _visible)
00056     {
00057         if (mVisible == _visible)
00058             return;
00059 
00060         mVisible = _visible;
00061         mGeometryOutdated = true;
00062 
00063         if (nullptr != mNode)
00064             mNode->outOfDate(mRenderItem);
00065     }
00066 
00067     void RotatingSkin::setAlpha(float _alpha)
00068     {
00069         uint32 alpha = ((uint8)(_alpha * 255) << 24);
00070         mCurrentColour = (mCurrentColour & 0x00FFFFFF) | (alpha & 0xFF000000);
00071 
00072         if (nullptr != mNode)
00073             mNode->outOfDate(mRenderItem);
00074     }
00075 
00076     void RotatingSkin::_correctView()
00077     {
00078         mGeometryOutdated = true;
00079 
00080         if (nullptr != mNode)
00081             mNode->outOfDate(mRenderItem);
00082     }
00083 
00084     void RotatingSkin::_setAlign(const IntSize& _oldsize)
00085     {
00086         // необходимо разобраться
00087         bool need_update = true;
00088 
00089         // первоначальное выравнивание
00090         if (mAlign.isHStretch())
00091         {
00092             // растягиваем
00093             mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
00094             need_update = true;
00095             mIsMargin = true; // при изменении размеров все пересчитывать
00096         }
00097         else if (mAlign.isRight())
00098         {
00099             // двигаем по правому краю
00100             mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
00101             need_update = true;
00102         }
00103         else if (mAlign.isHCenter())
00104         {
00105             // выравнивание по горизонтали без растяжения
00106             mCoord.left = (mCroppedParent->getWidth() - mCoord.width) / 2;
00107             need_update = true;
00108         }
00109 
00110         if (mAlign.isVStretch())
00111         {
00112             // растягиваем
00113             mCoord.height = mCoord.height + (mCroppedParent->getHeight() - _oldsize.height);
00114             need_update = true;
00115             mIsMargin = true; // при изменении размеров все пересчитывать
00116         }
00117         else if (mAlign.isBottom())
00118         {
00119             // двигаем по нижнему краю
00120             mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
00121             need_update = true;
00122         }
00123         else if (mAlign.isVCenter())
00124         {
00125             // выравнивание по вертикали без растяжения
00126             mCoord.top = (mCroppedParent->getHeight() - mCoord.height) / 2;
00127             need_update = true;
00128         }
00129 
00130         if (need_update)
00131         {
00132             mCurrentCoord = mCoord;
00133             _updateView();
00134         }
00135     }
00136 
00137     void RotatingSkin::_updateView()
00138     {
00139         mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
00140 
00141         mGeometryOutdated = true;
00142 
00143         if (nullptr != mNode)
00144             mNode->outOfDate(mRenderItem);
00145     }
00146 
00147     void RotatingSkin::createDrawItem(ITexture* _texture, ILayerNode* _node)
00148     {
00149         MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
00150 
00151         mNode = _node;
00152         mRenderItem = mNode->addToRenderItem(_texture, true, false);
00153         mRenderItem->addDrawItem(this, (GEOMETRY_VERTICIES_TOTAL_COUNT - 2) * 3);
00154     }
00155 
00156     void RotatingSkin::destroyDrawItem()
00157     {
00158         MYGUI_ASSERT(mRenderItem, "mRenderItem must be not nullptr");
00159 
00160         mNode = nullptr;
00161         mRenderItem->removeDrawItem(this);
00162         mRenderItem = nullptr;
00163     }
00164 
00165     void RotatingSkin::doRender()
00166     {
00167         if (!mVisible || mEmptyView)
00168             return;
00169 
00170         Vertex* verticies = mRenderItem->getCurrentVertexBuffer();
00171 
00172         float vertex_z = mNode->getNodeDepth();
00173 
00174         if (mGeometryOutdated)
00175         {
00176             _rebuildGeometry();
00177             mGeometryOutdated = false;
00178         }
00179 
00180         for (int i = 1; i < GEOMETRY_VERTICIES_TOTAL_COUNT - 1; ++i)
00181         {
00182             verticies[3 * i - 3].set(mResultVerticiesPos[0].left, mResultVerticiesPos[0].top, vertex_z, mResultVerticiesUV[0].left, mResultVerticiesUV[0].top, mCurrentColour);
00183             verticies[3 * i - 2].set(mResultVerticiesPos[i].left, mResultVerticiesPos[i].top, vertex_z, mResultVerticiesUV[i].left, mResultVerticiesUV[i].top, mCurrentColour);
00184             verticies[3 * i - 1].set(mResultVerticiesPos[i + 1].left, mResultVerticiesPos[i + 1].top, vertex_z, mResultVerticiesUV[i + 1].left, mResultVerticiesUV[i + 1].top, mCurrentColour);
00185         }
00186 
00187         mRenderItem->setLastVertexCount((GEOMETRY_VERTICIES_TOTAL_COUNT - 2) * 3);
00188     }
00189 
00190     void RotatingSkin::_setColour(const Colour& _value)
00191     {
00192         uint32 colour = texture_utility::toColourARGB(_value);
00193         texture_utility::convertColour(colour, mVertexFormat);
00194         mCurrentColour = (colour & 0x00FFFFFF) | (mCurrentColour & 0xFF000000);
00195 
00196         if (nullptr != mNode)
00197             mNode->outOfDate(mRenderItem);
00198     }
00199 
00200     void RotatingSkin::setStateData(IStateInfo* _data)
00201     {
00202         RotatingSkinStateInfo* data = _data->castType<RotatingSkinStateInfo>();
00203 
00204         setAngle(data->getAngle());
00205         setCenter(data->getCenter());
00206 
00207         _setUVSet(data->getRect());
00208     }
00209 
00210     void RotatingSkin::_setUVSet(const FloatRect& _rect)
00211     {
00212         mCurrentTexture = _rect;
00213 
00214         mGeometryOutdated = true;
00215 
00216         if (nullptr != mNode)
00217             mNode->outOfDate(mRenderItem);
00218     }
00219 
00220     inline float len(float x, float y)
00221     {
00222         return sqrt(x * x + y * y);
00223     }
00224 
00225     void RotatingSkin::_rebuildGeometry()
00226     {
00227         /*
00228             0 1
00229             3 2
00230         */
00231 #ifndef M_PI
00232         const float M_PI = 3.141593f;
00233 #endif
00234 
00235         float width_base = (float)mCurrentCoord.width;
00236         float height_base = (float)mCurrentCoord.height;
00237 
00238         // calculate original unrotated angles of uncropped rectangle verticies: between axis and line from center of rotation to vertex)
00239         float baseAngles[RECT_VERTICIES_COUNT];
00240         baseAngles[0] = atan2((float)mCenterPos.left, (float)mCenterPos.top) + M_PI / 2;
00241         baseAngles[1] = atan2(- width_base + (float)mCenterPos.left, (float)mCenterPos.top) + M_PI / 2;
00242         baseAngles[2] = atan2(- width_base + (float)mCenterPos.left, - height_base + (float)mCenterPos.top) + M_PI / 2;
00243         baseAngles[3] = atan2((float)mCenterPos.left, - height_base + (float)mCenterPos.top) + M_PI / 2;
00244 
00245         // calculate original unrotated distances of uncropped rectangle verticies: between center of rotation and vertex)
00246         float baseDistances[RECT_VERTICIES_COUNT];
00247         baseDistances[0] = len((float)mCenterPos.left, (float)mCenterPos.top);
00248         baseDistances[1] = len(- width_base + (float)mCenterPos.left, (float)mCenterPos.top);
00249         baseDistances[2] = len(- width_base + (float)mCenterPos.left, - height_base + (float)mCenterPos.top);
00250         baseDistances[3] = len((float)mCenterPos.left, - height_base + (float)mCenterPos.top);
00251 
00252 
00253         // calculate rotated positions of uncropped rectangle verticies (relative to parent)
00254         FloatPoint baseVerticiesPos[RECT_VERTICIES_COUNT];
00255 
00256         int offsetX = /*mCurrentCoord.left +*/ mCenterPos.left;
00257         int offsetY = /*mCurrentCoord.top +*/ mCenterPos.top;
00258 
00259         for (int i = 0; i < RECT_VERTICIES_COUNT; ++i)
00260         {
00261             baseVerticiesPos[i].left = offsetX + cos(-mAngle + baseAngles[i]) * baseDistances[i];
00262             baseVerticiesPos[i].top = offsetY - sin(-mAngle + baseAngles[i]) * baseDistances[i];
00263         }
00264 
00265         // base texture coordinates
00266         FloatPoint baseVerticiesUV[RECT_VERTICIES_COUNT] =
00267         {
00268             FloatPoint(mCurrentTexture.left, mCurrentTexture.top),
00269             FloatPoint(mCurrentTexture.right, mCurrentTexture.top),
00270             FloatPoint(mCurrentTexture.right, mCurrentTexture.bottom),
00271             FloatPoint(mCurrentTexture.left, mCurrentTexture.bottom)
00272         };
00273 
00274         // now we have rotated uncropped rectangle verticies coordinates
00275 
00276         // --------- here the cropping starts ---------
00277 
00278         // now we are going to calculate verticies of resulting figure
00279 
00280         // no parent - no cropping
00281         size_t size = RECT_VERTICIES_COUNT;
00282         if (nullptr == mCroppedParent->getCroppedParent())
00283         {
00284             for (int i = 0; i < RECT_VERTICIES_COUNT; ++i)
00285             {
00286                 mResultVerticiesPos[i] = baseVerticiesPos[i];
00287                 mResultVerticiesUV[i] = baseVerticiesUV[i];
00288             }
00289         }
00290         else
00291         {
00292             ICroppedRectangle* parent = mCroppedParent->getCroppedParent();
00293 
00294             VectorFloatPoint resultVerticiesPos = geometry_utility::cropPolygon(
00295                 baseVerticiesPos,
00296                 RECT_VERTICIES_COUNT,
00297                 IntCoord(
00298                     parent->_getMarginLeft() - mCroppedParent->getLeft(),
00299                     parent->_getMarginTop() - mCroppedParent->getTop(),
00300                     parent->_getViewWidth(),
00301                     parent->_getViewHeight()));
00302 
00303             for (size_t i = 0; i < resultVerticiesPos.size(); ++i)
00304             {
00305                 mResultVerticiesPos[i] = resultVerticiesPos[i];
00306             }
00307 
00308             size = resultVerticiesPos.size();
00309 
00310             // calculate texture coordinates
00311             FloatPoint v0 = baseVerticiesUV[3] - baseVerticiesUV[0];
00312             FloatPoint v1 = baseVerticiesUV[1] - baseVerticiesUV[0];
00313             for (size_t i = 0; i < GEOMETRY_VERTICIES_TOTAL_COUNT; ++i)
00314             {
00315                 if (i < size)
00316                 {
00317                     FloatPoint point = geometry_utility::getPositionInsideRect(mResultVerticiesPos[i], baseVerticiesPos[0], baseVerticiesPos[1], baseVerticiesPos[3]);
00318                     mResultVerticiesUV[i] = geometry_utility::getUVFromPositionInsideRect(point, v0, v1, baseVerticiesUV[0]);
00319                 }
00320                 else
00321                 {
00322                     // all unused verticies is equal to last used
00323                     mResultVerticiesUV[i] = mResultVerticiesUV[size - 1];
00324                 }
00325             }
00326         }
00327 
00328 
00329         // now calculate widget base offset and then resulting position in screen coordinates
00330         const RenderTargetInfo& info = mRenderItem->getRenderTarget()->getInfo();
00331         float vertex_left_base = ((info.pixScaleX * (float)(mCroppedParent->getAbsoluteLeft()) + info.hOffset) * 2) - 1;
00332         float vertex_top_base = -(((info.pixScaleY * (float)(mCroppedParent->getAbsoluteTop()) + info.vOffset) * 2) - 1);
00333 
00334         for (size_t i = 0; i < GEOMETRY_VERTICIES_TOTAL_COUNT; ++i)
00335         {
00336             if (i < size)
00337             {
00338                 mResultVerticiesPos[i].left = vertex_left_base + mResultVerticiesPos[i].left * info.pixScaleX * 2;
00339                 mResultVerticiesPos[i].top = vertex_top_base + mResultVerticiesPos[i].top * info.pixScaleY * -2;
00340             }
00341             else
00342             {
00343                 // all unused verticies is equal to last used
00344                 mResultVerticiesPos[i] = mResultVerticiesPos[size - 1];
00345             }
00346         }
00347     }
00348 
00349     float RotatingSkin::getAngle() const
00350     {
00351         return mAngle;
00352     }
00353 
00354 } // namespace MyGUI