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