[5] | 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-2006 Torus Knot Software Ltd |
---|
| 8 | Also see acknowledgements in Readme.html |
---|
| 9 | |
---|
| 10 | This program is free software; you can redistribute it and/or modify it under |
---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
| 13 | version. |
---|
| 14 | |
---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
| 18 | |
---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
| 23 | |
---|
| 24 | You may alternatively use this source under the terms of a specific version of |
---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
| 26 | Torus Knot Software Ltd. |
---|
| 27 | ----------------------------------------------------------------------------- |
---|
| 28 | */ |
---|
| 29 | |
---|
| 30 | // Thanks to Vincent Cantin (karmaGfa) for the original implementation of this |
---|
| 31 | // class, although it has now been mostly rewritten |
---|
| 32 | |
---|
| 33 | #include "OgreStableHeaders.h" |
---|
| 34 | #include "OgreBillboardChain.h" |
---|
| 35 | |
---|
| 36 | #include "OgreSimpleRenderable.h" |
---|
| 37 | #include "OgreHardwareBufferManager.h" |
---|
| 38 | #include "OgreNode.h" |
---|
| 39 | #include "OgreCamera.h" |
---|
| 40 | #include "OgreRoot.h" |
---|
| 41 | #include "OgreMaterialManager.h" |
---|
| 42 | #include "OgreLogManager.h" |
---|
| 43 | #include "OgreStringConverter.h" |
---|
| 44 | |
---|
| 45 | namespace Ogre { |
---|
| 46 | const size_t BillboardChain::SEGMENT_EMPTY = 0xffffffff; |
---|
| 47 | //----------------------------------------------------------------------- |
---|
| 48 | BillboardChain::Element::Element() |
---|
| 49 | { |
---|
| 50 | } |
---|
| 51 | //----------------------------------------------------------------------- |
---|
| 52 | BillboardChain::Element::Element(Vector3 _position, |
---|
| 53 | Real _width, |
---|
| 54 | Real _texCoord, |
---|
| 55 | ColourValue _colour) : |
---|
| 56 | position(_position), |
---|
| 57 | width(_width), |
---|
| 58 | texCoord(_texCoord), |
---|
| 59 | colour(_colour) |
---|
| 60 | { |
---|
| 61 | } |
---|
| 62 | //----------------------------------------------------------------------- |
---|
| 63 | BillboardChain::BillboardChain(const String& name, size_t maxElements, |
---|
| 64 | size_t numberOfChains, bool useTextureCoords, bool useColours, bool dynamic) |
---|
| 65 | :MovableObject(name), |
---|
| 66 | mMaxElementsPerChain(maxElements), |
---|
| 67 | mChainCount(numberOfChains), |
---|
| 68 | mUseTexCoords(useTextureCoords), |
---|
| 69 | mUseVertexColour(useColours), |
---|
| 70 | mDynamic(dynamic), |
---|
| 71 | mVertexDeclDirty(true), |
---|
| 72 | mBuffersNeedRecreating(true), |
---|
| 73 | mBoundsDirty(true), |
---|
| 74 | mIndexContentDirty(true), |
---|
| 75 | mRadius(0.0f), |
---|
| 76 | mTexCoordDir(TCD_U) |
---|
| 77 | { |
---|
| 78 | mVertexData = new VertexData(); |
---|
| 79 | mIndexData = new IndexData(); |
---|
| 80 | |
---|
| 81 | mOtherTexCoordRange[0] = 0.0f; |
---|
| 82 | mOtherTexCoordRange[1] = 1.0f; |
---|
| 83 | |
---|
| 84 | setupChainContainers(); |
---|
| 85 | |
---|
| 86 | mVertexData->vertexStart = 0; |
---|
| 87 | // index data set up later |
---|
| 88 | // set basic white material |
---|
| 89 | this->setMaterialName("BaseWhiteNoLighting"); |
---|
| 90 | |
---|
| 91 | } |
---|
| 92 | //----------------------------------------------------------------------- |
---|
| 93 | BillboardChain::~BillboardChain() |
---|
| 94 | { |
---|
| 95 | delete mVertexData; |
---|
| 96 | delete mIndexData; |
---|
| 97 | } |
---|
| 98 | //----------------------------------------------------------------------- |
---|
| 99 | void BillboardChain::setupChainContainers(void) |
---|
| 100 | { |
---|
| 101 | // Allocate enough space for everything |
---|
| 102 | mChainElementList.resize(mChainCount * mMaxElementsPerChain); |
---|
| 103 | mVertexData->vertexCount = mChainElementList.size() * 2; |
---|
| 104 | |
---|
| 105 | // Configure chains |
---|
| 106 | mChainSegmentList.resize(mChainCount); |
---|
| 107 | for (size_t i = 0; i < mChainCount; ++i) |
---|
| 108 | { |
---|
| 109 | ChainSegment& seg = mChainSegmentList[i]; |
---|
| 110 | seg.start = i * mMaxElementsPerChain; |
---|
| 111 | seg.tail = seg.head = SEGMENT_EMPTY; |
---|
| 112 | |
---|
| 113 | } |
---|
| 114 | |
---|
| 115 | |
---|
| 116 | } |
---|
| 117 | //----------------------------------------------------------------------- |
---|
| 118 | void BillboardChain::setupVertexDeclaration(void) |
---|
| 119 | { |
---|
| 120 | if (mVertexDeclDirty) |
---|
| 121 | { |
---|
| 122 | VertexDeclaration* decl = mVertexData->vertexDeclaration; |
---|
| 123 | decl->removeAllElements(); |
---|
| 124 | |
---|
| 125 | size_t offset = 0; |
---|
| 126 | // Add a description for the buffer of the positions of the vertices |
---|
| 127 | decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); |
---|
| 128 | offset += VertexElement::getTypeSize(VET_FLOAT3); |
---|
| 129 | |
---|
| 130 | if (mUseVertexColour) |
---|
| 131 | { |
---|
| 132 | decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE); |
---|
| 133 | offset += VertexElement::getTypeSize(VET_COLOUR); |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | if (mUseTexCoords) |
---|
| 137 | { |
---|
| 138 | decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); |
---|
| 139 | offset += VertexElement::getTypeSize(VET_FLOAT2); |
---|
| 140 | } |
---|
| 141 | |
---|
| 142 | if (!mUseTexCoords && !mUseVertexColour) |
---|
| 143 | { |
---|
| 144 | LogManager::getSingleton().logMessage( |
---|
| 145 | "Error - BillboardChain '" + mName + "' is using neither " |
---|
| 146 | "texture coordinates or vertex colours; it will not be " |
---|
| 147 | "visible on some rendering APIs so you should change this " |
---|
| 148 | "so you use one or the other."); |
---|
| 149 | } |
---|
| 150 | mVertexDeclDirty = false; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | //----------------------------------------------------------------------- |
---|
| 154 | void BillboardChain::setupBuffers(void) |
---|
| 155 | { |
---|
| 156 | setupVertexDeclaration(); |
---|
| 157 | if (mBuffersNeedRecreating) |
---|
| 158 | { |
---|
| 159 | // Create the vertex buffer (always dynamic due to the camera adjust) |
---|
| 160 | HardwareVertexBufferSharedPtr pBuffer = |
---|
| 161 | HardwareBufferManager::getSingleton().createVertexBuffer( |
---|
| 162 | mVertexData->vertexDeclaration->getVertexSize(0), |
---|
| 163 | mVertexData->vertexCount, |
---|
| 164 | HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE); |
---|
| 165 | |
---|
| 166 | // (re)Bind the buffer |
---|
| 167 | // Any existing buffer will lose its reference count and be destroyed |
---|
| 168 | mVertexData->vertexBufferBinding->setBinding(0, pBuffer); |
---|
| 169 | |
---|
| 170 | mIndexData->indexBuffer = |
---|
| 171 | HardwareBufferManager::getSingleton().createIndexBuffer( |
---|
| 172 | HardwareIndexBuffer::IT_16BIT, |
---|
| 173 | mChainCount * mMaxElementsPerChain * 6, // max we can use |
---|
| 174 | mDynamic? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY : HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
---|
| 175 | // NB we don't set the indexCount on IndexData here since we will |
---|
| 176 | // probably use less than the maximum number of indices |
---|
| 177 | |
---|
| 178 | mBuffersNeedRecreating = false; |
---|
| 179 | } |
---|
| 180 | } |
---|
| 181 | //----------------------------------------------------------------------- |
---|
| 182 | void BillboardChain::setMaxChainElements(size_t maxElements) |
---|
| 183 | { |
---|
| 184 | mMaxElementsPerChain = maxElements; |
---|
| 185 | setupChainContainers(); |
---|
| 186 | mBuffersNeedRecreating = mIndexContentDirty = true; |
---|
| 187 | } |
---|
| 188 | //----------------------------------------------------------------------- |
---|
| 189 | void BillboardChain::setNumberOfChains(size_t numChains) |
---|
| 190 | { |
---|
| 191 | mChainCount = numChains; |
---|
| 192 | setupChainContainers(); |
---|
| 193 | mBuffersNeedRecreating = mIndexContentDirty = true; |
---|
| 194 | } |
---|
| 195 | //----------------------------------------------------------------------- |
---|
| 196 | void BillboardChain::setUseTextureCoords(bool use) |
---|
| 197 | { |
---|
| 198 | mUseTexCoords = use; |
---|
| 199 | mVertexDeclDirty = mBuffersNeedRecreating = true; |
---|
| 200 | mIndexContentDirty = true; |
---|
| 201 | } |
---|
| 202 | //----------------------------------------------------------------------- |
---|
| 203 | void BillboardChain::setTextureCoordDirection(BillboardChain::TexCoordDirection dir) |
---|
| 204 | { |
---|
| 205 | mTexCoordDir = dir; |
---|
| 206 | } |
---|
| 207 | //----------------------------------------------------------------------- |
---|
| 208 | void BillboardChain::setOtherTextureCoordRange(Real start, Real end) |
---|
| 209 | { |
---|
| 210 | mOtherTexCoordRange[0] = start; |
---|
| 211 | mOtherTexCoordRange[1] = end; |
---|
| 212 | } |
---|
| 213 | //----------------------------------------------------------------------- |
---|
| 214 | void BillboardChain::setUseVertexColours(bool use) |
---|
| 215 | { |
---|
| 216 | mUseVertexColour = use; |
---|
| 217 | mVertexDeclDirty = mBuffersNeedRecreating = true; |
---|
| 218 | mIndexContentDirty = true; |
---|
| 219 | } |
---|
| 220 | //----------------------------------------------------------------------- |
---|
| 221 | void BillboardChain::setDynamic(bool dyn) |
---|
| 222 | { |
---|
| 223 | mDynamic = dyn; |
---|
| 224 | mBuffersNeedRecreating = mIndexContentDirty = true; |
---|
| 225 | } |
---|
| 226 | //----------------------------------------------------------------------- |
---|
| 227 | void BillboardChain::addChainElement(size_t chainIndex, |
---|
| 228 | const BillboardChain::Element& dtls) |
---|
| 229 | { |
---|
| 230 | |
---|
| 231 | if (chainIndex >= mChainCount) |
---|
| 232 | { |
---|
| 233 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 234 | "chainIndex out of bounds", |
---|
| 235 | "BillboardChain::addChainElement"); |
---|
| 236 | } |
---|
| 237 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
| 238 | if (seg.head == SEGMENT_EMPTY) |
---|
| 239 | { |
---|
| 240 | // Tail starts at end, head grows backwards |
---|
| 241 | seg.tail = mMaxElementsPerChain - 1; |
---|
| 242 | seg.head = seg.tail; |
---|
| 243 | mIndexContentDirty = true; |
---|
| 244 | } |
---|
| 245 | else |
---|
| 246 | { |
---|
| 247 | if (seg.head == 0) |
---|
| 248 | { |
---|
| 249 | // Wrap backwards |
---|
| 250 | seg.head = mMaxElementsPerChain - 1; |
---|
| 251 | } |
---|
| 252 | else |
---|
| 253 | { |
---|
| 254 | // Just step backward |
---|
| 255 | --seg.head; |
---|
| 256 | } |
---|
| 257 | // Run out of elements? |
---|
| 258 | if (seg.head == seg.tail) |
---|
| 259 | { |
---|
| 260 | // Move tail backwards too, losing the end of the segment and re-using |
---|
| 261 | // it in the head |
---|
| 262 | if (seg.tail == 0) |
---|
| 263 | seg.tail = mMaxElementsPerChain - 1; |
---|
| 264 | else |
---|
| 265 | --seg.tail; |
---|
| 266 | } |
---|
| 267 | } |
---|
| 268 | |
---|
| 269 | // Set the details |
---|
| 270 | mChainElementList[seg.start + seg.head] = dtls; |
---|
| 271 | |
---|
| 272 | mIndexContentDirty = true; |
---|
| 273 | mBoundsDirty = true; |
---|
| 274 | // tell parent node to update bounds |
---|
| 275 | if (mParentNode) |
---|
| 276 | mParentNode->needUpdate(); |
---|
| 277 | |
---|
| 278 | } |
---|
| 279 | //----------------------------------------------------------------------- |
---|
| 280 | void BillboardChain::removeChainElement(size_t chainIndex) |
---|
| 281 | { |
---|
| 282 | if (chainIndex >= mChainCount) |
---|
| 283 | { |
---|
| 284 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 285 | "chainIndex out of bounds", |
---|
| 286 | "BillboardChain::removeChainElement"); |
---|
| 287 | } |
---|
| 288 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
| 289 | if (seg.head == SEGMENT_EMPTY) |
---|
| 290 | return; // do nothing, nothing to remove |
---|
| 291 | |
---|
| 292 | |
---|
| 293 | if (seg.tail == seg.head) |
---|
| 294 | { |
---|
| 295 | // last item |
---|
| 296 | seg.head = seg.tail = SEGMENT_EMPTY; |
---|
| 297 | } |
---|
| 298 | else if (seg.tail == 0) |
---|
| 299 | { |
---|
| 300 | seg.tail = mMaxElementsPerChain - 1; |
---|
| 301 | } |
---|
| 302 | else |
---|
| 303 | { |
---|
| 304 | --seg.tail; |
---|
| 305 | } |
---|
| 306 | |
---|
| 307 | // we removed an entry so indexes need updating |
---|
| 308 | mIndexContentDirty = true; |
---|
| 309 | mBoundsDirty = true; |
---|
| 310 | // tell parent node to update bounds |
---|
| 311 | if (mParentNode) |
---|
| 312 | mParentNode->needUpdate(); |
---|
| 313 | |
---|
| 314 | } |
---|
| 315 | //----------------------------------------------------------------------- |
---|
| 316 | void BillboardChain::clearChain(size_t chainIndex) |
---|
| 317 | { |
---|
| 318 | if (chainIndex >= mChainCount) |
---|
| 319 | { |
---|
| 320 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 321 | "chainIndex out of bounds", |
---|
| 322 | "BillboardChain::removeChainElement"); |
---|
| 323 | } |
---|
| 324 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
| 325 | |
---|
| 326 | // Just reset head & tail |
---|
| 327 | seg.tail = seg.head = SEGMENT_EMPTY; |
---|
| 328 | |
---|
| 329 | // we removed an entry so indexes need updating |
---|
| 330 | mIndexContentDirty = true; |
---|
| 331 | mBoundsDirty = true; |
---|
| 332 | // tell parent node to update bounds |
---|
| 333 | if (mParentNode) |
---|
| 334 | mParentNode->needUpdate(); |
---|
| 335 | |
---|
| 336 | } |
---|
| 337 | //----------------------------------------------------------------------- |
---|
| 338 | void BillboardChain::clearAllChains(void) |
---|
| 339 | { |
---|
| 340 | for (size_t i = 0; i < mChainCount; ++i) |
---|
| 341 | { |
---|
| 342 | clearChain(i); |
---|
| 343 | } |
---|
| 344 | |
---|
| 345 | } |
---|
| 346 | //----------------------------------------------------------------------- |
---|
| 347 | void BillboardChain::updateChainElement(size_t chainIndex, size_t elementIndex, |
---|
| 348 | const BillboardChain::Element& dtls) |
---|
| 349 | { |
---|
| 350 | if (chainIndex >= mChainCount) |
---|
| 351 | { |
---|
| 352 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 353 | "chainIndex out of bounds", |
---|
| 354 | "BillboardChain::updateChainElement"); |
---|
| 355 | } |
---|
| 356 | ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
| 357 | if (seg.head == SEGMENT_EMPTY) |
---|
| 358 | { |
---|
| 359 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 360 | "Chain segment is empty", |
---|
| 361 | "BillboardChain::updateChainElement"); |
---|
| 362 | } |
---|
| 363 | |
---|
| 364 | size_t idx = seg.head + elementIndex; |
---|
| 365 | // adjust for the edge and start |
---|
| 366 | idx = (idx % mMaxElementsPerChain) + seg.start; |
---|
| 367 | |
---|
| 368 | mChainElementList[idx] = dtls; |
---|
| 369 | |
---|
| 370 | mBoundsDirty = true; |
---|
| 371 | // tell parent node to update bounds |
---|
| 372 | if (mParentNode) |
---|
| 373 | mParentNode->needUpdate(); |
---|
| 374 | |
---|
| 375 | |
---|
| 376 | } |
---|
| 377 | //----------------------------------------------------------------------- |
---|
| 378 | const BillboardChain::Element& |
---|
| 379 | BillboardChain::getChainElement(size_t chainIndex, size_t elementIndex) const |
---|
| 380 | { |
---|
| 381 | |
---|
| 382 | if (chainIndex >= mChainCount) |
---|
| 383 | { |
---|
| 384 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 385 | "chainIndex out of bounds", |
---|
| 386 | "BillboardChain::updateChainElement"); |
---|
| 387 | } |
---|
| 388 | const ChainSegment& seg = mChainSegmentList[chainIndex]; |
---|
| 389 | |
---|
| 390 | size_t idx = seg.head + elementIndex; |
---|
| 391 | // adjust for the edge and start |
---|
| 392 | idx = (idx % mMaxElementsPerChain) + seg.start; |
---|
| 393 | |
---|
| 394 | return mChainElementList[idx]; |
---|
| 395 | } |
---|
| 396 | //----------------------------------------------------------------------- |
---|
| 397 | void BillboardChain::updateBoundingBox(void) const |
---|
| 398 | { |
---|
| 399 | if (mBoundsDirty) |
---|
| 400 | { |
---|
| 401 | mAABB.setNull(); |
---|
| 402 | Vector3 widthVector; |
---|
| 403 | for (ChainSegmentList::const_iterator segi = mChainSegmentList.begin(); |
---|
| 404 | segi != mChainSegmentList.end(); ++segi) |
---|
| 405 | { |
---|
| 406 | const ChainSegment& seg = *segi; |
---|
| 407 | |
---|
| 408 | if (seg.head != SEGMENT_EMPTY) |
---|
| 409 | { |
---|
| 410 | |
---|
| 411 | for(size_t e = seg.head; ; ++e) // until break |
---|
| 412 | { |
---|
| 413 | // Wrap forwards |
---|
| 414 | if (e == mMaxElementsPerChain) |
---|
| 415 | e = 0; |
---|
| 416 | |
---|
| 417 | const Element& elem = mChainElementList[seg.start + e]; |
---|
| 418 | |
---|
| 419 | widthVector.x = widthVector.y = widthVector.z = elem.width; |
---|
| 420 | mAABB.merge(elem.position - widthVector); |
---|
| 421 | mAABB.merge(elem.position + widthVector); |
---|
| 422 | |
---|
| 423 | if (e == seg.tail) |
---|
| 424 | break; |
---|
| 425 | |
---|
| 426 | } |
---|
| 427 | } |
---|
| 428 | |
---|
| 429 | } |
---|
| 430 | |
---|
| 431 | // Set the current radius |
---|
| 432 | if (mAABB.isNull()) |
---|
| 433 | { |
---|
| 434 | mRadius = 0.0f; |
---|
| 435 | } |
---|
| 436 | else |
---|
| 437 | { |
---|
| 438 | mRadius = Math::Sqrt( |
---|
| 439 | std::max(mAABB.getMinimum().squaredLength(), |
---|
| 440 | mAABB.getMaximum().squaredLength())); |
---|
| 441 | } |
---|
| 442 | |
---|
| 443 | mBoundsDirty = false; |
---|
| 444 | } |
---|
| 445 | } |
---|
| 446 | //----------------------------------------------------------------------- |
---|
| 447 | void BillboardChain::updateVertexBuffer(Camera* cam) |
---|
| 448 | { |
---|
| 449 | setupBuffers(); |
---|
| 450 | HardwareVertexBufferSharedPtr pBuffer = |
---|
| 451 | mVertexData->vertexBufferBinding->getBuffer(0); |
---|
| 452 | void* pBufferStart = pBuffer->lock(HardwareBuffer::HBL_DISCARD); |
---|
| 453 | |
---|
| 454 | const Vector3& camPos = cam->getDerivedPosition(); |
---|
| 455 | Vector3 eyePos = mParentNode->_getDerivedOrientation().Inverse() * |
---|
| 456 | (camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale(); |
---|
| 457 | |
---|
| 458 | Vector3 chainTangent; |
---|
| 459 | for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); |
---|
| 460 | segi != mChainSegmentList.end(); ++segi) |
---|
| 461 | { |
---|
| 462 | ChainSegment& seg = *segi; |
---|
| 463 | |
---|
| 464 | // Skip 0 or 1 element segment counts |
---|
| 465 | if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) |
---|
| 466 | { |
---|
| 467 | size_t laste = seg.head; |
---|
| 468 | for (size_t e = seg.head; ; ++e) // until break |
---|
| 469 | { |
---|
| 470 | // Wrap forwards |
---|
| 471 | if (e == mMaxElementsPerChain) |
---|
| 472 | e = 0; |
---|
| 473 | |
---|
| 474 | Element& elem = mChainElementList[e + seg.start]; |
---|
| 475 | assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); |
---|
| 476 | uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); |
---|
| 477 | |
---|
| 478 | // Determine base pointer to vertex #1 |
---|
| 479 | void* pBase = static_cast<void*>( |
---|
| 480 | static_cast<char*>(pBufferStart) + |
---|
| 481 | pBuffer->getVertexSize() * baseIdx); |
---|
| 482 | |
---|
| 483 | // Get index of next item |
---|
| 484 | size_t nexte = e + 1; |
---|
| 485 | if (nexte == mMaxElementsPerChain) |
---|
| 486 | nexte = 0; |
---|
| 487 | |
---|
| 488 | if (e == seg.head) |
---|
| 489 | { |
---|
| 490 | // No laste, use next item |
---|
| 491 | chainTangent = mChainElementList[nexte + seg.start].position - elem.position; |
---|
| 492 | } |
---|
| 493 | else if (e == seg.tail) |
---|
| 494 | { |
---|
| 495 | // No nexte, use only last item |
---|
| 496 | chainTangent = elem.position - mChainElementList[laste + seg.start].position; |
---|
| 497 | } |
---|
| 498 | else |
---|
| 499 | { |
---|
| 500 | // A mid position, use tangent across both prev and next |
---|
| 501 | chainTangent = mChainElementList[nexte + seg.start].position - mChainElementList[laste + seg.start].position; |
---|
| 502 | |
---|
| 503 | } |
---|
| 504 | |
---|
| 505 | Vector3 vP1ToEye = eyePos - elem.position; |
---|
| 506 | Vector3 vPerpendicular = chainTangent.crossProduct(vP1ToEye); |
---|
| 507 | vPerpendicular.normalise(); |
---|
| 508 | vPerpendicular *= (elem.width * 0.5); |
---|
| 509 | |
---|
| 510 | Vector3 pos0 = elem.position - vPerpendicular; |
---|
| 511 | Vector3 pos1 = elem.position + vPerpendicular; |
---|
| 512 | |
---|
| 513 | float* pFloat = static_cast<float*>(pBase); |
---|
| 514 | // pos1 |
---|
| 515 | *pFloat++ = pos0.x; |
---|
| 516 | *pFloat++ = pos0.y; |
---|
| 517 | *pFloat++ = pos0.z; |
---|
| 518 | |
---|
| 519 | pBase = static_cast<void*>(pFloat); |
---|
| 520 | |
---|
| 521 | if (mUseVertexColour) |
---|
| 522 | { |
---|
| 523 | RGBA* pCol = static_cast<RGBA*>(pBase); |
---|
| 524 | Root::getSingleton().convertColourValue(elem.colour, pCol); |
---|
| 525 | pCol++; |
---|
| 526 | pBase = static_cast<void*>(pCol); |
---|
| 527 | } |
---|
| 528 | |
---|
| 529 | if (mUseTexCoords) |
---|
| 530 | { |
---|
| 531 | pFloat = static_cast<float*>(pBase); |
---|
| 532 | if (mTexCoordDir == TCD_U) |
---|
| 533 | { |
---|
| 534 | *pFloat++ = elem.texCoord; |
---|
| 535 | *pFloat++ = mOtherTexCoordRange[0]; |
---|
| 536 | } |
---|
| 537 | else |
---|
| 538 | { |
---|
| 539 | *pFloat++ = mOtherTexCoordRange[0]; |
---|
| 540 | *pFloat++ = elem.texCoord; |
---|
| 541 | } |
---|
| 542 | pBase = static_cast<void*>(pFloat); |
---|
| 543 | } |
---|
| 544 | |
---|
| 545 | // pos2 |
---|
| 546 | pFloat = static_cast<float*>(pBase); |
---|
| 547 | *pFloat++ = pos1.x; |
---|
| 548 | *pFloat++ = pos1.y; |
---|
| 549 | *pFloat++ = pos1.z; |
---|
| 550 | pBase = static_cast<void*>(pFloat); |
---|
| 551 | |
---|
| 552 | if (mUseVertexColour) |
---|
| 553 | { |
---|
| 554 | RGBA* pCol = static_cast<RGBA*>(pBase); |
---|
| 555 | Root::getSingleton().convertColourValue(elem.colour, pCol); |
---|
| 556 | pCol++; |
---|
| 557 | pBase = static_cast<void*>(pCol); |
---|
| 558 | } |
---|
| 559 | |
---|
| 560 | if (mUseTexCoords) |
---|
| 561 | { |
---|
| 562 | pFloat = static_cast<float*>(pBase); |
---|
| 563 | if (mTexCoordDir == TCD_U) |
---|
| 564 | { |
---|
| 565 | *pFloat++ = elem.texCoord; |
---|
| 566 | *pFloat++ = mOtherTexCoordRange[1]; |
---|
| 567 | } |
---|
| 568 | else |
---|
| 569 | { |
---|
| 570 | *pFloat++ = mOtherTexCoordRange[1]; |
---|
| 571 | *pFloat++ = elem.texCoord; |
---|
| 572 | } |
---|
| 573 | pBase = static_cast<void*>(pFloat); |
---|
| 574 | } |
---|
| 575 | |
---|
| 576 | if (e == seg.tail) |
---|
| 577 | break; // last one |
---|
| 578 | |
---|
| 579 | laste = e; |
---|
| 580 | |
---|
| 581 | } // element |
---|
| 582 | } // segment valid? |
---|
| 583 | |
---|
| 584 | } // each segment |
---|
| 585 | |
---|
| 586 | |
---|
| 587 | |
---|
| 588 | pBuffer->unlock(); |
---|
| 589 | |
---|
| 590 | |
---|
| 591 | } |
---|
| 592 | //----------------------------------------------------------------------- |
---|
| 593 | void BillboardChain::updateIndexBuffer(void) |
---|
| 594 | { |
---|
| 595 | |
---|
| 596 | setupBuffers(); |
---|
| 597 | if (mIndexContentDirty) |
---|
| 598 | { |
---|
| 599 | |
---|
| 600 | uint16* pShort = static_cast<uint16*>( |
---|
| 601 | mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); |
---|
| 602 | mIndexData->indexCount = 0; |
---|
| 603 | // indexes |
---|
| 604 | for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); |
---|
| 605 | segi != mChainSegmentList.end(); ++segi) |
---|
| 606 | { |
---|
| 607 | ChainSegment& seg = *segi; |
---|
| 608 | |
---|
| 609 | // Skip 0 or 1 element segment counts |
---|
| 610 | if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) |
---|
| 611 | { |
---|
| 612 | // Start from head + 1 since it's only useful in pairs |
---|
| 613 | size_t laste = seg.head; |
---|
| 614 | while(1) // until break |
---|
| 615 | { |
---|
| 616 | size_t e = laste + 1; |
---|
| 617 | // Wrap forwards |
---|
| 618 | if (e == mMaxElementsPerChain) |
---|
| 619 | e = 0; |
---|
| 620 | // indexes of this element are (e * 2) and (e * 2) + 1 |
---|
| 621 | // indexes of the last element are the same, -2 |
---|
| 622 | assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); |
---|
| 623 | uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); |
---|
| 624 | uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2); |
---|
| 625 | *pShort++ = lastBaseIdx; |
---|
| 626 | *pShort++ = lastBaseIdx + 1; |
---|
| 627 | *pShort++ = baseIdx; |
---|
| 628 | *pShort++ = lastBaseIdx + 1; |
---|
| 629 | *pShort++ = baseIdx + 1; |
---|
| 630 | *pShort++ = baseIdx; |
---|
| 631 | |
---|
| 632 | mIndexData->indexCount += 6; |
---|
| 633 | |
---|
| 634 | |
---|
| 635 | if (e == seg.tail) |
---|
| 636 | break; // last one |
---|
| 637 | |
---|
| 638 | laste = e; |
---|
| 639 | |
---|
| 640 | } |
---|
| 641 | } |
---|
| 642 | |
---|
| 643 | } |
---|
| 644 | mIndexData->indexBuffer->unlock(); |
---|
| 645 | |
---|
| 646 | mIndexContentDirty = false; |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | } |
---|
| 650 | //----------------------------------------------------------------------- |
---|
| 651 | void BillboardChain::_notifyCurrentCamera(Camera* cam) |
---|
| 652 | { |
---|
| 653 | updateVertexBuffer(cam); |
---|
| 654 | } |
---|
| 655 | //----------------------------------------------------------------------- |
---|
| 656 | Real BillboardChain::getSquaredViewDepth(const Camera* cam) const |
---|
| 657 | { |
---|
| 658 | Vector3 min, max, mid, dist; |
---|
| 659 | min = mAABB.getMinimum(); |
---|
| 660 | max = mAABB.getMaximum(); |
---|
| 661 | mid = ((max - min) * 0.5) + min; |
---|
| 662 | dist = cam->getDerivedPosition() - mid; |
---|
| 663 | |
---|
| 664 | return dist.squaredLength(); |
---|
| 665 | } |
---|
| 666 | //----------------------------------------------------------------------- |
---|
| 667 | Real BillboardChain::getBoundingRadius(void) const |
---|
| 668 | { |
---|
| 669 | return mRadius; |
---|
| 670 | } |
---|
| 671 | //----------------------------------------------------------------------- |
---|
| 672 | const AxisAlignedBox& BillboardChain::getBoundingBox(void) const |
---|
| 673 | { |
---|
| 674 | updateBoundingBox(); |
---|
| 675 | return mAABB; |
---|
| 676 | } |
---|
| 677 | //----------------------------------------------------------------------- |
---|
| 678 | const MaterialPtr& BillboardChain::getMaterial(void) const |
---|
| 679 | { |
---|
| 680 | return mMaterial; |
---|
| 681 | } |
---|
| 682 | //----------------------------------------------------------------------- |
---|
| 683 | void BillboardChain::setMaterialName(const String& name) |
---|
| 684 | { |
---|
| 685 | mMaterialName = name; |
---|
| 686 | mMaterial = MaterialManager::getSingleton().getByName(mMaterialName); |
---|
| 687 | |
---|
| 688 | if (mMaterial.isNull()) |
---|
| 689 | { |
---|
| 690 | LogManager::getSingleton().logMessage("Can't assign material " + name + |
---|
| 691 | " to BillboardChain " + mName + " because this " |
---|
| 692 | "Material does not exist. Have you forgotten to define it in a " |
---|
| 693 | ".material script?"); |
---|
| 694 | mMaterial = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); |
---|
| 695 | if (mMaterial.isNull()) |
---|
| 696 | { |
---|
| 697 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Can't assign default material " |
---|
| 698 | "to BillboardChain of " + mName + ". Did " |
---|
| 699 | "you forget to call MaterialManager::initialise()?", |
---|
| 700 | "BillboardChain.setMaterialName"); |
---|
| 701 | } |
---|
| 702 | } |
---|
| 703 | // Ensure new material loaded (will not load again if already loaded) |
---|
| 704 | mMaterial->load(); |
---|
| 705 | } |
---|
| 706 | //----------------------------------------------------------------------- |
---|
| 707 | const String& BillboardChain::getMovableType(void) const |
---|
| 708 | { |
---|
| 709 | return BillboardChainFactory::FACTORY_TYPE_NAME; |
---|
| 710 | } |
---|
| 711 | //----------------------------------------------------------------------- |
---|
| 712 | void BillboardChain::_updateRenderQueue(RenderQueue* queue) |
---|
| 713 | { |
---|
| 714 | updateIndexBuffer(); |
---|
| 715 | |
---|
| 716 | if (mIndexData->indexCount > 0) |
---|
| 717 | { |
---|
| 718 | if (mRenderQueueIDSet) |
---|
| 719 | queue->addRenderable(this, mRenderQueueID); |
---|
| 720 | else |
---|
| 721 | queue->addRenderable(this); |
---|
| 722 | } |
---|
| 723 | |
---|
| 724 | } |
---|
| 725 | //----------------------------------------------------------------------- |
---|
| 726 | void BillboardChain::getRenderOperation(RenderOperation& op) |
---|
| 727 | { |
---|
| 728 | op.indexData = mIndexData; |
---|
| 729 | op.operationType = RenderOperation::OT_TRIANGLE_LIST; |
---|
| 730 | op.srcRenderable = this; |
---|
| 731 | op.useIndexes = true; |
---|
| 732 | op.vertexData = mVertexData; |
---|
| 733 | } |
---|
| 734 | //----------------------------------------------------------------------- |
---|
| 735 | void BillboardChain::getWorldTransforms(Matrix4* xform) const |
---|
| 736 | { |
---|
| 737 | *xform = _getParentNodeFullTransform(); |
---|
| 738 | } |
---|
| 739 | //----------------------------------------------------------------------- |
---|
| 740 | const Quaternion& BillboardChain::getWorldOrientation(void) const |
---|
| 741 | { |
---|
| 742 | return getParentNode()->_getDerivedOrientation(); |
---|
| 743 | } |
---|
| 744 | //----------------------------------------------------------------------- |
---|
| 745 | const Vector3& BillboardChain::getWorldPosition(void) const |
---|
| 746 | { |
---|
| 747 | return getParentNode()->_getDerivedPosition(); |
---|
| 748 | } |
---|
| 749 | //----------------------------------------------------------------------- |
---|
| 750 | const LightList& BillboardChain::getLights(void) const |
---|
| 751 | { |
---|
| 752 | return queryLights(); |
---|
| 753 | } |
---|
| 754 | //----------------------------------------------------------------------- |
---|
| 755 | //----------------------------------------------------------------------- |
---|
| 756 | String BillboardChainFactory::FACTORY_TYPE_NAME = "BillboardChain"; |
---|
| 757 | //----------------------------------------------------------------------- |
---|
| 758 | const String& BillboardChainFactory::getType(void) const |
---|
| 759 | { |
---|
| 760 | return FACTORY_TYPE_NAME; |
---|
| 761 | } |
---|
| 762 | //----------------------------------------------------------------------- |
---|
| 763 | MovableObject* BillboardChainFactory::createInstanceImpl( const String& name, |
---|
| 764 | const NameValuePairList* params) |
---|
| 765 | { |
---|
| 766 | size_t maxElements = 20; |
---|
| 767 | size_t numberOfChains = 1; |
---|
| 768 | bool useTex = true; |
---|
| 769 | bool useCol = true; |
---|
| 770 | bool dynamic = true; |
---|
| 771 | // optional params |
---|
| 772 | if (params != 0) |
---|
| 773 | { |
---|
| 774 | NameValuePairList::const_iterator ni = params->find("maxElements"); |
---|
| 775 | if (ni != params->end()) |
---|
| 776 | { |
---|
| 777 | maxElements = StringConverter::parseUnsignedLong(ni->second); |
---|
| 778 | } |
---|
| 779 | ni = params->find("numberOfChains"); |
---|
| 780 | if (ni != params->end()) |
---|
| 781 | { |
---|
| 782 | numberOfChains = StringConverter::parseUnsignedLong(ni->second); |
---|
| 783 | } |
---|
| 784 | ni = params->find("useTextureCoords"); |
---|
| 785 | if (ni != params->end()) |
---|
| 786 | { |
---|
| 787 | useTex = StringConverter::parseBool(ni->second); |
---|
| 788 | } |
---|
| 789 | ni = params->find("useVertexColours"); |
---|
| 790 | if (ni != params->end()) |
---|
| 791 | { |
---|
| 792 | useCol = StringConverter::parseBool(ni->second); |
---|
| 793 | } |
---|
| 794 | ni = params->find("dynamic"); |
---|
| 795 | if (ni != params->end()) |
---|
| 796 | { |
---|
| 797 | dynamic = StringConverter::parseBool(ni->second); |
---|
| 798 | } |
---|
| 799 | |
---|
| 800 | } |
---|
| 801 | |
---|
| 802 | return new BillboardChain(name, maxElements, numberOfChains, useTex, useCol, dynamic); |
---|
| 803 | |
---|
| 804 | } |
---|
| 805 | //----------------------------------------------------------------------- |
---|
| 806 | void BillboardChainFactory::destroyInstance( MovableObject* obj) |
---|
| 807 | { |
---|
| 808 | delete obj; |
---|
| 809 | } |
---|
| 810 | |
---|
| 811 | } |
---|
| 812 | |
---|