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