1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 29 #include "OgrePanelOverlayElement.h" 30 #include "OgreTechnique.h" 31 #include "OgreStringConverter.h" 32 #include "OgreHardwareBufferManager.h" 33 #include "OgreRoot.h" 34 #include "OgreRenderSystem.h" 35 36 namespace Ogre { 37 //--------------------------------------------------------------------- 38 String PanelOverlayElement::msTypeName = "Panel"; 39 PanelOverlayElement::CmdTiling PanelOverlayElement::msCmdTiling; 40 PanelOverlayElement::CmdTransparent PanelOverlayElement::msCmdTransparent; 41 PanelOverlayElement::CmdUVCoords PanelOverlayElement::msCmdUVCoords; 42 //--------------------------------------------------------------------- 43 // vertex buffer bindings, set at compile time (we could look these up but no point) 44 #define POSITION_BINDING 0 45 #define TEXCOORD_BINDING 1 46 47 //--------------------------------------------------------------------- PanelOverlayElement(const String & name)48 PanelOverlayElement::PanelOverlayElement(const String& name) 49 : OverlayContainer(name) 50 , mTransparent(false) 51 // Defer creation of texcoord buffer until we know how big it needs to be 52 , mNumTexCoordsInBuffer(0) 53 , mU1(0.0) 54 , mV1(0.0) 55 , mU2(1.0) 56 , mV2(1.0) 57 58 { 59 // Init tiling 60 for (ushort i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS; ++i) 61 { 62 mTileX[i] = 1.0f; 63 mTileY[i] = 1.0f; 64 } 65 66 // No normals or colours 67 if (createParamDictionary("PanelOverlayElement")) 68 { 69 addBaseParameters(); 70 } 71 72 } 73 //--------------------------------------------------------------------- ~PanelOverlayElement()74 PanelOverlayElement::~PanelOverlayElement() 75 { 76 OGRE_DELETE mRenderOp.vertexData; 77 } 78 //--------------------------------------------------------------------- initialise(void)79 void PanelOverlayElement::initialise(void) 80 { 81 bool init = !mInitialised; 82 83 OverlayContainer::initialise(); 84 if (init) 85 { 86 // Setup render op in advance 87 mRenderOp.vertexData = OGRE_NEW VertexData(); 88 // Vertex declaration: 1 position, add texcoords later depending on #layers 89 // Create as separate buffers so we can lock & discard separately 90 VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration; 91 decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION); 92 93 // Basic vertex data 94 mRenderOp.vertexData->vertexStart = 0; 95 mRenderOp.vertexData->vertexCount = 4; 96 // No indexes & issue as a strip 97 mRenderOp.useIndexes = false; 98 mRenderOp.operationType = RenderOperation::OT_TRIANGLE_STRIP; 99 mRenderOp.useGlobalInstancingVertexBufferIsAvailable = false; 100 101 mInitialised = true; 102 103 _restoreManualHardwareResources(); 104 } 105 } 106 //--------------------------------------------------------------------- _restoreManualHardwareResources()107 void PanelOverlayElement::_restoreManualHardwareResources() 108 { 109 if(!mInitialised) 110 return; 111 112 VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration; 113 114 // Vertex buffer #1 115 HardwareVertexBufferSharedPtr vbuf = 116 HardwareBufferManager::getSingleton().createVertexBuffer( 117 decl->getVertexSize(POSITION_BINDING), mRenderOp.vertexData->vertexCount, 118 HardwareBuffer::HBU_STATIC_WRITE_ONLY// mostly static except during resizing 119 ); 120 // Bind buffer 121 mRenderOp.vertexData->vertexBufferBinding->setBinding(POSITION_BINDING, vbuf); 122 123 // Buffers are restored, but with trash within 124 mGeomPositionsOutOfDate = true; 125 mGeomUVsOutOfDate = true; 126 } 127 //--------------------------------------------------------------------- _releaseManualHardwareResources()128 void PanelOverlayElement::_releaseManualHardwareResources() 129 { 130 if(!mInitialised) 131 return; 132 133 VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding; 134 if (bind->isBufferBound(POSITION_BINDING)) 135 bind->unsetBinding(POSITION_BINDING); 136 137 // Remove all texcoord element declarations 138 if(mNumTexCoordsInBuffer > 0) 139 { 140 if (bind->isBufferBound (TEXCOORD_BINDING)) 141 bind->unsetBinding(TEXCOORD_BINDING); 142 143 VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration; 144 for(size_t i = mNumTexCoordsInBuffer; i > 0; --i) 145 { 146 decl->removeElement(VES_TEXTURE_COORDINATES, 147 static_cast<unsigned short>(i - 1)); 148 } 149 mNumTexCoordsInBuffer = 0; 150 } 151 } 152 //--------------------------------------------------------------------- setTiling(Real x,Real y,ushort layer)153 void PanelOverlayElement::setTiling(Real x, Real y, ushort layer) 154 { 155 OgreAssert (layer < OGRE_MAX_TEXTURE_COORD_SETS, "out of bounds"); 156 OgreAssert (x != 0 && y != 0, "tile number must be > 0"); 157 158 mTileX[layer] = x; 159 mTileY[layer] = y; 160 161 mGeomUVsOutOfDate = true; 162 163 } 164 //--------------------------------------------------------------------- getTileX(ushort layer) const165 Real PanelOverlayElement::getTileX(ushort layer) const 166 { 167 return mTileX[layer]; 168 } 169 //--------------------------------------------------------------------- getTileY(ushort layer) const170 Real PanelOverlayElement::getTileY(ushort layer) const 171 { 172 return mTileY[layer]; 173 } 174 //--------------------------------------------------------------------- setTransparent(bool inTransparent)175 void PanelOverlayElement::setTransparent(bool inTransparent) 176 { 177 mTransparent = inTransparent; 178 } 179 //--------------------------------------------------------------------- isTransparent(void) const180 bool PanelOverlayElement::isTransparent(void) const 181 { 182 return mTransparent; 183 } 184 //--------------------------------------------------------------------- setUV(Real u1,Real v1,Real u2,Real v2)185 void PanelOverlayElement::setUV(Real u1, Real v1, Real u2, Real v2) 186 { 187 mU1 = u1; 188 mU2 = u2; 189 mV1 = v1; 190 mV2 = v2; 191 mGeomUVsOutOfDate = true; 192 } getUV(Real & u1,Real & v1,Real & u2,Real & v2) const193 void PanelOverlayElement::getUV(Real& u1, Real& v1, Real& u2, Real& v2) const 194 { 195 u1 = mU1; 196 u2 = mU2; 197 v1 = mV1; 198 v2 = mV2; 199 } 200 //--------------------------------------------------------------------- getTypeName(void) const201 const String& PanelOverlayElement::getTypeName(void) const 202 { 203 return msTypeName; 204 } 205 //--------------------------------------------------------------------- getRenderOperation(RenderOperation & op)206 void PanelOverlayElement::getRenderOperation(RenderOperation& op) 207 { 208 op = mRenderOp; 209 } 210 //--------------------------------------------------------------------- _updateRenderQueue(RenderQueue * queue)211 void PanelOverlayElement::_updateRenderQueue(RenderQueue* queue) 212 { 213 if (mVisible) 214 { 215 216 if (!mTransparent && mMaterial) 217 { 218 OverlayElement::_updateRenderQueue(queue); 219 } 220 221 // Also add children 222 ChildIterator it = getChildIterator(); 223 while (it.hasMoreElements()) 224 { 225 // Give children Z-order 1 higher than this 226 it.getNext()->_updateRenderQueue(queue); 227 } 228 } 229 } 230 //--------------------------------------------------------------------- updatePositionGeometry(void)231 void PanelOverlayElement::updatePositionGeometry(void) 232 { 233 /* 234 0-----2 235 | /| 236 | / | 237 |/ | 238 1-----3 239 */ 240 Real left, right, top, bottom; 241 242 /* Convert positions into -1, 1 coordinate space (homogenous clip space). 243 - Left / right is simple range conversion 244 - Top / bottom also need inverting since y is upside down - this means 245 that top will end up greater than bottom and when computing texture 246 coordinates, we have to flip the v-axis (ie. subtract the value from 247 1.0 to get the actual correct value). 248 */ 249 left = _getDerivedLeft() * 2 - 1; 250 right = left + (mWidth * 2); 251 top = -((_getDerivedTop() * 2) - 1); 252 bottom = top - (mHeight * 2); 253 254 HardwareVertexBufferSharedPtr vbuf = 255 mRenderOp.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING); 256 HardwareBufferLockGuard vbufLock(vbuf, HardwareBuffer::HBL_DISCARD); 257 float* pPos = static_cast<float*>(vbufLock.pData); 258 259 // Use the furthest away depth value, since materials should have depth-check off 260 // This initialised the depth buffer for any 3D objects in front 261 Real zValue = Root::getSingleton().getRenderSystem()->getMaximumDepthInputValue(); 262 *pPos++ = left; 263 *pPos++ = top; 264 *pPos++ = zValue; 265 266 *pPos++ = left; 267 *pPos++ = bottom; 268 *pPos++ = zValue; 269 270 *pPos++ = right; 271 *pPos++ = top; 272 *pPos++ = zValue; 273 274 *pPos++ = right; 275 *pPos++ = bottom; 276 *pPos++ = zValue; 277 } 278 //--------------------------------------------------------------------- updateTextureGeometry(void)279 void PanelOverlayElement::updateTextureGeometry(void) 280 { 281 // Generate for as many texture layers as there are in material 282 if (mMaterial && mInitialised) 283 { 284 // Assume one technique and pass for the moment 285 size_t numLayers = mMaterial->getTechnique(0)->getPass(0)->getNumTextureUnitStates(); 286 287 VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration; 288 // Check the number of texcoords we have in our buffer now 289 if (mNumTexCoordsInBuffer > numLayers) 290 { 291 // remove extras 292 for (size_t i = mNumTexCoordsInBuffer; i > numLayers; --i) 293 { 294 decl->removeElement(VES_TEXTURE_COORDINATES, 295 static_cast<unsigned short>(i - 1)); 296 } 297 } 298 else if (mNumTexCoordsInBuffer < numLayers) 299 { 300 // Add extra texcoord elements 301 size_t offset = VertexElement::getTypeSize(VET_FLOAT2) * mNumTexCoordsInBuffer; 302 for (size_t i = mNumTexCoordsInBuffer; i < numLayers; ++i) 303 { 304 decl->addElement(TEXCOORD_BINDING, 305 offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 306 static_cast<unsigned short>(i)); 307 offset += VertexElement::getTypeSize(VET_FLOAT2); 308 309 } 310 } 311 312 // if number of layers changed at all, we'll need to reallocate buffer 313 if (mNumTexCoordsInBuffer != numLayers) 314 { 315 // NB reference counting will take care of the old one if it exists 316 HardwareVertexBufferSharedPtr newbuf = 317 HardwareBufferManager::getSingleton().createVertexBuffer( 318 decl->getVertexSize(TEXCOORD_BINDING), mRenderOp.vertexData->vertexCount, 319 HardwareBuffer::HBU_STATIC_WRITE_ONLY // mostly static except during resizing 320 ); 321 // Bind buffer, note this will unbind the old one and destroy the buffer it had 322 mRenderOp.vertexData->vertexBufferBinding->setBinding(TEXCOORD_BINDING, newbuf); 323 // Set num tex coords in use now 324 mNumTexCoordsInBuffer = numLayers; 325 } 326 327 // Get the tcoord buffer & lock 328 if (mNumTexCoordsInBuffer) 329 { 330 HardwareVertexBufferSharedPtr vbuf = 331 mRenderOp.vertexData->vertexBufferBinding->getBuffer(TEXCOORD_BINDING); 332 HardwareBufferLockGuard vbufLock(vbuf, HardwareBuffer::HBL_DISCARD); 333 float* pVBStart = static_cast<float*>(vbufLock.pData); 334 335 size_t uvSize = VertexElement::getTypeSize(VET_FLOAT2) / sizeof(float); 336 size_t vertexSize = decl->getVertexSize(TEXCOORD_BINDING) / sizeof(float); 337 for (ushort i = 0; i < numLayers; ++i) 338 { 339 // Calc upper tex coords 340 Real upperX = mU2 * mTileX[i]; 341 Real upperY = mV2 * mTileY[i]; 342 343 344 /* 345 0-----2 346 | /| 347 | / | 348 |/ | 349 1-----3 350 */ 351 // Find start offset for this set 352 float* pTex = pVBStart + (i * uvSize); 353 354 pTex[0] = mU1; 355 pTex[1] = mV1; 356 357 pTex += vertexSize; // jump by 1 vertex stride 358 pTex[0] = mU1; 359 pTex[1] = upperY; 360 361 pTex += vertexSize; 362 pTex[0] = upperX; 363 pTex[1] = mV1; 364 365 pTex += vertexSize; 366 pTex[0] = upperX; 367 pTex[1] = upperY; 368 } 369 } 370 } 371 } 372 //----------------------------------------------------------------------- addBaseParameters(void)373 void PanelOverlayElement::addBaseParameters(void) 374 { 375 OverlayContainer::addBaseParameters(); 376 ParamDictionary* dict = getParamDictionary(); 377 378 dict->addParameter(ParameterDef("uv_coords", 379 "The texture coordinates for the texture. 1 set of uv values." 380 , PT_STRING), 381 &msCmdUVCoords); 382 383 dict->addParameter(ParameterDef("tiling", 384 "The number of times to repeat the background texture." 385 , PT_STRING), 386 &msCmdTiling); 387 388 dict->addParameter(ParameterDef("transparent", 389 "Sets whether the panel is transparent, i.e. invisible itself " 390 "but it's contents are still displayed." 391 , PT_BOOL), 392 &msCmdTransparent); 393 } 394 //----------------------------------------------------------------------- 395 // Command objects 396 //----------------------------------------------------------------------- doGet(const void * target) const397 String PanelOverlayElement::CmdTiling::doGet(const void* target) const 398 { 399 // NB only returns 1st layer tiling 400 String ret = "0 " + StringConverter::toString( 401 static_cast<const PanelOverlayElement*>(target)->getTileX() ); 402 ret += " " + StringConverter::toString( 403 static_cast<const PanelOverlayElement*>(target)->getTileY() ); 404 return ret; 405 } doSet(void * target,const String & val)406 void PanelOverlayElement::CmdTiling::doSet(void* target, const String& val) 407 { 408 // 3 params: <layer> <x_tile> <y_tile> 409 // Param count is validated higher up 410 std::vector<String> vec = StringUtil::split(val); 411 ushort layer = (ushort)StringConverter::parseUnsignedInt(vec[0]); 412 Real x_tile = StringConverter::parseReal(vec[1]); 413 Real y_tile = StringConverter::parseReal(vec[2]); 414 415 static_cast<PanelOverlayElement*>(target)->setTiling(x_tile, y_tile, layer); 416 } 417 //----------------------------------------------------------------------- doGet(const void * target) const418 String PanelOverlayElement::CmdTransparent::doGet(const void* target) const 419 { 420 return StringConverter::toString( 421 static_cast<const PanelOverlayElement*>(target)->isTransparent() ); 422 } doSet(void * target,const String & val)423 void PanelOverlayElement::CmdTransparent::doSet(void* target, const String& val) 424 { 425 static_cast<PanelOverlayElement*>(target)->setTransparent( 426 StringConverter::parseBool(val)); 427 } 428 //----------------------------------------------------------------------- doGet(const void * target) const429 String PanelOverlayElement::CmdUVCoords::doGet(const void* target) const 430 { 431 Real u1, v1, u2, v2; 432 433 static_cast<const PanelOverlayElement*>(target)->getUV(u1, v1, u2, v2); 434 String ret = " " + StringConverter::toString(u1) + " " 435 + StringConverter::toString(v1) + " " + StringConverter::toString(u2) + " " 436 + StringConverter::toString(v2); 437 438 return ret; 439 } doSet(void * target,const String & val)440 void PanelOverlayElement::CmdUVCoords::doSet(void* target, const String& val) 441 { 442 std::vector<String> vec = StringUtil::split(val); 443 444 static_cast<PanelOverlayElement*>(target)->setUV( 445 StringConverter::parseReal(vec[0]), 446 StringConverter::parseReal(vec[1]), 447 StringConverter::parseReal(vec[2]), 448 StringConverter::parseReal(vec[3]) 449 ); 450 } 451 452 } 453 454 455 456