/src/ogre/OgreMain/src/OgreBillboardSet.cpp
Line | Count | Source |
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 | | #include "OgreStableHeaders.h" |
29 | | |
30 | | #include "OgreBillboardSet.h" |
31 | | #include "OgreBillboard.h" |
32 | | |
33 | | #include <algorithm> |
34 | | #include <memory> |
35 | | |
36 | | namespace Ogre { |
37 | | //----------------------------------------------------------------------- |
38 | | BillboardSet::BillboardSet() : |
39 | 0 | mBoundingRadius(0.0f), |
40 | 0 | mOriginType( BBO_CENTER ), |
41 | 0 | mRotationType( BBR_TEXCOORD ), |
42 | 0 | mAutoExtendPool( true ), |
43 | 0 | mSortingEnabled(false), |
44 | 0 | mAccurateFacing(false), |
45 | 0 | mWorldSpace(false), |
46 | 0 | mCullIndividual( false ), |
47 | 0 | mBillboardType(BBT_POINT), |
48 | 0 | mCommonDirection(Ogre::Vector3::UNIT_Z), |
49 | 0 | mCommonUpVector(Vector3::UNIT_Y), |
50 | 0 | mPointRendering(false), |
51 | 0 | mBuffersCreated(false), |
52 | 0 | mPoolSize(0), |
53 | 0 | mExternalData(false), |
54 | 0 | mAutoUpdate(true), |
55 | 0 | mBillboardDataChanged(true) |
56 | 0 | { |
57 | 0 | setDefaultDimensions( 100, 100 ); |
58 | 0 | mMaterial = MaterialManager::getSingleton().getDefaultMaterial(); |
59 | 0 | mMaterial->load(); |
60 | 0 | mCastShadows = false; |
61 | 0 | setTextureStacksAndSlices( 1, 1 ); |
62 | 0 | } |
63 | | |
64 | | //----------------------------------------------------------------------- |
65 | | BillboardSet::BillboardSet( |
66 | | const String& name, |
67 | | unsigned int poolSize, |
68 | | bool externalData) : |
69 | 0 | MovableObject(name), |
70 | 0 | mBoundingRadius(0.0f), |
71 | 0 | mOriginType( BBO_CENTER ), |
72 | 0 | mRotationType( BBR_TEXCOORD ), |
73 | 0 | mAutoExtendPool( true ), |
74 | 0 | mSortingEnabled(false), |
75 | 0 | mAccurateFacing(false), |
76 | 0 | mWorldSpace(false), |
77 | 0 | mActiveBillboards(0), |
78 | 0 | mCullIndividual( false ), |
79 | 0 | mBillboardType(BBT_POINT), |
80 | 0 | mCommonDirection(Ogre::Vector3::UNIT_Z), |
81 | 0 | mCommonUpVector(Vector3::UNIT_Y), |
82 | 0 | mPointRendering(false), |
83 | 0 | mBuffersCreated(false), |
84 | 0 | mPoolSize(poolSize), |
85 | 0 | mExternalData(externalData), |
86 | 0 | mAutoUpdate(true), |
87 | 0 | mBillboardDataChanged(true) |
88 | 0 | { |
89 | 0 | setDefaultDimensions( 100, 100 ); |
90 | 0 | mMaterial = MaterialManager::getSingleton().getDefaultMaterial(); |
91 | 0 | mMaterial->load(); |
92 | 0 | setPoolSize( poolSize ); |
93 | 0 | mCastShadows = false; |
94 | 0 | setTextureStacksAndSlices( 1, 1 ); |
95 | 0 | } |
96 | | //----------------------------------------------------------------------- |
97 | | BillboardSet::~BillboardSet() |
98 | 0 | { |
99 | | // Free pool items |
100 | 0 | for (auto *b : mBillboardPool) |
101 | 0 | { |
102 | 0 | OGRE_DELETE b; |
103 | 0 | } |
104 | | |
105 | | // Delete shared buffers |
106 | 0 | _destroyBuffers(); |
107 | 0 | } |
108 | | //----------------------------------------------------------------------- |
109 | | Billboard* BillboardSet::createBillboard( |
110 | | const Vector3& position, |
111 | | const ColourValue& colour ) |
112 | 0 | { |
113 | 0 | if( mActiveBillboards == mBillboardPool.size() ) |
114 | 0 | { |
115 | 0 | if( mAutoExtendPool ) |
116 | 0 | { |
117 | 0 | setPoolSize( getPoolSize() * 2 ); |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | return 0; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | // Get a new billboard |
126 | 0 | Billboard* newBill = mBillboardPool[mActiveBillboards++]; |
127 | 0 | newBill->setPosition(position); |
128 | 0 | newBill->setColour(colour); |
129 | 0 | newBill->mDirection = Vector3::ZERO; |
130 | 0 | newBill->setRotation(Radian(0)); |
131 | 0 | newBill->setTexcoordIndex(0); |
132 | 0 | newBill->resetDimensions(); |
133 | | |
134 | | // Merge into bounds |
135 | 0 | Real adjust = std::max(mDefaultWidth, mDefaultHeight); |
136 | 0 | Vector3 vecAdjust(adjust, adjust, adjust); |
137 | 0 | Vector3 newMin = position - vecAdjust; |
138 | 0 | Vector3 newMax = position + vecAdjust; |
139 | |
|
140 | 0 | mAABB.merge(newMin); |
141 | 0 | mAABB.merge(newMax); |
142 | |
|
143 | 0 | mBoundingRadius = Math::boundingRadiusFromAABB(mAABB); |
144 | |
|
145 | 0 | return newBill; |
146 | 0 | } |
147 | | |
148 | | //----------------------------------------------------------------------- |
149 | | void BillboardSet::clear() |
150 | 0 | { |
151 | 0 | mActiveBillboards = 0; |
152 | 0 | } |
153 | | |
154 | | //----------------------------------------------------------------------- |
155 | | Billboard* BillboardSet::getBillboard( unsigned int index ) const |
156 | 0 | { |
157 | 0 | assert(index < mActiveBillboards && "Billboard index out of bounds."); |
158 | 0 | return mBillboardPool[index]; |
159 | 0 | } |
160 | | |
161 | | //----------------------------------------------------------------------- |
162 | | void BillboardSet::removeBillboard(unsigned int index) |
163 | 0 | { |
164 | 0 | assert(index < mActiveBillboards && "Billboard isn't in the active list."); |
165 | 0 | std::swap(mBillboardPool[index], mBillboardPool[--mActiveBillboards]); |
166 | 0 | } |
167 | | |
168 | | //----------------------------------------------------------------------- |
169 | | void BillboardSet::removeBillboard( Billboard* pBill ) |
170 | 0 | { |
171 | 0 | auto it = std::find(mBillboardPool.begin(), mBillboardPool.begin() + mActiveBillboards, pBill); |
172 | 0 | removeBillboard(std::distance(mBillboardPool.begin(), it)); |
173 | 0 | } |
174 | | //----------------------------------------------------------------------- |
175 | | void BillboardSet::setMaterialName( const String& name , const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */ ) |
176 | 0 | { |
177 | 0 | mMaterial = MaterialManager::getSingleton().getByName(name, groupName); |
178 | |
|
179 | 0 | if (!mMaterial) |
180 | 0 | OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "Could not find material " + name, |
181 | 0 | "BillboardSet::setMaterialName" ); |
182 | | |
183 | | /* Ensure that the new material was loaded (will not load again if |
184 | | already loaded anyway) |
185 | | */ |
186 | 0 | mMaterial->load(); |
187 | 0 | } |
188 | | |
189 | | //----------------------------------------------------------------------- |
190 | | void BillboardSet::_sortBillboards( Camera* cam) |
191 | 0 | { |
192 | 0 | static RadixSort<BillboardPool, Billboard*, float> mRadixSorter; |
193 | |
|
194 | 0 | switch (_getSortMode()) |
195 | 0 | { |
196 | 0 | case SM_DIRECTION: |
197 | 0 | mRadixSorter.sort(mBillboardPool.begin(), mBillboardPool.begin() + mActiveBillboards, |
198 | 0 | SortByDirectionFunctor(-mCamDir)); |
199 | 0 | break; |
200 | 0 | case SM_DISTANCE: |
201 | 0 | mRadixSorter.sort(mBillboardPool.begin(), mBillboardPool.begin() + mActiveBillboards, |
202 | 0 | SortByDistanceFunctor(mCamPos)); |
203 | 0 | break; |
204 | 0 | } |
205 | 0 | } |
206 | | BillboardSet::SortByDirectionFunctor::SortByDirectionFunctor(const Vector3& dir) |
207 | 0 | : sortDir(dir) |
208 | 0 | { |
209 | 0 | } |
210 | | float BillboardSet::SortByDirectionFunctor::operator()(Billboard* bill) const |
211 | 0 | { |
212 | 0 | return sortDir.dotProduct(bill->getPosition()); |
213 | 0 | } |
214 | | BillboardSet::SortByDistanceFunctor::SortByDistanceFunctor(const Vector3& pos) |
215 | 0 | : sortPos(pos) |
216 | 0 | { |
217 | 0 | } |
218 | | float BillboardSet::SortByDistanceFunctor::operator()(Billboard* bill) const |
219 | 0 | { |
220 | | // Sort descending by squared distance |
221 | 0 | return - (sortPos - bill->getPosition()).squaredLength(); |
222 | 0 | } |
223 | | //----------------------------------------------------------------------- |
224 | | SortMode BillboardSet::_getSortMode(void) const |
225 | 0 | { |
226 | | // Need to sort by distance if we're using accurate facing, or perpendicular billboard type. |
227 | 0 | if (mAccurateFacing || |
228 | 0 | mBillboardType == BBT_PERPENDICULAR_SELF || |
229 | 0 | mBillboardType == BBT_PERPENDICULAR_COMMON) |
230 | 0 | { |
231 | 0 | return SM_DISTANCE; |
232 | 0 | } |
233 | 0 | else |
234 | 0 | { |
235 | 0 | return SM_DIRECTION; |
236 | 0 | } |
237 | 0 | } |
238 | | //----------------------------------------------------------------------- |
239 | | void BillboardSet::_notifyCurrentCamera( Camera* cam ) |
240 | 0 | { |
241 | 0 | MovableObject::_notifyCurrentCamera(cam); |
242 | |
|
243 | 0 | mCurrentCamera = cam; |
244 | | |
245 | | // Calculate camera orientation and position |
246 | 0 | mCamQ = mCurrentCamera->getDerivedOrientation(); |
247 | 0 | mCamPos = mCurrentCamera->getDerivedPosition(); |
248 | 0 | if (!mWorldSpace) |
249 | 0 | { |
250 | | // Default behaviour is that billboards are in local node space |
251 | | // so orientation of camera (in world space) must be reverse-transformed |
252 | | // into node space |
253 | 0 | mCamQ = mParentNode->convertWorldToLocalOrientation(mCamQ); |
254 | 0 | mCamPos = mParentNode->convertWorldToLocalPosition(mCamPos); |
255 | 0 | } |
256 | | |
257 | | // Camera direction points down -Z |
258 | 0 | mCamDir = mCamQ * Vector3::NEGATIVE_UNIT_Z; |
259 | 0 | } |
260 | | //----------------------------------------------------------------------- |
261 | | void BillboardSet::beginBillboards(size_t numBillboards) |
262 | 0 | { |
263 | | /* Generate the vertices for all the billboards relative to the camera |
264 | | Also take the opportunity to update the vertex colours |
265 | | May as well do it here to save on loops elsewhere |
266 | | */ |
267 | | |
268 | | /* NOTE: most engines generate world coordinates for the billboards |
269 | | directly, taking the world axes of the camera as offsets to the |
270 | | center points. I take a different approach, reverse-transforming |
271 | | the camera world axes into local billboard space. |
272 | | Why? |
273 | | Well, it's actually more efficient this way, because I only have to |
274 | | reverse-transform using the billboardset world matrix (inverse) |
275 | | once, from then on it's simple additions (assuming identically |
276 | | sized billboards). If I transformed every billboard center by it's |
277 | | world transform, that's a matrix multiplication per billboard |
278 | | instead. |
279 | | I leave the final transform to the render pipeline since that can |
280 | | use hardware TnL if it is available. |
281 | | */ |
282 | | |
283 | | // create vertex and index buffers if they haven't already been |
284 | 0 | if(!mBuffersCreated) |
285 | 0 | _createBuffers(); |
286 | | |
287 | | // Only calculate vertex offets et al if we're not point rendering |
288 | 0 | if (!mPointRendering) |
289 | 0 | { |
290 | | |
291 | | // Get offsets for origin type |
292 | 0 | getParametricOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff); |
293 | | |
294 | | // Generate axes etc up-front if not oriented per-billboard |
295 | 0 | if (mBillboardType != BBT_ORIENTED_SELF && |
296 | 0 | mBillboardType != BBT_PERPENDICULAR_SELF && |
297 | 0 | !(mAccurateFacing && mBillboardType != BBT_PERPENDICULAR_COMMON)) |
298 | 0 | { |
299 | 0 | genBillboardAxes(&mCamX, &mCamY); |
300 | | |
301 | | /* If all billboards are the same size we can precalculate the |
302 | | offsets and just use '+' instead of '*' for each billboard, |
303 | | and it should be faster. |
304 | | */ |
305 | 0 | genVertOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff, |
306 | 0 | mDefaultWidth, mDefaultHeight, mCamX, mCamY, mVOffset); |
307 | |
|
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | | // Init num visible |
312 | 0 | mNumVisibleBillboards = 0; |
313 | | |
314 | | // Lock the buffer |
315 | 0 | if (numBillboards) // optimal lock |
316 | 0 | { |
317 | | // clamp to max |
318 | 0 | numBillboards = std::min(mPoolSize, numBillboards); |
319 | |
|
320 | 0 | size_t billboardSize; |
321 | 0 | if (mPointRendering) |
322 | 0 | { |
323 | | // just one vertex per billboard (this also excludes texcoords) |
324 | 0 | billboardSize = mMainBuf->getVertexSize(); |
325 | 0 | } |
326 | 0 | else |
327 | 0 | { |
328 | | // 4 corners |
329 | 0 | billboardSize = mMainBuf->getVertexSize() * 4; |
330 | 0 | } |
331 | 0 | assert (numBillboards * billboardSize <= mMainBuf->getSizeInBytes()); |
332 | |
|
333 | 0 | mLockPtr = static_cast<float*>( |
334 | 0 | mMainBuf->lock(0, numBillboards * billboardSize, |
335 | 0 | mMainBuf->getUsage() & HardwareBuffer::HBU_DYNAMIC ? |
336 | 0 | HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL) ); |
337 | 0 | } |
338 | 0 | else // lock the entire thing |
339 | 0 | mLockPtr = static_cast<float*>( |
340 | 0 | mMainBuf->lock(mMainBuf->getUsage() & HardwareBuffer::HBU_DYNAMIC ? |
341 | 0 | HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL) ); |
342 | |
|
343 | 0 | } |
344 | | //----------------------------------------------------------------------- |
345 | | void BillboardSet::injectBillboard(const Billboard& bb) |
346 | 0 | { |
347 | | // Don't accept injections beyond pool size |
348 | 0 | if (mNumVisibleBillboards == mPoolSize) return; |
349 | | |
350 | | // Skip if not visible (NB always true if not bounds checking individual billboards) |
351 | 0 | if (!billboardVisible(mCurrentCamera, bb)) return; |
352 | | |
353 | | // Increment visibles |
354 | 0 | mNumVisibleBillboards++; |
355 | |
|
356 | 0 | if(mPointRendering) |
357 | 0 | { |
358 | 0 | genPointVertices(bb); |
359 | 0 | return; |
360 | 0 | } |
361 | | |
362 | 0 | if ((mBillboardType == BBT_ORIENTED_SELF || mBillboardType == BBT_PERPENDICULAR_SELF || |
363 | 0 | (mAccurateFacing && mBillboardType != BBT_PERPENDICULAR_COMMON))) |
364 | 0 | { |
365 | | // Have to generate axes & offsets per billboard |
366 | 0 | genBillboardAxes(&mCamX, &mCamY, &bb); |
367 | 0 | } |
368 | |
|
369 | 0 | if ((mBillboardType == BBT_ORIENTED_SELF || mBillboardType == BBT_PERPENDICULAR_SELF || |
370 | 0 | bb.mOwnDimensions || (mAccurateFacing && mBillboardType != BBT_PERPENDICULAR_COMMON))) |
371 | 0 | { |
372 | | // If it has own dimensions, or self-oriented, gen offsets |
373 | 0 | Vector3 vOwnOffset[4]; |
374 | 0 | Real width = bb.mOwnDimensions ? bb.mWidth : mDefaultWidth; |
375 | 0 | Real height = bb.mOwnDimensions ? bb.mHeight : mDefaultHeight; |
376 | 0 | genVertOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff, |
377 | 0 | width, height, mCamX, mCamY, vOwnOffset); |
378 | 0 | genQuadVertices(vOwnOffset, bb); |
379 | 0 | } |
380 | 0 | else |
381 | 0 | { |
382 | | // Use default dimension, already computed before the loop, for faster creation |
383 | 0 | genQuadVertices(mVOffset, bb); |
384 | 0 | } |
385 | 0 | } |
386 | | //----------------------------------------------------------------------- |
387 | | void BillboardSet::endBillboards(void) |
388 | 0 | { |
389 | 0 | mMainBuf->unlock(); |
390 | 0 | } |
391 | | //----------------------------------------------------------------------- |
392 | | void BillboardSet::setBounds(const AxisAlignedBox& box, Real radius) |
393 | 0 | { |
394 | 0 | mAABB = box; |
395 | 0 | mBoundingRadius = radius; |
396 | 0 | } |
397 | | //----------------------------------------------------------------------- |
398 | | void BillboardSet::_updateBounds(void) |
399 | 0 | { |
400 | 0 | if (mActiveBillboards == 0) |
401 | 0 | { |
402 | | // No billboards, null bbox |
403 | 0 | mAABB.setNull(); |
404 | 0 | mBoundingRadius = 0.0f; |
405 | 0 | } |
406 | 0 | else |
407 | 0 | { |
408 | 0 | mAABB.setNull(); |
409 | 0 | auto iend = mBillboardPool.begin() + mActiveBillboards; |
410 | 0 | Affine3 invWorld; |
411 | 0 | bool invert = mWorldSpace && getParentSceneNode(); |
412 | 0 | if (invert) |
413 | 0 | invWorld = getParentSceneNode()->_getFullTransform().inverse(); |
414 | |
|
415 | 0 | for (auto i = mBillboardPool.begin(); i != iend; ++i) |
416 | 0 | { |
417 | 0 | Vector3 pos = (*i)->getPosition(); |
418 | | // transform from world space to local space |
419 | 0 | if (invert) |
420 | 0 | pos = invWorld * pos; |
421 | |
|
422 | 0 | mAABB.merge(pos); |
423 | 0 | } |
424 | | // Adjust for billboard size |
425 | 0 | Real adjust = std::max(mDefaultWidth, mDefaultHeight); |
426 | 0 | Vector3 vecAdjust(adjust, adjust, adjust); |
427 | |
|
428 | 0 | mAABB.setExtents(mAABB.getMinimum() - vecAdjust, mAABB.getMaximum() + vecAdjust); |
429 | 0 | mBoundingRadius = Math::boundingRadiusFromAABB(mAABB); |
430 | 0 | } |
431 | |
|
432 | 0 | if (mParentNode) |
433 | 0 | mParentNode->needUpdate(); |
434 | |
|
435 | 0 | } |
436 | | |
437 | | //----------------------------------------------------------------------- |
438 | | void BillboardSet::_updateRenderQueue(RenderQueue* queue) |
439 | 0 | { |
440 | | // If we're driving this from our own data, update geometry if need to. |
441 | 0 | if (!mExternalData && (mAutoUpdate || mBillboardDataChanged || !mBuffersCreated)) |
442 | 0 | { |
443 | 0 | if (mSortingEnabled) |
444 | 0 | { |
445 | 0 | _sortBillboards(mCurrentCamera); |
446 | 0 | } |
447 | |
|
448 | 0 | beginBillboards(mActiveBillboards); |
449 | 0 | auto iend = mBillboardPool.begin() + mActiveBillboards; |
450 | 0 | for (auto it = mBillboardPool.begin(); it != iend; ++it) |
451 | 0 | { |
452 | 0 | injectBillboard(*(*it)); |
453 | 0 | } |
454 | 0 | endBillboards(); |
455 | 0 | mBillboardDataChanged = false; |
456 | 0 | } |
457 | | |
458 | | //only set the render queue group if it has been explicitly set. |
459 | 0 | if (mRenderQueuePrioritySet) |
460 | 0 | { |
461 | 0 | assert(mRenderQueueIDSet == true); |
462 | 0 | queue->addRenderable(this, mRenderQueueID, mRenderQueuePriority); |
463 | 0 | } |
464 | 0 | else if( mRenderQueueIDSet ) |
465 | 0 | { |
466 | 0 | queue->addRenderable(this, mRenderQueueID); |
467 | 0 | } else { |
468 | 0 | queue->addRenderable(this); |
469 | 0 | } |
470 | |
|
471 | 0 | } |
472 | | |
473 | | void BillboardSet::setMaterial( const MaterialPtr& material ) |
474 | 0 | { |
475 | 0 | OgreAssert(material, "material is NULL"); |
476 | 0 | mMaterial = material; |
477 | | |
478 | | // Ensure new material loaded (will not load again if already loaded) |
479 | 0 | mMaterial->load(); |
480 | 0 | } |
481 | | |
482 | | //----------------------------------------------------------------------- |
483 | | void BillboardSet::getRenderOperation(RenderOperation& op) |
484 | 0 | { |
485 | 0 | op.vertexData = mVertexData.get(); |
486 | 0 | op.vertexData->vertexStart = 0; |
487 | |
|
488 | 0 | if (mPointRendering) |
489 | 0 | { |
490 | 0 | op.operationType = RenderOperation::OT_POINT_LIST; |
491 | 0 | op.useIndexes = false; |
492 | 0 | op.indexData = 0; |
493 | 0 | op.vertexData->vertexCount = mNumVisibleBillboards; |
494 | 0 | } |
495 | 0 | else |
496 | 0 | { |
497 | 0 | op.operationType = RenderOperation::OT_TRIANGLE_LIST; |
498 | 0 | op.useIndexes = true; |
499 | |
|
500 | 0 | op.vertexData->vertexCount = mNumVisibleBillboards * 4; |
501 | |
|
502 | 0 | op.indexData = mIndexData.get(); |
503 | 0 | op.indexData->indexCount = mNumVisibleBillboards * 6; |
504 | 0 | op.indexData->indexStart = 0; |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | | //----------------------------------------------------------------------- |
509 | | void BillboardSet::getWorldTransforms( Matrix4* xform ) const |
510 | 0 | { |
511 | 0 | if (mWorldSpace) |
512 | 0 | { |
513 | 0 | *xform = Matrix4::IDENTITY; |
514 | 0 | } |
515 | 0 | else |
516 | 0 | { |
517 | 0 | *xform = _getParentNodeFullTransform(); |
518 | 0 | } |
519 | 0 | } |
520 | | |
521 | | //----------------------------------------------------------------------- |
522 | | void BillboardSet::setPoolSize( size_t size ) |
523 | 0 | { |
524 | | // If we're driving this from our own data, allocate billboards |
525 | 0 | if (!mExternalData) |
526 | 0 | { |
527 | | // Never shrink below size() |
528 | 0 | size_t currSize = mBillboardPool.size(); |
529 | 0 | if (currSize >= size) |
530 | 0 | return; |
531 | | |
532 | 0 | this->increasePool(size); |
533 | 0 | } |
534 | | |
535 | 0 | mPoolSize = size; |
536 | |
|
537 | 0 | _destroyBuffers(); |
538 | 0 | } |
539 | | |
540 | | //----------------------------------------------------------------------- |
541 | | void BillboardSet::_createBuffers(void) |
542 | 0 | { |
543 | | /* Allocate / reallocate vertex data |
544 | | Note that we allocate enough space for ALL the billboards in the pool, but only issue |
545 | | rendering operations for the sections relating to the active billboards |
546 | | */ |
547 | | |
548 | | /* Alloc positions ( 1 or 4 verts per billboard, 3 components ) |
549 | | colours ( 1 x RGBA per vertex ) |
550 | | indices ( 6 per billboard ( 2 tris ) if not point rendering ) |
551 | | tex. coords ( 2D coords, 1 or 4 per billboard ) |
552 | | */ |
553 | | |
554 | | // Warn if user requested an invalid setup |
555 | | // Do it here so it only appears once |
556 | 0 | if (mPointRendering && mBillboardType != BBT_POINT) |
557 | 0 | { |
558 | |
|
559 | 0 | LogManager::getSingleton().logWarning("BillboardSet " + |
560 | 0 | mName + " has point rendering enabled but is using a type " |
561 | 0 | "other than BBT_POINT, this may not give you the results you " |
562 | 0 | "expect."); |
563 | 0 | } |
564 | |
|
565 | 0 | mVertexData = std::make_unique<VertexData>(); |
566 | 0 | if (mPointRendering) |
567 | 0 | mVertexData->vertexCount = mPoolSize; |
568 | 0 | else |
569 | 0 | mVertexData->vertexCount = mPoolSize * 4; |
570 | |
|
571 | 0 | mVertexData->vertexStart = 0; |
572 | | |
573 | | // Vertex declaration |
574 | 0 | VertexDeclaration* decl = mVertexData->vertexDeclaration; |
575 | 0 | VertexBufferBinding* binding = mVertexData->vertexBufferBinding; |
576 | |
|
577 | 0 | size_t offset = 0; |
578 | 0 | offset += decl->addElement(0, offset, VET_FLOAT3, VES_POSITION).getSize(); |
579 | 0 | offset += decl->addElement(0, offset, VET_UBYTE4_NORM, VES_DIFFUSE).getSize(); |
580 | | // Texture coords irrelevant when enabled point rendering (generated |
581 | | // in point sprite mode, and unused in standard point mode) |
582 | 0 | if (!mPointRendering) |
583 | 0 | { |
584 | 0 | decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); |
585 | 0 | } |
586 | |
|
587 | 0 | mMainBuf = |
588 | 0 | HardwareBufferManager::getSingleton().createVertexBuffer( |
589 | 0 | decl->getVertexSize(0), |
590 | 0 | mVertexData->vertexCount, |
591 | 0 | mAutoUpdate ? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE : |
592 | 0 | HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
593 | | // bind position and diffuses |
594 | 0 | binding->setBinding(0, mMainBuf); |
595 | |
|
596 | 0 | if (!mPointRendering) |
597 | 0 | { |
598 | 0 | mIndexData = std::make_unique<IndexData>(); |
599 | 0 | mIndexData->indexStart = 0; |
600 | 0 | mIndexData->indexCount = mPoolSize * 6; |
601 | |
|
602 | 0 | mIndexData->indexBuffer = HardwareBufferManager::getSingleton(). |
603 | 0 | createIndexBuffer(HardwareIndexBuffer::IT_16BIT, |
604 | 0 | mIndexData->indexCount, |
605 | 0 | HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
606 | | |
607 | | /* Create indexes (will be the same every frame) |
608 | | Using indexes because it means 1/3 less vertex transforms (4 instead of 6) |
609 | | |
610 | | Billboard layout relative to camera: |
611 | | |
612 | | 0-----1 |
613 | | | /| |
614 | | | / | |
615 | | |/ | |
616 | | 2-----3 |
617 | | */ |
618 | |
|
619 | 0 | HardwareBufferLockGuard indexLock(mIndexData->indexBuffer, HardwareBuffer::HBL_DISCARD); |
620 | 0 | ushort* pIdx = static_cast<ushort*>(indexLock.pData); |
621 | |
|
622 | 0 | for( |
623 | 0 | size_t idx, idxOff, bboard = 0; |
624 | 0 | bboard < mPoolSize; |
625 | 0 | ++bboard ) |
626 | 0 | { |
627 | | // Do indexes |
628 | 0 | idx = bboard * 6; |
629 | 0 | idxOff = bboard * 4; |
630 | |
|
631 | 0 | pIdx[idx] = static_cast<unsigned short>(idxOff); // + 0;, for clarity |
632 | 0 | pIdx[idx+1] = static_cast<unsigned short>(idxOff + 2); |
633 | 0 | pIdx[idx+2] = static_cast<unsigned short>(idxOff + 1); |
634 | 0 | pIdx[idx+3] = static_cast<unsigned short>(idxOff + 1); |
635 | 0 | pIdx[idx+4] = static_cast<unsigned short>(idxOff + 2); |
636 | 0 | pIdx[idx+5] = static_cast<unsigned short>(idxOff + 3); |
637 | |
|
638 | 0 | } |
639 | 0 | } |
640 | 0 | mBuffersCreated = true; |
641 | 0 | } |
642 | | //----------------------------------------------------------------------- |
643 | | void BillboardSet::_destroyBuffers(void) |
644 | 0 | { |
645 | 0 | mVertexData.reset(); |
646 | 0 | mIndexData.reset(); |
647 | 0 | mMainBuf.reset(); |
648 | |
|
649 | 0 | mBuffersCreated = false; |
650 | 0 | } |
651 | | |
652 | | //----------------------------------------------------------------------- |
653 | | void BillboardSet::getParametricOffsets( |
654 | | Real& left, Real& right, Real& top, Real& bottom ) |
655 | 0 | { |
656 | 0 | switch( mOriginType ) |
657 | 0 | { |
658 | 0 | case BBO_TOP_LEFT: |
659 | 0 | left = 0.0f; |
660 | 0 | right = 1.0f; |
661 | 0 | top = 0.0f; |
662 | 0 | bottom = -1.0f; |
663 | 0 | break; |
664 | | |
665 | 0 | case BBO_TOP_CENTER: |
666 | 0 | left = -0.5f; |
667 | 0 | right = 0.5f; |
668 | 0 | top = 0.0f; |
669 | 0 | bottom = -1.0f; |
670 | 0 | break; |
671 | | |
672 | 0 | case BBO_TOP_RIGHT: |
673 | 0 | left = -1.0f; |
674 | 0 | right = 0.0f; |
675 | 0 | top = 0.0f; |
676 | 0 | bottom = -1.0f; |
677 | 0 | break; |
678 | | |
679 | 0 | case BBO_CENTER_LEFT: |
680 | 0 | left = 0.0f; |
681 | 0 | right = 1.0f; |
682 | 0 | top = 0.5f; |
683 | 0 | bottom = -0.5f; |
684 | 0 | break; |
685 | | |
686 | 0 | case BBO_CENTER: |
687 | 0 | left = -0.5f; |
688 | 0 | right = 0.5f; |
689 | 0 | top = 0.5f; |
690 | 0 | bottom = -0.5f; |
691 | 0 | break; |
692 | | |
693 | 0 | case BBO_CENTER_RIGHT: |
694 | 0 | left = -1.0f; |
695 | 0 | right = 0.0f; |
696 | 0 | top = 0.5f; |
697 | 0 | bottom = -0.5f; |
698 | 0 | break; |
699 | | |
700 | 0 | case BBO_BOTTOM_LEFT: |
701 | 0 | left = 0.0f; |
702 | 0 | right = 1.0f; |
703 | 0 | top = 1.0f; |
704 | 0 | bottom = 0.0f; |
705 | 0 | break; |
706 | | |
707 | 0 | case BBO_BOTTOM_CENTER: |
708 | 0 | left = -0.5f; |
709 | 0 | right = 0.5f; |
710 | 0 | top = 1.0f; |
711 | 0 | bottom = 0.0f; |
712 | 0 | break; |
713 | | |
714 | 0 | case BBO_BOTTOM_RIGHT: |
715 | 0 | left = -1.0f; |
716 | 0 | right = 0.0f; |
717 | 0 | top = 1.0f; |
718 | 0 | bottom = 0.0f; |
719 | 0 | break; |
720 | 0 | } |
721 | 0 | } |
722 | | //----------------------------------------------------------------------- |
723 | | bool BillboardSet::billboardVisible(Camera* cam, const Billboard& bill) |
724 | 0 | { |
725 | | // Return always visible if not culling individually |
726 | 0 | if (!mCullIndividual) return true; |
727 | | |
728 | | // Cull based on sphere (have to transform less) |
729 | 0 | Sphere sph; |
730 | 0 | Matrix4 xworld; |
731 | |
|
732 | 0 | getWorldTransforms(&xworld); |
733 | |
|
734 | 0 | sph.setCenter(xworld * bill.mPosition); |
735 | |
|
736 | 0 | if (bill.mOwnDimensions) |
737 | 0 | { |
738 | 0 | sph.setRadius(std::max(bill.mWidth, bill.mHeight)); |
739 | 0 | } |
740 | 0 | else |
741 | 0 | { |
742 | 0 | sph.setRadius(std::max(mDefaultWidth, mDefaultHeight)); |
743 | 0 | } |
744 | |
|
745 | 0 | return cam->isVisible(sph); |
746 | |
|
747 | 0 | } |
748 | | //----------------------------------------------------------------------- |
749 | | void BillboardSet::increasePool(size_t size) |
750 | 0 | { |
751 | 0 | size_t oldSize = mBillboardPool.size(); |
752 | | |
753 | | // Increase size |
754 | 0 | mBillboardPool.resize(size); |
755 | | |
756 | | // Create new billboards |
757 | 0 | for( size_t i = oldSize; i < size; ++i ) |
758 | 0 | mBillboardPool[i] = OGRE_NEW Billboard(); |
759 | |
|
760 | 0 | } |
761 | | //----------------------------------------------------------------------- |
762 | | void BillboardSet::genBillboardAxes(Vector3* pX, Vector3 *pY, const Billboard* bb) |
763 | 0 | { |
764 | | // If we're using accurate facing, recalculate camera direction per BB |
765 | 0 | if (mAccurateFacing && |
766 | 0 | (mBillboardType == BBT_POINT || |
767 | 0 | mBillboardType == BBT_ORIENTED_COMMON || |
768 | 0 | mBillboardType == BBT_ORIENTED_SELF)) |
769 | 0 | { |
770 | | // cam -> bb direction |
771 | 0 | mCamDir = bb->mPosition - mCamPos; |
772 | 0 | mCamDir.normalise(); |
773 | 0 | } |
774 | | |
775 | |
|
776 | 0 | switch (mBillboardType) |
777 | 0 | { |
778 | 0 | case BBT_POINT: |
779 | 0 | if (mAccurateFacing) |
780 | 0 | { |
781 | | // Point billboards will have 'up' based on but not equal to cameras |
782 | | // Use pY temporarily to avoid allocation |
783 | 0 | *pY = mCamQ * Vector3::UNIT_Y; |
784 | 0 | *pX = mCamDir.crossProduct(*pY); |
785 | 0 | pX->normalise(); |
786 | 0 | *pY = pX->crossProduct(mCamDir); // both normalised already |
787 | 0 | } |
788 | 0 | else |
789 | 0 | { |
790 | | // Get camera axes for X and Y (depth is irrelevant) |
791 | 0 | *pX = mCamQ * Vector3::UNIT_X; |
792 | 0 | *pY = mCamQ * Vector3::UNIT_Y; |
793 | 0 | } |
794 | 0 | break; |
795 | | |
796 | 0 | case BBT_ORIENTED_COMMON: |
797 | | // Y-axis is common direction |
798 | | // X-axis is cross with camera direction |
799 | 0 | *pY = mCommonDirection; |
800 | 0 | *pX = mCamDir.crossProduct(*pY); |
801 | 0 | pX->normalise(); |
802 | 0 | break; |
803 | | |
804 | 0 | case BBT_ORIENTED_SELF: |
805 | | // Y-axis is direction |
806 | | // X-axis is cross with camera direction |
807 | | // Scale direction first |
808 | 0 | *pY = bb->mDirection; |
809 | 0 | *pX = mCamDir.crossProduct(*pY); |
810 | 0 | pX->normalise(); |
811 | 0 | break; |
812 | | |
813 | 0 | case BBT_PERPENDICULAR_COMMON: |
814 | | // X-axis is up-vector cross common direction |
815 | | // Y-axis is common direction cross X-axis |
816 | 0 | *pX = mCommonUpVector.crossProduct(mCommonDirection); |
817 | 0 | *pY = mCommonDirection.crossProduct(*pX); |
818 | 0 | break; |
819 | | |
820 | 0 | case BBT_PERPENDICULAR_SELF: |
821 | | // X-axis is up-vector cross own direction |
822 | | // Y-axis is own direction cross X-axis |
823 | 0 | *pX = mCommonUpVector.crossProduct(bb->mDirection); |
824 | 0 | pX->normalise(); |
825 | 0 | *pY = bb->mDirection.crossProduct(*pX); // both should be normalised |
826 | 0 | break; |
827 | 0 | } |
828 | |
|
829 | 0 | } |
830 | | //----------------------------------------------------------------------- |
831 | | uint32 BillboardSet::getTypeFlags(void) const |
832 | 0 | { |
833 | 0 | return SceneManager::FX_TYPE_MASK; |
834 | 0 | } |
835 | | //----------------------------------------------------------------------- |
836 | | void BillboardSet::genPointVertices(const Billboard& bb) |
837 | 0 | { |
838 | 0 | RGBA colour = bb.mColour; |
839 | | // Single vertex per billboard, ignore offsets |
840 | | // position |
841 | 0 | *mLockPtr++ = bb.mPosition.x; |
842 | 0 | *mLockPtr++ = bb.mPosition.y; |
843 | 0 | *mLockPtr++ = bb.mPosition.z; |
844 | | // Colour |
845 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
846 | | // No texture coords in point rendering |
847 | 0 | } |
848 | | void BillboardSet::genQuadVertices(const Vector3* const offsets, const Billboard& bb) |
849 | 0 | { |
850 | 0 | RGBA colour = bb.mColour; |
851 | | |
852 | | // Texcoords |
853 | 0 | assert(bb.mUseTexcoordRect || bb.mTexcoordIndex < mTextureCoords.size()); |
854 | 0 | const Ogre::FloatRect& r = |
855 | 0 | bb.mUseTexcoordRect ? bb.mTexcoordRect : mTextureCoords[bb.mTexcoordIndex]; |
856 | |
|
857 | 0 | if (bb.mRotation == Radian(0)) |
858 | 0 | { |
859 | | // Left-top |
860 | | // Positions |
861 | 0 | *mLockPtr++ = offsets[0].x + bb.mPosition.x; |
862 | 0 | *mLockPtr++ = offsets[0].y + bb.mPosition.y; |
863 | 0 | *mLockPtr++ = offsets[0].z + bb.mPosition.z; |
864 | | // Colour |
865 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
866 | | // Texture coords |
867 | 0 | *mLockPtr++ = r.left; |
868 | 0 | *mLockPtr++ = r.top; |
869 | | |
870 | | // Right-top |
871 | | // Positions |
872 | 0 | *mLockPtr++ = offsets[1].x + bb.mPosition.x; |
873 | 0 | *mLockPtr++ = offsets[1].y + bb.mPosition.y; |
874 | 0 | *mLockPtr++ = offsets[1].z + bb.mPosition.z; |
875 | | // Colour |
876 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
877 | | // Texture coords |
878 | 0 | *mLockPtr++ = r.right; |
879 | 0 | *mLockPtr++ = r.top; |
880 | | |
881 | | // Left-bottom |
882 | | // Positions |
883 | 0 | *mLockPtr++ = offsets[2].x + bb.mPosition.x; |
884 | 0 | *mLockPtr++ = offsets[2].y + bb.mPosition.y; |
885 | 0 | *mLockPtr++ = offsets[2].z + bb.mPosition.z; |
886 | | // Colour |
887 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
888 | | // Texture coords |
889 | 0 | *mLockPtr++ = r.left; |
890 | 0 | *mLockPtr++ = r.bottom; |
891 | | |
892 | | // Right-bottom |
893 | | // Positions |
894 | 0 | *mLockPtr++ = offsets[3].x + bb.mPosition.x; |
895 | 0 | *mLockPtr++ = offsets[3].y + bb.mPosition.y; |
896 | 0 | *mLockPtr++ = offsets[3].z + bb.mPosition.z; |
897 | | // Colour |
898 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
899 | | // Texture coords |
900 | 0 | *mLockPtr++ = r.right; |
901 | 0 | *mLockPtr++ = r.bottom; |
902 | 0 | } |
903 | 0 | else if (mRotationType == BBR_VERTEX) |
904 | 0 | { |
905 | | // TODO: Cache axis when billboard type is BBT_POINT or BBT_PERPENDICULAR_COMMON |
906 | 0 | Vector3 axis = (offsets[3] - offsets[0]).crossProduct(offsets[2] - offsets[1]).normalisedCopy(); |
907 | |
|
908 | 0 | Matrix3 rotation; |
909 | 0 | rotation.FromAngleAxis(axis, bb.mRotation); |
910 | |
|
911 | 0 | Vector3 pt; |
912 | | |
913 | | // Left-top |
914 | | // Positions |
915 | 0 | pt = rotation * offsets[0]; |
916 | 0 | *mLockPtr++ = pt.x + bb.mPosition.x; |
917 | 0 | *mLockPtr++ = pt.y + bb.mPosition.y; |
918 | 0 | *mLockPtr++ = pt.z + bb.mPosition.z; |
919 | | // Colour |
920 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
921 | | // Texture coords |
922 | 0 | *mLockPtr++ = r.left; |
923 | 0 | *mLockPtr++ = r.top; |
924 | | |
925 | | // Right-top |
926 | | // Positions |
927 | 0 | pt = rotation * offsets[1]; |
928 | 0 | *mLockPtr++ = pt.x + bb.mPosition.x; |
929 | 0 | *mLockPtr++ = pt.y + bb.mPosition.y; |
930 | 0 | *mLockPtr++ = pt.z + bb.mPosition.z; |
931 | | // Colour |
932 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
933 | | // Texture coords |
934 | 0 | *mLockPtr++ = r.right; |
935 | 0 | *mLockPtr++ = r.top; |
936 | | |
937 | | // Left-bottom |
938 | | // Positions |
939 | 0 | pt = rotation * offsets[2]; |
940 | 0 | *mLockPtr++ = pt.x + bb.mPosition.x; |
941 | 0 | *mLockPtr++ = pt.y + bb.mPosition.y; |
942 | 0 | *mLockPtr++ = pt.z + bb.mPosition.z; |
943 | | // Colour |
944 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
945 | | // Texture coords |
946 | 0 | *mLockPtr++ = r.left; |
947 | 0 | *mLockPtr++ = r.bottom; |
948 | | |
949 | | // Right-bottom |
950 | | // Positions |
951 | 0 | pt = rotation * offsets[3]; |
952 | 0 | *mLockPtr++ = pt.x + bb.mPosition.x; |
953 | 0 | *mLockPtr++ = pt.y + bb.mPosition.y; |
954 | 0 | *mLockPtr++ = pt.z + bb.mPosition.z; |
955 | | // Colour |
956 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
957 | | // Texture coords |
958 | 0 | *mLockPtr++ = r.right; |
959 | 0 | *mLockPtr++ = r.bottom; |
960 | 0 | } |
961 | 0 | else |
962 | 0 | { |
963 | 0 | const Real cos_rot ( Math::Cos(bb.mRotation) ); |
964 | 0 | const Real sin_rot ( Math::Sin(bb.mRotation) ); |
965 | |
|
966 | 0 | float width = (r.right-r.left)/2; |
967 | 0 | float height = (r.bottom-r.top)/2; |
968 | 0 | float mid_u = r.left+width; |
969 | 0 | float mid_v = r.top+height; |
970 | |
|
971 | 0 | float cos_rot_w = cos_rot * width; |
972 | 0 | float cos_rot_h = cos_rot * height; |
973 | 0 | float sin_rot_w = sin_rot * width; |
974 | 0 | float sin_rot_h = sin_rot * height; |
975 | | |
976 | | // Left-top |
977 | | // Positions |
978 | 0 | *mLockPtr++ = offsets[0].x + bb.mPosition.x; |
979 | 0 | *mLockPtr++ = offsets[0].y + bb.mPosition.y; |
980 | 0 | *mLockPtr++ = offsets[0].z + bb.mPosition.z; |
981 | | // Colour |
982 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
983 | | // Texture coords |
984 | 0 | *mLockPtr++ = mid_u - cos_rot_w + sin_rot_h; |
985 | 0 | *mLockPtr++ = mid_v - sin_rot_w - cos_rot_h; |
986 | | |
987 | | // Right-top |
988 | | // Positions |
989 | 0 | *mLockPtr++ = offsets[1].x + bb.mPosition.x; |
990 | 0 | *mLockPtr++ = offsets[1].y + bb.mPosition.y; |
991 | 0 | *mLockPtr++ = offsets[1].z + bb.mPosition.z; |
992 | | // Colour |
993 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
994 | | // Texture coords |
995 | 0 | *mLockPtr++ = mid_u + cos_rot_w + sin_rot_h; |
996 | 0 | *mLockPtr++ = mid_v + sin_rot_w - cos_rot_h; |
997 | | |
998 | | // Left-bottom |
999 | | // Positions |
1000 | 0 | *mLockPtr++ = offsets[2].x + bb.mPosition.x; |
1001 | 0 | *mLockPtr++ = offsets[2].y + bb.mPosition.y; |
1002 | 0 | *mLockPtr++ = offsets[2].z + bb.mPosition.z; |
1003 | | // Colour |
1004 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
1005 | | // Texture coords |
1006 | 0 | *mLockPtr++ = mid_u - cos_rot_w - sin_rot_h; |
1007 | 0 | *mLockPtr++ = mid_v - sin_rot_w + cos_rot_h; |
1008 | | |
1009 | | // Right-bottom |
1010 | | // Positions |
1011 | 0 | *mLockPtr++ = offsets[3].x + bb.mPosition.x; |
1012 | 0 | *mLockPtr++ = offsets[3].y + bb.mPosition.y; |
1013 | 0 | *mLockPtr++ = offsets[3].z + bb.mPosition.z; |
1014 | | // Colour |
1015 | 0 | memcpy(mLockPtr++, &colour, sizeof(RGBA)); |
1016 | | // Texture coords |
1017 | 0 | *mLockPtr++ = mid_u + cos_rot_w - sin_rot_h; |
1018 | 0 | *mLockPtr++ = mid_v + sin_rot_w + cos_rot_h; |
1019 | 0 | } |
1020 | 0 | } |
1021 | | //----------------------------------------------------------------------- |
1022 | | void BillboardSet::genVertOffsets(Real inleft, Real inright, Real intop, Real inbottom, |
1023 | | Real width, Real height, const Vector3& x, const Vector3& y, Vector3* pDestVec) |
1024 | 0 | { |
1025 | 0 | Vector3 vLeftOff, vRightOff, vTopOff, vBottomOff; |
1026 | | /* Calculate default offsets. Scale the axes by |
1027 | | parametric offset and dimensions, ready to be added to |
1028 | | positions. |
1029 | | */ |
1030 | |
|
1031 | 0 | vLeftOff = x * ( inleft * width ); |
1032 | 0 | vRightOff = x * ( inright * width ); |
1033 | 0 | vTopOff = y * ( intop * height ); |
1034 | 0 | vBottomOff = y * ( inbottom * height ); |
1035 | | |
1036 | | // Make final offsets to vertex positions |
1037 | 0 | pDestVec[0] = vLeftOff + vTopOff; |
1038 | 0 | pDestVec[1] = vRightOff + vTopOff; |
1039 | 0 | pDestVec[2] = vLeftOff + vBottomOff; |
1040 | 0 | pDestVec[3] = vRightOff + vBottomOff; |
1041 | |
|
1042 | 0 | } |
1043 | | //----------------------------------------------------------------------- |
1044 | | const String& BillboardSet::getMovableType(void) const |
1045 | 0 | { |
1046 | 0 | return MOT_BILLBOARD_SET; |
1047 | 0 | } |
1048 | | //----------------------------------------------------------------------- |
1049 | | Real BillboardSet::getSquaredViewDepth(const Camera* const cam) const |
1050 | 0 | { |
1051 | 0 | assert(mParentNode); |
1052 | 0 | return mParentNode->getSquaredViewDepth(cam); |
1053 | 0 | } |
1054 | | //----------------------------------------------------------------------- |
1055 | | const LightList& BillboardSet::getLights(void) const |
1056 | 0 | { |
1057 | | // It's actually quite unlikely that this will be called, |
1058 | | // because most billboards are unlit, but here we go anyway |
1059 | 0 | return queryLights(); |
1060 | 0 | } |
1061 | | //--------------------------------------------------------------------- |
1062 | | void BillboardSet::visitRenderables(Renderable::Visitor* visitor, |
1063 | | bool debugRenderables) |
1064 | 0 | { |
1065 | | // only one renderable |
1066 | 0 | visitor->visit(this, 0, false); |
1067 | 0 | } |
1068 | | |
1069 | | |
1070 | | void BillboardSet::setTextureCoords(const std::vector<FloatRect>& coords) |
1071 | 0 | { |
1072 | 0 | if(coords.empty()) { |
1073 | 0 | setTextureStacksAndSlices(1, 1); |
1074 | 0 | return; |
1075 | 0 | } |
1076 | 0 | mTextureCoords = coords; |
1077 | 0 | } |
1078 | | |
1079 | | void BillboardSet::setTextureStacksAndSlices( uchar stacks, uchar slices ) |
1080 | 0 | { |
1081 | 0 | if(stacks == 0) stacks = 1; |
1082 | 0 | if(slices == 0) slices = 1; |
1083 | | // clear out any previous allocation (as vectors may not shrink) |
1084 | 0 | TextureCoordSets().swap(mTextureCoords); |
1085 | | // make room |
1086 | 0 | mTextureCoords.resize((size_t)stacks * slices); |
1087 | 0 | unsigned int coordIndex = 0; |
1088 | | // spread the U and V coordinates across the rects |
1089 | 0 | for(uint v = 0; v < stacks; ++v) { |
1090 | | // (float)X / X is guaranteed to be == 1.0f for X up to 8 million, so |
1091 | | // our range of 1..256 is quite enough to guarantee perfect coverage. |
1092 | 0 | float top = (float)v / (float)stacks; |
1093 | 0 | float bottom = ((float)v + 1) / (float)stacks; |
1094 | 0 | for(uint u = 0; u < slices; ++u) { |
1095 | 0 | Ogre::FloatRect & r = mTextureCoords[coordIndex]; |
1096 | 0 | r.left = (float)u / (float)slices; |
1097 | 0 | r.bottom = bottom; |
1098 | 0 | r.right = ((float)u + 1) / (float)slices; |
1099 | 0 | r.top = top; |
1100 | 0 | ++coordIndex; |
1101 | 0 | } |
1102 | 0 | } |
1103 | 0 | assert( coordIndex == (size_t)stacks * slices ); |
1104 | 0 | } |
1105 | | //----------------------------------------------------------------------- |
1106 | | void BillboardSet::setPointRenderingEnabled(bool enabled) |
1107 | 0 | { |
1108 | | // Override point rendering if not supported |
1109 | 0 | if (enabled && !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_POINT_SPRITES)) |
1110 | 0 | { |
1111 | 0 | enabled = false; |
1112 | 0 | } |
1113 | |
|
1114 | 0 | if (enabled != mPointRendering) |
1115 | 0 | { |
1116 | 0 | mPointRendering = enabled; |
1117 | | // Different buffer structure (1 or 4 verts per billboard) |
1118 | 0 | _destroyBuffers(); |
1119 | 0 | } |
1120 | 0 | } |
1121 | | |
1122 | | //----------------------------------------------------------------------- |
1123 | | void BillboardSet::setAutoUpdate(bool autoUpdate) |
1124 | 0 | { |
1125 | | // Case auto update buffers changed we have to destroy the current buffers |
1126 | | // since their usage will be different. |
1127 | 0 | if (autoUpdate != mAutoUpdate) |
1128 | 0 | { |
1129 | 0 | mAutoUpdate = autoUpdate; |
1130 | 0 | _destroyBuffers(); |
1131 | 0 | } |
1132 | 0 | } |
1133 | | |
1134 | | //----------------------------------------------------------------------- |
1135 | | //----------------------------------------------------------------------- |
1136 | | const String MOT_BILLBOARD_SET = "BillboardSet"; |
1137 | | //----------------------------------------------------------------------- |
1138 | | const String& BillboardSetFactory::getType(void) const |
1139 | 0 | { |
1140 | 0 | return MOT_BILLBOARD_SET; |
1141 | 0 | } |
1142 | | //----------------------------------------------------------------------- |
1143 | | MovableObject* BillboardSetFactory::createInstanceImpl( const String& name, |
1144 | | const NameValuePairList* params) |
1145 | 0 | { |
1146 | | // may have parameters |
1147 | 0 | bool externalData = false; |
1148 | 0 | unsigned int poolSize = 0; |
1149 | |
|
1150 | 0 | if (params != 0) |
1151 | 0 | { |
1152 | 0 | NameValuePairList::const_iterator ni = params->find("poolSize"); |
1153 | 0 | if (ni != params->end()) |
1154 | 0 | { |
1155 | 0 | poolSize = StringConverter::parseUnsignedInt(ni->second); |
1156 | 0 | } |
1157 | 0 | ni = params->find("externalData"); |
1158 | 0 | if (ni != params->end()) |
1159 | 0 | { |
1160 | 0 | externalData = StringConverter::parseBool(ni->second); |
1161 | 0 | } |
1162 | 0 | } |
1163 | |
|
1164 | 0 | if (poolSize > 0) |
1165 | 0 | { |
1166 | 0 | return OGRE_NEW BillboardSet(name, poolSize, externalData); |
1167 | 0 | } |
1168 | 0 | else |
1169 | 0 | { |
1170 | | return OGRE_NEW BillboardSet(name); |
1171 | 0 | } |
1172 | 0 | } |
1173 | | } |