MyGUI  3.2.0
MyGUI_TileRect.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_TileRect.h"
00024 #include "MyGUI_RenderItem.h"
00025 #include "MyGUI_SkinManager.h"
00026 #include "MyGUI_LanguageManager.h"
00027 #include "MyGUI_LayerNode.h"
00028 #include "MyGUI_CommonStateInfo.h"
00029 #include "MyGUI_RenderManager.h"
00030 #include "MyGUI_TextureUtility.h"
00031 
00032 namespace MyGUI
00033 {
00034 
00035     const size_t TILERECT_COUNT_VERTEX = 16 * VertexQuad::VertexCount;
00036 
00037     TileRect::TileRect() :
00038         mEmptyView(false),
00039         mCurrentColour(0xFFFFFFFF),
00040         mNode(nullptr),
00041         mRenderItem(nullptr),
00042         mCountVertex(TILERECT_COUNT_VERTEX),
00043         mRealTileWidth(0),
00044         mRealTileHeight(0),
00045         mTextureHeightOne(0),
00046         mTextureWidthOne(0),
00047         mTileH(true),
00048         mTileV(true)
00049     {
00050         mVertexFormat = RenderManager::getInstance().getVertexFormat();
00051     }
00052 
00053     TileRect::~TileRect()
00054     {
00055     }
00056 
00057     void TileRect::setVisible(bool _visible)
00058     {
00059         if (mVisible == _visible) return;
00060         mVisible = _visible;
00061 
00062         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00063     }
00064 
00065     void TileRect::setAlpha(float _alpha)
00066     {
00067         uint32 alpha = ((uint8)(_alpha * 255) << 24);
00068         mCurrentColour = (mCurrentColour & 0x00FFFFFF) | (alpha & 0xFF000000);
00069 
00070         if (nullptr != mNode)
00071             mNode->outOfDate(mRenderItem);
00072     }
00073 
00074     void TileRect::_correctView()
00075     {
00076         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00077     }
00078 
00079     void TileRect::_setAlign(const IntSize& _oldsize)
00080     {
00081         // необходимо разобраться
00082         bool need_update = true;
00083 
00084         // первоначальное выравнивание
00085         if (mAlign.isHStretch())
00086         {
00087             // растягиваем
00088             mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
00089             need_update = true;
00090             mIsMargin = true; // при изменении размеров все пересчитывать
00091         }
00092         else if (mAlign.isRight())
00093         {
00094             // двигаем по правому краю
00095             mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
00096             need_update = true;
00097         }
00098         else if (mAlign.isHCenter())
00099         {
00100             // выравнивание по горизонтали без растяжения
00101             mCoord.left = (mCroppedParent->getWidth() - mCoord.width) / 2;
00102             need_update = true;
00103         }
00104 
00105         if (mAlign.isVStretch())
00106         {
00107             // растягиваем
00108             mCoord.height = mCoord.height + (mCroppedParent->getHeight() - _oldsize.height);
00109             need_update = true;
00110             mIsMargin = true; // при изменении размеров все пересчитывать
00111         }
00112         else if (mAlign.isBottom())
00113         {
00114             // двигаем по нижнему краю
00115             mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
00116             need_update = true;
00117         }
00118         else if (mAlign.isVCenter())
00119         {
00120             // выравнивание по вертикали без растяжения
00121             mCoord.top = (mCroppedParent->getHeight() - mCoord.height) / 2;
00122             need_update = true;
00123         }
00124 
00125         if (need_update)
00126         {
00127             mCurrentCoord = mCoord;
00128             if (!mTileH) mTileSize.width = mCoord.width;
00129             if (!mTileV) mTileSize.height = mCoord.height;
00130             _updateView();
00131         }
00132 
00133     }
00134 
00135     void TileRect::_updateView()
00136     {
00137         bool margin = _checkMargin();
00138 
00139         mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
00140 
00141         mCurrentCoord.left = mCoord.left + mMargin.left;
00142         mCurrentCoord.top = mCoord.top + mMargin.top;
00143         mCurrentCoord.width = _getViewWidth();
00144         mCurrentCoord.height = _getViewHeight();
00145 
00146         // подсчитываем необходимое колличество тайлов
00147         if (!mEmptyView)
00148         {
00149             size_t count = 0;
00150             if (!mTileSize.empty())
00151             {
00152                 size_t count_x = mCoord.width / mTileSize.width;
00153                 if ((mCoord.width % mTileSize.width) > 0) count_x ++;
00154                 size_t count_y = mCoord.height / mTileSize.height;
00155                 if ((mCoord.height % mTileSize.height) > 0) count_y ++;
00156                 count = count_y * count_x * VertexQuad::VertexCount;
00157             }
00158 
00159             // нужно больше вершин
00160             if (count > mCountVertex)
00161             {
00162                 mCountVertex = count + TILERECT_COUNT_VERTEX;
00163                 if (nullptr != mRenderItem) mRenderItem->reallockDrawItem(this, mCountVertex);
00164             }
00165         }
00166 
00167         // вьюпорт стал битым
00168         if (margin)
00169         {
00170             // проверка на полный выход за границу
00171             if (_checkOutside())
00172             {
00173                 // запоминаем текущее состояние
00174                 mIsMargin = margin;
00175 
00176                 // обновить перед выходом
00177                 if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00178                 return;
00179             }
00180         }
00181 
00182         // запоминаем текущее состояние
00183         mIsMargin = margin;
00184 
00185         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00186     }
00187 
00188     void TileRect::_setUVSet(const FloatRect& _rect)
00189     {
00190         mCurrentTexture = _rect;
00191         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00192     }
00193 
00194     void TileRect::doRender()
00195     {
00196         if (!mVisible || mEmptyView || mTileSize.empty()) return;
00197 
00198         VertexQuad* quad = (VertexQuad*)mRenderItem->getCurrentVertexBuffer();
00199 
00200         const RenderTargetInfo& info = mRenderItem->getRenderTarget()->getInfo();
00201 
00202         // размер одного тайла
00203         mRealTileWidth = info.pixScaleX * (float)(mTileSize.width) * 2;
00204         mRealTileHeight = info.pixScaleY * (float)(mTileSize.height) * 2;
00205 
00206         mTextureHeightOne = (mCurrentTexture.bottom - mCurrentTexture.top) / mRealTileHeight;
00207         mTextureWidthOne = (mCurrentTexture.right - mCurrentTexture.left) / mRealTileWidth;
00208 
00209         float vertex_z = info.maximumDepth;
00210 
00211         // абсолютный размер окна
00212         float window_left = ((info.pixScaleX * (float)(mCoord.left + mCroppedParent->getAbsoluteLeft() - info.leftOffset) + info.hOffset) * 2) - 1;
00213         float window_top = -(((info.pixScaleY * (float)(mCoord.top + mCroppedParent->getAbsoluteTop() - info.topOffset) + info.vOffset) * 2) - 1);
00214 
00215         // размер вьюпорта
00216         float real_left = ((info.pixScaleX * (float)(mCurrentCoord.left + mCroppedParent->getAbsoluteLeft() - info.leftOffset) + info.hOffset) * 2) - 1;
00217         float real_right = real_left + (info.pixScaleX * (float)mCurrentCoord.width * 2);
00218         float real_top = -(((info.pixScaleY * (float)(mCurrentCoord.top + mCroppedParent->getAbsoluteTop() - info.topOffset) + info.vOffset) * 2) - 1);
00219         float real_bottom = real_top - (info.pixScaleY * (float)mCurrentCoord.height * 2);
00220 
00221         size_t count = 0;
00222 
00223         float left = window_left;
00224         float right = window_left;
00225         float top = window_top;
00226         float bottom = window_top;
00227 
00228         for (int y = 0; y < mCoord.height; y += mTileSize.height)
00229         {
00230             top = bottom;
00231             bottom -= mRealTileHeight;
00232             right = window_left;
00233 
00234             float vertex_top = top;
00235             float vertex_bottom = bottom;
00236             bool texture_crop_height  = false;
00237 
00238             if (vertex_top > real_top)
00239             {
00240                 // проверка на полный выход
00241                 if (vertex_bottom > real_top)
00242                 {
00243                     continue;
00244                 }
00245                 // обрезаем
00246                 vertex_top = real_top;
00247                 texture_crop_height = true;
00248             }
00249             if (vertex_bottom < real_bottom)
00250             {
00251                 // вообще вниз ушли
00252                 if (vertex_top < real_bottom)
00253                 {
00254                     continue;
00255                 }
00256                 // обрезаем
00257                 vertex_bottom = real_bottom;
00258                 texture_crop_height = true;
00259             }
00260 
00261             for (int x = 0; x < mCoord.width; x += mTileSize.width)
00262             {
00263                 left = right;
00264                 right += mRealTileWidth;
00265 
00266                 float vertex_left = left;
00267                 float vertex_right = right;
00268                 bool texture_crop_width  = false;
00269 
00270 
00271                 if (vertex_left < real_left)
00272                 {
00273                     // проверка на полный выход
00274                     if (vertex_right < real_left)
00275                     {
00276                         continue;
00277                     }
00278                     // обрезаем
00279                     vertex_left = real_left;
00280                     texture_crop_width = true;
00281                 }
00282 
00283                 if (vertex_right > real_right)
00284                 {
00285                     // вообще строку до конца не нуна
00286                     if (vertex_left > real_right)
00287                     {
00288                         continue;
00289                     }
00290                     // обрезаем
00291                     vertex_right = real_right;
00292                     texture_crop_width = true;
00293                 }
00294 
00295                 // текущие текстурные координаты
00296                 float texture_left = mCurrentTexture.left;
00297                 float texture_right = mCurrentTexture.right;
00298                 float texture_top = mCurrentTexture.top;
00299                 float texture_bottom = mCurrentTexture.bottom;
00300 
00301                 // смещение текстуры по вертикили
00302                 if (texture_crop_height)
00303                 {
00304                     // прибавляем размер смещения в текстурных координатах
00305                     texture_top += (top - vertex_top) * mTextureHeightOne;
00306                     // отнимаем размер смещения в текстурных координатах
00307                     texture_bottom -= (vertex_bottom - bottom) * mTextureHeightOne;
00308                 }
00309 
00310                 // смещение текстуры по горизонтали
00311                 if (texture_crop_width)
00312                 {
00313                     // прибавляем размер смещения в текстурных координатах
00314                     texture_left += (vertex_left - left) * mTextureWidthOne;
00315                     // отнимаем размер смещения в текстурных координатах
00316                     texture_right -= (right - vertex_right) * mTextureWidthOne;
00317                 }
00318 
00319                 quad[count].set(
00320                     vertex_left,
00321                     vertex_top,
00322                     vertex_right,
00323                     vertex_bottom,
00324                     vertex_z,
00325                     texture_left,
00326                     texture_top,
00327                     texture_right,
00328                     texture_bottom,
00329                     mCurrentColour
00330                 );
00331 
00332                 count ++;
00333             }
00334         }
00335 
00336         mRenderItem->setLastVertexCount(VertexQuad::VertexCount * count);
00337     }
00338 
00339     void TileRect::createDrawItem(ITexture* _texture, ILayerNode* _node)
00340     {
00341         MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
00342 
00343         mNode = _node;
00344         mRenderItem = mNode->addToRenderItem(_texture, true, false);
00345         mRenderItem->addDrawItem(this, mCountVertex);
00346     }
00347 
00348     void TileRect::destroyDrawItem()
00349     {
00350         MYGUI_ASSERT(mRenderItem, "mRenderItem must be not nullptr");
00351 
00352         mNode = nullptr;
00353         mRenderItem->removeDrawItem(this);
00354         mRenderItem = nullptr;
00355     }
00356 
00357     void TileRect::setStateData(IStateInfo* _data)
00358     {
00359         TileRectStateInfo* data = _data->castType<TileRectStateInfo>();
00360 
00361         mTileSize = data->getTileSize();
00362         mTileH = data->getTileH();
00363         mTileV = data->getTileV();
00364         _setUVSet(data->getRect());
00365     }
00366 
00367     void TileRect::_setColour(const Colour& _value)
00368     {
00369         uint32 colour = texture_utility::toColourARGB(_value);
00370         texture_utility::convertColour(colour, mVertexFormat);
00371         mCurrentColour = (colour & 0x00FFFFFF) | (mCurrentColour & 0xFF000000);
00372 
00373         if (nullptr != mNode)
00374             mNode->outOfDate(mRenderItem);
00375     }
00376 
00377 } // namespace MyGUI