MyGUI
3.2.0
|
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