MyGUI 3.0.1
MyGUI_TileRect.cpp
Go to the documentation of this file.
00001 
00007 /*
00008     This file is part of MyGUI.
00009 
00010     MyGUI is free software: you can redistribute it and/or modify
00011     it under the terms of the GNU Lesser General Public License as published by
00012     the Free Software Foundation, either version 3 of the License, or
00013     (at your option) any later version.
00014 
00015     MyGUI is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU Lesser General Public License for more details.
00019 
00020     You should have received a copy of the GNU Lesser General Public License
00021     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 #include "MyGUI_Precompiled.h"
00024 #include "MyGUI_TileRect.h"
00025 #include "MyGUI_RenderItem.h"
00026 #include "MyGUI_SkinManager.h"
00027 #include "MyGUI_LanguageManager.h"
00028 #include "MyGUI_LayerNode.h"
00029 #include "MyGUI_CommonStateInfo.h"
00030 #include "MyGUI_RenderManager.h"
00031 #include "MyGUI_TextureUtility.h"
00032 
00033 namespace MyGUI
00034 {
00035 
00036     const size_t TILERECT_COUNT_VERTEX = 16 * VertexQuad::VertexCount;
00037 
00038     TileRect::TileRect() :
00039         mEmptyView(false),
00040         mCurrentColour(0xFFFFFFFF),
00041         mNode(nullptr),
00042         mRenderItem(nullptr),
00043         mCountVertex(TILERECT_COUNT_VERTEX),
00044         mRealTileWidth(0),
00045         mRealTileHeight(0),
00046         mTextureHeightOne(0),
00047         mTextureWidthOne(0),
00048         mTileH(true),
00049         mTileV(true)
00050     {
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) mNode->outOfDate(mRenderItem);
00071     }
00072 
00073     void TileRect::_correctView()
00074     {
00075         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00076     }
00077 
00078     void TileRect::_setAlign(const IntCoord& _oldcoord, bool _update)
00079     {
00080         _setAlign(_oldcoord.size(), _update);
00081     }
00082 
00083     void TileRect::_setAlign(const IntSize& _oldsize, bool _update)
00084     {
00085         // необходимо разобраться
00086         bool need_update = true;//_update;
00087 
00088         // первоначальное выравнивание
00089         if (mAlign.isHStretch())
00090         {
00091             // растягиваем
00092             mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
00093             need_update = true;
00094             mIsMargin = true; // при изменении размеров все пересчитывать
00095         }
00096         else if (mAlign.isRight())
00097         {
00098             // двигаем по правому краю
00099             mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
00100             need_update = true;
00101         }
00102         else if (mAlign.isHCenter())
00103         {
00104             // выравнивание по горизонтали без растяжения
00105             mCoord.left = (mCroppedParent->getWidth() - mCoord.width) / 2;
00106             need_update = true;
00107         }
00108 
00109         if (mAlign.isVStretch())
00110         {
00111             // растягиваем
00112             mCoord.height = mCoord.height + (mCroppedParent->getHeight() - _oldsize.height);
00113             need_update = true;
00114             mIsMargin = true; // при изменении размеров все пересчитывать
00115         }
00116         else if (mAlign.isBottom())
00117         {
00118             // двигаем по нижнему краю
00119             mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
00120             need_update = true;
00121         }
00122         else if (mAlign.isVCenter())
00123         {
00124             // выравнивание по вертикали без растяжения
00125             mCoord.top = (mCroppedParent->getHeight() - mCoord.height) / 2;
00126             need_update = true;
00127         }
00128 
00129         if (need_update)
00130         {
00131             mCurrentCoord = mCoord;
00132             if (!mTileH) mTileSize.width = mCoord.width;
00133             if (!mTileV) mTileSize.height = mCoord.height;
00134             _updateView();
00135         }
00136 
00137     }
00138 
00139     void TileRect::_updateView()
00140     {
00141         bool margin = _checkMargin();
00142 
00143         mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
00144 
00145         mCurrentCoord.left = mCoord.left + mMargin.left;
00146         mCurrentCoord.top = mCoord.top + mMargin.top;
00147         mCurrentCoord.width = _getViewWidth();
00148         mCurrentCoord.height = _getViewHeight();
00149 
00150         // подсчитываем необходимое колличество тайлов
00151         if (!mEmptyView)
00152         {
00153             size_t count = 0;
00154             if (!mTileSize.empty())
00155             {
00156                 size_t count_x = mCoord.width / mTileSize.width;
00157                 if ((mCoord.width % mTileSize.width) > 0) count_x ++;
00158                 size_t count_y = mCoord.height / mTileSize.height;
00159                 if ((mCoord.height % mTileSize.height) > 0) count_y ++;
00160                 count = count_y * count_x * VertexQuad::VertexCount;
00161             }
00162 
00163             // нужно больше вершин
00164             if (count > mCountVertex)
00165             {
00166                 mCountVertex = count + TILERECT_COUNT_VERTEX;
00167                 if (nullptr != mRenderItem) mRenderItem->reallockDrawItem(this, mCountVertex);
00168             }
00169         }
00170 
00171         // вьюпорт стал битым
00172         if (margin)
00173         {
00174             // проверка на полный выход за границу
00175             if (_checkOutside())
00176             {
00177                 // запоминаем текущее состояние
00178                 mIsMargin = margin;
00179 
00180                 // обновить перед выходом
00181                 if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00182                 return;
00183             }
00184         }
00185 
00186         // запоминаем текущее состояние
00187         mIsMargin = margin;
00188 
00189         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00190     }
00191 
00192     void TileRect::_setUVSet(const FloatRect& _rect)
00193     {
00194         mCurrentTexture = _rect;
00195         if (nullptr != mNode) mNode->outOfDate(mRenderItem);
00196     }
00197 
00198     void TileRect::doRender()
00199     {
00200         if (!mVisible || mEmptyView || mTileSize.empty()) return;
00201 
00202         VertexQuad* quad = (VertexQuad*)mRenderItem->getCurrentVertextBuffer();
00203 
00204         const RenderTargetInfo& info = mRenderItem->getRenderTarget()->getInfo();
00205 
00206         // размер одного тайла
00207         mRealTileWidth = info.pixScaleX * (float)(mTileSize.width) * 2;
00208         mRealTileHeight = info.pixScaleY * (float)(mTileSize.height) * 2;
00209 
00210         mTextureHeightOne = (mCurrentTexture.bottom - mCurrentTexture.top) / mRealTileHeight;
00211         mTextureWidthOne = (mCurrentTexture.right - mCurrentTexture.left) / mRealTileWidth;
00212 
00213         float vertex_z = info.maximumDepth;
00214 
00215         // абсолютный размер окна
00216         float window_left = ((info.pixScaleX * (float)(mCoord.left + mCroppedParent->getAbsoluteLeft() - info.leftOffset) + info.hOffset) * 2) - 1;
00217         float window_top = -(((info.pixScaleY * (float)(mCoord.top + mCroppedParent->getAbsoluteTop() - info.topOffset) + info.vOffset) * 2) - 1);
00218 
00219         // размер вьюпорта
00220         float real_left = ((info.pixScaleX * (float)(mCurrentCoord.left + mCroppedParent->getAbsoluteLeft() - info.leftOffset) + info.hOffset) * 2) - 1;
00221         float real_right = real_left + (info.pixScaleX * (float)mCurrentCoord.width * 2);
00222         float real_top = -(((info.pixScaleY * (float)(mCurrentCoord.top + mCroppedParent->getAbsoluteTop() - info.topOffset) + info.vOffset) * 2) - 1);
00223         float real_bottom = real_top - (info.pixScaleY * (float)mCurrentCoord.height * 2);
00224 
00225         size_t count = 0;
00226 
00227         float left = window_left;
00228         float right = window_left;
00229         float top = window_top;
00230         float bottom = window_top;
00231 
00232         for (int y=0; y<mCoord.height; y+=mTileSize.height)
00233         {
00234             top = bottom;
00235             bottom -= mRealTileHeight;
00236             right = window_left;
00237 
00238             float vertex_top = top;
00239             float vertex_bottom = bottom;
00240             bool texture_crop_height  = false;
00241 
00242             if (vertex_top > real_top)
00243             {
00244                 // проверка на полный выход
00245                 if (vertex_bottom > real_top)
00246                 {
00247                     continue;
00248                 }
00249                 // обрезаем
00250                 vertex_top = real_top;
00251                 texture_crop_height = true;
00252             }
00253             if (vertex_bottom < real_bottom)
00254             {
00255                 // вообще вниз ушли
00256                 if (vertex_top < real_bottom)
00257                 {
00258                     continue;
00259                 }
00260                 // обрезаем
00261                 vertex_bottom = real_bottom;
00262                 texture_crop_height = true;
00263             }
00264 
00265             for (int x=0; x<mCoord.width; x+=mTileSize.width)
00266             {
00267                 left = right;
00268                 right += mRealTileWidth;
00269 
00270                 float vertex_left = left;
00271                 float vertex_right = right;
00272                 bool texture_crop_width  = false;
00273 
00274 
00275                 if (vertex_left < real_left)
00276                 {
00277                     // проверка на полный выход
00278                     if (vertex_right < real_left)
00279                     {
00280                         continue;
00281                     }
00282                     // обрезаем
00283                     vertex_left = real_left;
00284                     texture_crop_width = true;
00285                 }
00286 
00287                 if (vertex_right > real_right)
00288                 {
00289                     // вообще строку до конца не нуна
00290                     if (vertex_left > real_right)
00291                     {
00292                         continue;
00293                     }
00294                     // обрезаем
00295                     vertex_right = real_right;
00296                     texture_crop_width = true;
00297                 }
00298 
00299                 // текущие текстурные координаты
00300                 float texture_left = mCurrentTexture.left;
00301                 float texture_right = mCurrentTexture.right;
00302                 float texture_top = mCurrentTexture.top;
00303                 float texture_bottom = mCurrentTexture.bottom;
00304 
00305                 // смещение текстуры по вертикили
00306                 if (texture_crop_height)
00307                 {
00308                     // прибавляем размер смещения в текстурных координатах
00309                     texture_top += (top - vertex_top) * mTextureHeightOne;
00310                     // отнимаем размер смещения в текстурных координатах
00311                     texture_bottom -= (vertex_bottom - bottom) * mTextureHeightOne;
00312                 }
00313 
00314                 // смещение текстуры по горизонтали
00315                 if (texture_crop_width)
00316                 {
00317                     // прибавляем размер смещения в текстурных координатах
00318                     texture_left += (vertex_left - left) * mTextureWidthOne;
00319                     // отнимаем размер смещения в текстурных координатах
00320                     texture_right -= (right - vertex_right) * mTextureWidthOne;
00321                 }
00322 
00323                 quad[count].set(
00324                     vertex_left,
00325                     vertex_top,
00326                     vertex_right,
00327                     vertex_bottom,
00328                     vertex_z,
00329                     texture_left,
00330                     texture_top,
00331                     texture_right,
00332                     texture_bottom,
00333                     mCurrentColour
00334                     );
00335 
00336                 count ++;
00337             }
00338         }
00339 
00340         mRenderItem->setLastVertexCount(VertexQuad::VertexCount * count);
00341     }
00342 
00343     void TileRect::createDrawItem(ITexture* _texture, ILayerNode * _node)
00344     {
00345         MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
00346 
00347         mNode = _node;
00348         mRenderItem = mNode->addToRenderItem(_texture, this);
00349         mRenderItem->addDrawItem(this, mCountVertex);
00350     }
00351 
00352     void TileRect::destroyDrawItem()
00353     {
00354         MYGUI_ASSERT(mRenderItem, "mRenderItem must be not nullptr");
00355 
00356         mNode = nullptr;
00357         mRenderItem->removeDrawItem(this);
00358         mRenderItem = nullptr;
00359     }
00360 
00361     void TileRect::setStateData(IStateInfo* _data)
00362     {
00363         TileRectStateInfo* data = _data->castType<TileRectStateInfo>();
00364 
00365         mTileSize = data->getTileSize();
00366         mTileH = data->getTileH();
00367         mTileV = data->getTileV();
00368         _setUVSet(data->getRect());
00369     }
00370 
00371     void TileRect::_setColour(const Colour& _value)
00372     {
00373         uint32 colour = texture_utility::toColourARGB(_value);
00374         texture_utility::convertColour(colour, RenderManager::getInstance().getVertexFormat());
00375         mCurrentColour = (colour & 0x00FFFFFF) | (mCurrentColour & 0xFF000000);
00376 
00377         if (nullptr != mNode)
00378             mNode->outOfDate(mRenderItem);
00379     }
00380 
00381 } // namespace MyGUI