/src/ogre/OgreMain/src/OgreBillboardChain.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 | | |
29 | | // Thanks to Vincent Cantin (karmaGfa) for the original implementation of this |
30 | | // class, although it has now been mostly rewritten |
31 | | |
32 | | #include "OgreStableHeaders.h" |
33 | | #include "OgreBillboardChain.h" |
34 | | #include "OgreViewport.h" |
35 | | |
36 | | #include <limits> |
37 | | #include <memory> |
38 | | |
39 | | namespace Ogre { |
40 | | const size_t BillboardChain::SEGMENT_EMPTY = std::numeric_limits<size_t>::max(); |
41 | | //----------------------------------------------------------------------- |
42 | | BillboardChain::Element::Element(const Vector3 &_position, |
43 | | float _width, |
44 | | float _texCoord, |
45 | | const ColourValue &_colour, |
46 | | const Quaternion &_orientation) : |
47 | 0 | position(_position), |
48 | 0 | width(_width), |
49 | 0 | texCoord(_texCoord), |
50 | 0 | colour(_colour), |
51 | 0 | orientation(_orientation) |
52 | 0 | { |
53 | 0 | } |
54 | | //----------------------------------------------------------------------- |
55 | | BillboardChain::BillboardChain(const String& name, size_t maxElements, |
56 | | size_t numberOfChains, bool useTextureCoords, bool useColours, bool dynamic) |
57 | 0 | :MovableObject(name), |
58 | 0 | mMaxElementsPerChain(maxElements), |
59 | 0 | mChainCount(numberOfChains), |
60 | 0 | mUseTexCoords(useTextureCoords), |
61 | 0 | mUseVertexColour(useColours), |
62 | 0 | mVertexDeclDirty(true), |
63 | 0 | mBuffersNeedRecreating(true), |
64 | 0 | mBoundsDirty(true), |
65 | 0 | mIndexContentDirty(true), |
66 | 0 | mVertexContentDirty(true), |
67 | 0 | mRadius(0.0f), |
68 | 0 | mTexCoordDir(TCD_U), |
69 | 0 | mFaceCamera(true), |
70 | 0 | mNormalBase(Vector3::UNIT_X), |
71 | 0 | mVertexCameraUsed(0) |
72 | 0 | { |
73 | 0 | mVertexData = std::make_unique<VertexData>(); |
74 | 0 | mIndexData = std::make_unique<IndexData>(); |
75 | |
|
76 | 0 | mOtherTexCoordRange[0] = 0.0f; |
77 | 0 | mOtherTexCoordRange[1] = 1.0f; |
78 | |
|
79 | 0 | setupChainContainers(); |
80 | |
|
81 | 0 | mVertexData->vertexStart = 0; |
82 | | // index data set up later |
83 | | // set basic white material |
84 | 0 | mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false); |
85 | 0 | mMaterial->load(); |
86 | 0 | } |
87 | | |
88 | 0 | BillboardChain::~BillboardChain() = default; // ensure unique_ptr destructors are in cpp |
89 | | |
90 | | //----------------------------------------------------------------------- |
91 | | void BillboardChain::setupChainContainers(void) |
92 | 0 | { |
93 | | // Allocate enough space for everything |
94 | 0 | mChainElementList.resize(mChainCount * mMaxElementsPerChain); |
95 | 0 | mVertexData->vertexCount = mChainElementList.size() * 2; |
96 | | |
97 | | // Configure chains |
98 | 0 | mChainSegmentList.resize(mChainCount); |
99 | 0 | for (size_t i = 0; i < mChainCount; ++i) |
100 | 0 | { |
101 | 0 | ChainSegment& seg = mChainSegmentList[i]; |
102 | 0 | seg.start = i * mMaxElementsPerChain; |
103 | 0 | seg.tail = seg.head = SEGMENT_EMPTY; |
104 | |
|
105 | 0 | } |
106 | | |
107 | |
|
108 | 0 | } |
109 | | //----------------------------------------------------------------------- |
110 | | void BillboardChain::setupVertexDeclaration(void) |
111 | 0 | { |
112 | 0 | if (mVertexDeclDirty) |
113 | 0 | { |
114 | 0 | VertexDeclaration* decl = mVertexData->vertexDeclaration; |
115 | 0 | decl->removeAllElements(); |
116 | |
|
117 | 0 | size_t offset = 0; |
118 | | // Add a description for the buffer of the positions of the vertices |
119 | 0 | offset += decl->addElement(0, offset, VET_FLOAT3, VES_POSITION).getSize(); |
120 | |
|
121 | 0 | if (mUseVertexColour) |
122 | 0 | { |
123 | 0 | offset += decl->addElement(0, offset, VET_UBYTE4_NORM, VES_DIFFUSE).getSize(); |
124 | 0 | } |
125 | |
|
126 | 0 | if (mUseTexCoords) |
127 | 0 | { |
128 | 0 | decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); |
129 | 0 | } |
130 | |
|
131 | 0 | if (!mUseTexCoords && !mUseVertexColour) |
132 | 0 | { |
133 | 0 | LogManager::getSingleton().logError( |
134 | 0 | "BillboardChain '" + mName + "' is using neither " |
135 | 0 | "texture coordinates nor vertex colours; it will not be " |
136 | 0 | "visible on some rendering APIs so you should change this " |
137 | 0 | "so you use one or the other."); |
138 | 0 | } |
139 | 0 | mVertexDeclDirty = false; |
140 | 0 | } |
141 | 0 | } |
142 | | //----------------------------------------------------------------------- |
143 | | void BillboardChain::setupBuffers(void) |
144 | 0 | { |
145 | 0 | setupVertexDeclaration(); |
146 | 0 | if (mBuffersNeedRecreating) |
147 | 0 | { |
148 | | // Create the vertex buffer (always dynamic due to the camera adjust) |
149 | 0 | HardwareVertexBufferSharedPtr pBuffer = |
150 | 0 | HardwareBufferManager::getSingleton().createVertexBuffer( |
151 | 0 | mVertexData->vertexDeclaration->getVertexSize(0), |
152 | 0 | mVertexData->vertexCount, |
153 | 0 | HBU_CPU_TO_GPU); |
154 | | |
155 | | // (re)Bind the buffer |
156 | | // Any existing buffer will lose its reference count and be destroyed |
157 | 0 | mVertexData->vertexBufferBinding->setBinding(0, pBuffer); |
158 | |
|
159 | 0 | mIndexData->indexBuffer = |
160 | 0 | HardwareBufferManager::getSingleton().createIndexBuffer( |
161 | 0 | HardwareIndexBuffer::IT_16BIT, |
162 | 0 | mChainCount * mMaxElementsPerChain * 6, // max we can use |
163 | 0 | HBU_GPU_ONLY); |
164 | | // NB we don't set the indexCount on IndexData here since we will |
165 | | // probably use less than the maximum number of indices |
166 | |
|
167 | 0 | mBuffersNeedRecreating = false; |
168 | 0 | } |
169 | 0 | } |
170 | | //----------------------------------------------------------------------- |
171 | | void BillboardChain::setMaxChainElements(size_t maxElements) |
172 | 0 | { |
173 | 0 | mMaxElementsPerChain = maxElements; |
174 | 0 | setupChainContainers(); |
175 | 0 | mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true; |
176 | 0 | } |
177 | | //----------------------------------------------------------------------- |
178 | | void BillboardChain::setNumberOfChains(size_t numChains) |
179 | 0 | { |
180 | 0 | mChainCount = numChains; |
181 | 0 | setupChainContainers(); |
182 | 0 | mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true; |
183 | 0 | } |
184 | | //----------------------------------------------------------------------- |
185 | | void BillboardChain::setUseTextureCoords(bool use) |
186 | 0 | { |
187 | 0 | mUseTexCoords = use; |
188 | 0 | mVertexDeclDirty = mBuffersNeedRecreating = true; |
189 | 0 | mIndexContentDirty = mVertexContentDirty = true; |
190 | 0 | } |
191 | | //----------------------------------------------------------------------- |
192 | | void BillboardChain::setTextureCoordDirection(BillboardChain::TexCoordDirection dir) |
193 | 0 | { |
194 | 0 | mTexCoordDir = dir; |
195 | 0 | mVertexContentDirty = true; |
196 | 0 | } |
197 | | //----------------------------------------------------------------------- |
198 | | void BillboardChain::setOtherTextureCoordRange(Real start, Real end) |
199 | 0 | { |
200 | 0 | mOtherTexCoordRange[0] = start; |
201 | 0 | mOtherTexCoordRange[1] = end; |
202 | 0 | mVertexContentDirty = true; |
203 | 0 | } |
204 | | //----------------------------------------------------------------------- |
205 | | void BillboardChain::setUseVertexColours(bool use) |
206 | 0 | { |
207 | 0 | mUseVertexColour = use; |
208 | 0 | mVertexDeclDirty = mBuffersNeedRecreating = true; |
209 | 0 | mIndexContentDirty = mVertexContentDirty = true; |
210 | 0 | } |
211 | | void BillboardChain::setAutoUpdate(bool autoUpdate) |
212 | 0 | { |
213 | 0 | mAutoUpdate = autoUpdate; |
214 | 0 | } |
215 | | //----------------------------------------------------------------------- |
216 | | void BillboardChain::addChainElement(size_t chainIndex, |
217 | | const BillboardChain::Element& dtls) |
218 | 0 | { |
219 | 0 | ChainSegment& seg = mChainSegmentList.at(chainIndex); |
220 | 0 | if (seg.head == SEGMENT_EMPTY) |
221 | 0 | { |
222 | | // Tail starts at end, head grows backwards |
223 | 0 | seg.tail = mMaxElementsPerChain - 1; |
224 | 0 | seg.head = seg.tail; |
225 | 0 | } |
226 | 0 | else |
227 | 0 | { |
228 | 0 | if (seg.head == 0) |
229 | 0 | { |
230 | | // Wrap backwards |
231 | 0 | seg.head = mMaxElementsPerChain - 1; |
232 | 0 | } |
233 | 0 | else |
234 | 0 | { |
235 | | // Just step backward |
236 | 0 | --seg.head; |
237 | 0 | } |
238 | | // Run out of elements? |
239 | 0 | if (seg.head == seg.tail) |
240 | 0 | { |
241 | | // Move tail backwards too, losing the end of the segment and re-using |
242 | | // it in the head |
243 | 0 | if (seg.tail == 0) |
244 | 0 | seg.tail = mMaxElementsPerChain - 1; |
245 | 0 | else |
246 | 0 | --seg.tail; |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | | // Set the details |
251 | 0 | mChainElementList[seg.start + seg.head] = dtls; |
252 | |
|
253 | 0 | mVertexContentDirty = true; |
254 | 0 | mIndexContentDirty = true; |
255 | 0 | mBoundsDirty = true; |
256 | | // tell parent node to update bounds |
257 | 0 | if (mParentNode) |
258 | 0 | mParentNode->needUpdate(); |
259 | |
|
260 | 0 | } |
261 | | //----------------------------------------------------------------------- |
262 | | void BillboardChain::removeChainElement(size_t chainIndex) |
263 | 0 | { |
264 | 0 | ChainSegment& seg = mChainSegmentList.at(chainIndex); |
265 | 0 | if (seg.head == SEGMENT_EMPTY) |
266 | 0 | return; // do nothing, nothing to remove |
267 | | |
268 | | |
269 | 0 | if (seg.tail == seg.head) |
270 | 0 | { |
271 | | // last item |
272 | 0 | seg.head = seg.tail = SEGMENT_EMPTY; |
273 | 0 | } |
274 | 0 | else if (seg.tail == 0) |
275 | 0 | { |
276 | 0 | seg.tail = mMaxElementsPerChain - 1; |
277 | 0 | } |
278 | 0 | else |
279 | 0 | { |
280 | 0 | --seg.tail; |
281 | 0 | } |
282 | | |
283 | | // we removed an entry so indexes need updating |
284 | 0 | mVertexContentDirty = true; |
285 | 0 | mIndexContentDirty = true; |
286 | 0 | mBoundsDirty = true; |
287 | | // tell parent node to update bounds |
288 | 0 | if (mParentNode) |
289 | 0 | mParentNode->needUpdate(); |
290 | |
|
291 | 0 | } |
292 | | //----------------------------------------------------------------------- |
293 | | void BillboardChain::clearChain(size_t chainIndex) |
294 | 0 | { |
295 | 0 | ChainSegment& seg = mChainSegmentList.at(chainIndex); |
296 | | |
297 | | // Just reset head & tail |
298 | 0 | seg.tail = seg.head = SEGMENT_EMPTY; |
299 | | |
300 | | // we removed an entry so indexes need updating |
301 | 0 | mVertexContentDirty = true; |
302 | 0 | mIndexContentDirty = true; |
303 | 0 | mBoundsDirty = true; |
304 | | // tell parent node to update bounds |
305 | 0 | if (mParentNode) |
306 | 0 | mParentNode->needUpdate(); |
307 | |
|
308 | 0 | } |
309 | | //----------------------------------------------------------------------- |
310 | | void BillboardChain::clearAllChains(void) |
311 | 0 | { |
312 | 0 | for (size_t i = 0; i < mChainCount; ++i) |
313 | 0 | { |
314 | 0 | clearChain(i); |
315 | 0 | } |
316 | |
|
317 | 0 | } |
318 | | //----------------------------------------------------------------------- |
319 | | void BillboardChain::setFaceCamera( bool faceCamera, const Vector3 &normalVector ) |
320 | 0 | { |
321 | 0 | mFaceCamera = faceCamera; |
322 | 0 | mNormalBase = normalVector.normalisedCopy(); |
323 | 0 | mVertexContentDirty = true; |
324 | 0 | } |
325 | | //----------------------------------------------------------------------- |
326 | | void BillboardChain::updateChainElement(size_t chainIndex, size_t elementIndex, |
327 | | const BillboardChain::Element& dtls) |
328 | 0 | { |
329 | 0 | ChainSegment& seg = mChainSegmentList.at(chainIndex); |
330 | 0 | OgreAssert(seg.head != SEGMENT_EMPTY, "Chain segment is empty"); |
331 | | |
332 | 0 | size_t idx = seg.head + elementIndex; |
333 | | // adjust for the edge and start |
334 | 0 | idx = (idx % mMaxElementsPerChain) + seg.start; |
335 | |
|
336 | 0 | mChainElementList[idx] = dtls; |
337 | |
|
338 | 0 | mVertexContentDirty = true; |
339 | 0 | mBoundsDirty = true; |
340 | | // tell parent node to update bounds |
341 | 0 | if (mParentNode) |
342 | 0 | mParentNode->needUpdate(); |
343 | | |
344 | |
|
345 | 0 | } |
346 | | //----------------------------------------------------------------------- |
347 | | const BillboardChain::Element& |
348 | | BillboardChain::getChainElement(size_t chainIndex, size_t elementIndex) const |
349 | 0 | { |
350 | 0 | const ChainSegment& seg = mChainSegmentList.at(chainIndex); |
351 | 0 | OgreAssert(seg.head != SEGMENT_EMPTY, "Chain segment is empty"); |
352 | | |
353 | 0 | size_t idx = seg.head + elementIndex; |
354 | | // adjust for the edge and start |
355 | 0 | idx = (idx % mMaxElementsPerChain) + seg.start; |
356 | |
|
357 | 0 | return mChainElementList[idx]; |
358 | 0 | } |
359 | | //----------------------------------------------------------------------- |
360 | | size_t BillboardChain::getNumChainElements(size_t chainIndex) const |
361 | 0 | { |
362 | 0 | const ChainSegment& seg = mChainSegmentList.at(chainIndex); |
363 | | |
364 | 0 | if (seg.head == SEGMENT_EMPTY) |
365 | 0 | { |
366 | 0 | return 0; |
367 | 0 | } |
368 | 0 | else if (seg.tail < seg.head) |
369 | 0 | { |
370 | 0 | return seg.tail - seg.head + mMaxElementsPerChain + 1; |
371 | 0 | } |
372 | 0 | else |
373 | 0 | { |
374 | 0 | return seg.tail - seg.head + 1; |
375 | 0 | } |
376 | 0 | } |
377 | | //----------------------------------------------------------------------- |
378 | | void BillboardChain::updateBoundingBox(void) const |
379 | 0 | { |
380 | 0 | if (mBoundsDirty) |
381 | 0 | { |
382 | 0 | mAABB.setNull(); |
383 | 0 | Vector3 widthVector; |
384 | 0 | for (const auto& seg : mChainSegmentList) |
385 | 0 | { |
386 | 0 | if (seg.head != SEGMENT_EMPTY) |
387 | 0 | { |
388 | |
|
389 | 0 | for(size_t e = seg.head; ; ++e) // until break |
390 | 0 | { |
391 | | // Wrap forwards |
392 | 0 | if (e == mMaxElementsPerChain) |
393 | 0 | e = 0; |
394 | |
|
395 | 0 | const Element& elem = mChainElementList[seg.start + e]; |
396 | |
|
397 | 0 | widthVector.x = widthVector.y = widthVector.z = elem.width; |
398 | 0 | mAABB.merge(elem.position - widthVector); |
399 | 0 | mAABB.merge(elem.position + widthVector); |
400 | |
|
401 | 0 | if (e == seg.tail) |
402 | 0 | break; |
403 | |
|
404 | 0 | } |
405 | 0 | } |
406 | |
|
407 | 0 | } |
408 | | |
409 | | // Set the current radius |
410 | 0 | if (mAABB.isNull()) |
411 | 0 | { |
412 | 0 | mRadius = 0.0f; |
413 | 0 | } |
414 | 0 | else |
415 | 0 | { |
416 | 0 | mRadius = Math::Sqrt( |
417 | 0 | std::max(mAABB.getMinimum().squaredLength(), |
418 | 0 | mAABB.getMaximum().squaredLength())); |
419 | 0 | } |
420 | |
|
421 | 0 | mBoundsDirty = false; |
422 | 0 | } |
423 | 0 | } |
424 | | //----------------------------------------------------------------------- |
425 | | void BillboardChain::updateVertexBuffer(Camera* cam) |
426 | 0 | { |
427 | 0 | setupBuffers(); |
428 | |
|
429 | 0 | if (!mVertexContentDirty && !mAutoUpdate) |
430 | 0 | return; |
431 | | |
432 | 0 | HardwareVertexBufferSharedPtr pBuffer = |
433 | 0 | mVertexData->vertexBufferBinding->getBuffer(0); |
434 | 0 | HardwareBufferLockGuard vertexLock(pBuffer, HardwareBuffer::HBL_DISCARD); |
435 | |
|
436 | 0 | const Vector3& camPos = cam->getDerivedPosition(); |
437 | 0 | Vector3 eyePos = mParentNode->convertWorldToLocalPosition(camPos); |
438 | |
|
439 | 0 | Vector3 chainTangent; |
440 | 0 | for (auto& seg : mChainSegmentList) |
441 | 0 | { |
442 | | // Skip 0 or 1 element segment counts |
443 | 0 | if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) |
444 | 0 | { |
445 | 0 | size_t laste = seg.head; |
446 | 0 | for (size_t e = seg.head; ; ++e) // until break |
447 | 0 | { |
448 | | // Wrap forwards |
449 | 0 | if (e == mMaxElementsPerChain) |
450 | 0 | e = 0; |
451 | |
|
452 | 0 | Element& elem = mChainElementList[e + seg.start]; |
453 | 0 | assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); |
454 | 0 | uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); |
455 | | |
456 | | // Determine base pointer to vertex #1 |
457 | 0 | float* pFloat = reinterpret_cast<float*>( |
458 | 0 | static_cast<char*>(vertexLock.pData) + |
459 | 0 | pBuffer->getVertexSize() * baseIdx); |
460 | | |
461 | | // Get index of next item |
462 | 0 | size_t nexte = e + 1; |
463 | 0 | if (nexte == mMaxElementsPerChain) |
464 | 0 | nexte = 0; |
465 | |
|
466 | 0 | if (e == seg.head) |
467 | 0 | { |
468 | | // No laste, use next item |
469 | 0 | chainTangent = mChainElementList[nexte + seg.start].position - elem.position; |
470 | 0 | } |
471 | 0 | else if (e == seg.tail) |
472 | 0 | { |
473 | | // No nexte, use only last item |
474 | 0 | chainTangent = elem.position - mChainElementList[laste + seg.start].position; |
475 | 0 | } |
476 | 0 | else |
477 | 0 | { |
478 | | // A mid position, use tangent across both prev and next |
479 | 0 | chainTangent = mChainElementList[nexte + seg.start].position - mChainElementList[laste + seg.start].position; |
480 | |
|
481 | 0 | } |
482 | |
|
483 | 0 | Vector3 vP1ToEye; |
484 | |
|
485 | 0 | if( mFaceCamera ) |
486 | 0 | vP1ToEye = eyePos - elem.position; |
487 | 0 | else |
488 | 0 | vP1ToEye = elem.orientation * mNormalBase; |
489 | |
|
490 | 0 | Vector3 vPerpendicular = chainTangent.crossProduct(vP1ToEye); |
491 | 0 | vPerpendicular.normalise(); |
492 | 0 | vPerpendicular *= (elem.width * 0.5f); |
493 | |
|
494 | 0 | Vector3 pos0 = elem.position - vPerpendicular; |
495 | 0 | Vector3 pos1 = elem.position + vPerpendicular; |
496 | | |
497 | | // pos1 |
498 | 0 | *pFloat++ = pos0.x; |
499 | 0 | *pFloat++ = pos0.y; |
500 | 0 | *pFloat++ = pos0.z; |
501 | |
|
502 | 0 | if (mUseVertexColour) |
503 | 0 | { |
504 | 0 | RGBA col = elem.colour.getAsBYTE(); |
505 | 0 | memcpy(pFloat++, &col, sizeof(RGBA)); |
506 | 0 | } |
507 | |
|
508 | 0 | if (mUseTexCoords) |
509 | 0 | { |
510 | 0 | if (mTexCoordDir == TCD_U) |
511 | 0 | { |
512 | 0 | *pFloat++ = elem.texCoord; |
513 | 0 | *pFloat++ = mOtherTexCoordRange[0]; |
514 | 0 | } |
515 | 0 | else |
516 | 0 | { |
517 | 0 | *pFloat++ = mOtherTexCoordRange[0]; |
518 | 0 | *pFloat++ = elem.texCoord; |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | // pos2 |
523 | 0 | *pFloat++ = pos1.x; |
524 | 0 | *pFloat++ = pos1.y; |
525 | 0 | *pFloat++ = pos1.z; |
526 | |
|
527 | 0 | if (mUseVertexColour) |
528 | 0 | { |
529 | 0 | RGBA col = elem.colour.getAsBYTE(); |
530 | 0 | memcpy(pFloat++, &col, sizeof(RGBA)); |
531 | 0 | } |
532 | |
|
533 | 0 | if (mUseTexCoords) |
534 | 0 | { |
535 | 0 | if (mTexCoordDir == TCD_U) |
536 | 0 | { |
537 | 0 | *pFloat++ = elem.texCoord; |
538 | 0 | *pFloat++ = mOtherTexCoordRange[1]; |
539 | 0 | } |
540 | 0 | else |
541 | 0 | { |
542 | 0 | *pFloat++ = mOtherTexCoordRange[1]; |
543 | 0 | *pFloat++ = elem.texCoord; |
544 | 0 | } |
545 | 0 | } |
546 | |
|
547 | 0 | if (e == seg.tail) |
548 | 0 | break; // last one |
549 | | |
550 | 0 | laste = e; |
551 | |
|
552 | 0 | } // element |
553 | 0 | } // segment valid? |
554 | |
|
555 | 0 | } // each segment |
556 | |
|
557 | 0 | mVertexCameraUsed = cam; |
558 | 0 | mVertexContentDirty = false; |
559 | 0 | } |
560 | | //----------------------------------------------------------------------- |
561 | | void BillboardChain::updateIndexBuffer(void) |
562 | 0 | { |
563 | |
|
564 | 0 | setupBuffers(); |
565 | 0 | if (mIndexContentDirty) |
566 | 0 | { |
567 | 0 | HardwareBufferLockGuard indexLock(mIndexData->indexBuffer, HardwareBuffer::HBL_DISCARD); |
568 | 0 | uint16* pShort = static_cast<uint16*>(indexLock.pData); |
569 | 0 | mIndexData->indexCount = 0; |
570 | | // indexes |
571 | 0 | for (auto& seg : mChainSegmentList) |
572 | 0 | { |
573 | | // Skip 0 or 1 element segment counts |
574 | 0 | if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) |
575 | 0 | { |
576 | | // Start from head + 1 since it's only useful in pairs |
577 | 0 | size_t laste = seg.head; |
578 | 0 | while(1) // until break |
579 | 0 | { |
580 | 0 | size_t e = laste + 1; |
581 | | // Wrap forwards |
582 | 0 | if (e == mMaxElementsPerChain) |
583 | 0 | e = 0; |
584 | | // indexes of this element are (e * 2) and (e * 2) + 1 |
585 | | // indexes of the last element are the same, -2 |
586 | 0 | assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); |
587 | 0 | uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); |
588 | 0 | uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2); |
589 | 0 | *pShort++ = lastBaseIdx; |
590 | 0 | *pShort++ = lastBaseIdx + 1; |
591 | 0 | *pShort++ = baseIdx; |
592 | 0 | *pShort++ = lastBaseIdx + 1; |
593 | 0 | *pShort++ = baseIdx + 1; |
594 | 0 | *pShort++ = baseIdx; |
595 | |
|
596 | 0 | mIndexData->indexCount += 6; |
597 | | |
598 | |
|
599 | 0 | if (e == seg.tail) |
600 | 0 | break; // last one |
601 | | |
602 | 0 | laste = e; |
603 | |
|
604 | 0 | } |
605 | 0 | } |
606 | |
|
607 | 0 | } |
608 | |
|
609 | 0 | mIndexContentDirty = false; |
610 | 0 | } |
611 | |
|
612 | 0 | } |
613 | | //----------------------------------------------------------------------- |
614 | | Real BillboardChain::getSquaredViewDepth(const Camera* cam) const |
615 | 0 | { |
616 | 0 | return (cam->getDerivedPosition() - mAABB.getCenter()).squaredLength(); |
617 | 0 | } |
618 | | //----------------------------------------------------------------------- |
619 | | Real BillboardChain::getBoundingRadius(void) const |
620 | 0 | { |
621 | 0 | return mRadius; |
622 | 0 | } |
623 | | //----------------------------------------------------------------------- |
624 | | const AxisAlignedBox& BillboardChain::getBoundingBox(void) const |
625 | 0 | { |
626 | 0 | updateBoundingBox(); |
627 | 0 | return mAABB; |
628 | 0 | } |
629 | | //----------------------------------------------------------------------- |
630 | | const MaterialPtr& BillboardChain::getMaterial(void) const |
631 | 0 | { |
632 | 0 | return mMaterial; |
633 | 0 | } |
634 | | //----------------------------------------------------------------------- |
635 | | void BillboardChain::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */) |
636 | 0 | { |
637 | 0 | mMaterial = MaterialManager::getSingleton().getByName(name, groupName); |
638 | |
|
639 | 0 | if (!mMaterial) |
640 | 0 | { |
641 | 0 | logMaterialNotFound(name, groupName, "BillboardChain", mName); |
642 | 0 | mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false); |
643 | 0 | } |
644 | | // Ensure new material loaded (will not load again if already loaded) |
645 | 0 | mMaterial->load(); |
646 | 0 | } |
647 | | //----------------------------------------------------------------------- |
648 | | const String& BillboardChain::getMovableType(void) const |
649 | 0 | { |
650 | 0 | return MOT_BILLBOARD_CHAIN; |
651 | 0 | } |
652 | | //----------------------------------------------------------------------- |
653 | | void BillboardChain::_updateRenderQueue(RenderQueue* queue) |
654 | 0 | { |
655 | 0 | updateIndexBuffer(); |
656 | |
|
657 | 0 | if (mIndexData->indexCount > 0) |
658 | 0 | { |
659 | 0 | if (mRenderQueuePrioritySet) |
660 | 0 | queue->addRenderable(this, mRenderQueueID, mRenderQueuePriority); |
661 | 0 | else if (mRenderQueueIDSet) |
662 | 0 | queue->addRenderable(this, mRenderQueueID); |
663 | 0 | else |
664 | 0 | queue->addRenderable(this); |
665 | 0 | } |
666 | 0 | } |
667 | | //----------------------------------------------------------------------- |
668 | | void BillboardChain::getRenderOperation(RenderOperation& op) |
669 | 0 | { |
670 | 0 | op.indexData = mIndexData.get(); |
671 | 0 | op.operationType = RenderOperation::OT_TRIANGLE_LIST; |
672 | 0 | op.srcRenderable = this; |
673 | 0 | op.useIndexes = true; |
674 | 0 | op.vertexData = mVertexData.get(); |
675 | 0 | } |
676 | | //----------------------------------------------------------------------- |
677 | | bool BillboardChain::preRender(SceneManager* sm, RenderSystem* rsys) |
678 | 0 | { |
679 | | // Retrieve the current viewport from the scene manager. |
680 | | // The viewport is only valid during a viewport update. |
681 | 0 | Viewport *currentViewport = sm->getCurrentViewport(); |
682 | 0 | if( !currentViewport ) |
683 | 0 | return false; |
684 | | |
685 | 0 | updateVertexBuffer(currentViewport->getCamera()); |
686 | 0 | return true; |
687 | 0 | } |
688 | | //----------------------------------------------------------------------- |
689 | | void BillboardChain::getWorldTransforms(Matrix4* xform) const |
690 | 0 | { |
691 | 0 | *xform = _getParentNodeFullTransform(); |
692 | 0 | } |
693 | | //----------------------------------------------------------------------- |
694 | | const LightList& BillboardChain::getLights(void) const |
695 | 0 | { |
696 | 0 | return queryLights(); |
697 | 0 | } |
698 | | //--------------------------------------------------------------------- |
699 | | void BillboardChain::visitRenderables(Renderable::Visitor* visitor, |
700 | | bool debugRenderables) |
701 | 0 | { |
702 | | // only one renderable |
703 | 0 | visitor->visit(this, 0, false); |
704 | 0 | } |
705 | | //----------------------------------------------------------------------- |
706 | | //----------------------------------------------------------------------- |
707 | | const String MOT_BILLBOARD_CHAIN = "BillboardChain"; |
708 | | //----------------------------------------------------------------------- |
709 | | const String& BillboardChainFactory::getType(void) const |
710 | 0 | { |
711 | 0 | return MOT_BILLBOARD_CHAIN; |
712 | 0 | } |
713 | | //----------------------------------------------------------------------- |
714 | | MovableObject* BillboardChainFactory::createInstanceImpl( const String& name, |
715 | | const NameValuePairList* params) |
716 | 0 | { |
717 | 0 | size_t maxElements = 20; |
718 | 0 | size_t numberOfChains = 1; |
719 | 0 | bool useTex = true; |
720 | 0 | bool useCol = true; |
721 | 0 | bool dynamic = true; |
722 | | // optional params |
723 | 0 | if (params != 0) |
724 | 0 | { |
725 | 0 | NameValuePairList::const_iterator ni = params->find("maxElements"); |
726 | 0 | if (ni != params->end()) |
727 | 0 | { |
728 | 0 | maxElements = StringConverter::parseSizeT(ni->second); |
729 | 0 | } |
730 | 0 | ni = params->find("numberOfChains"); |
731 | 0 | if (ni != params->end()) |
732 | 0 | { |
733 | 0 | numberOfChains = StringConverter::parseSizeT(ni->second); |
734 | 0 | } |
735 | 0 | ni = params->find("useTextureCoords"); |
736 | 0 | if (ni != params->end()) |
737 | 0 | { |
738 | 0 | useTex = StringConverter::parseBool(ni->second); |
739 | 0 | } |
740 | 0 | ni = params->find("useVertexColours"); |
741 | 0 | if (ni != params->end()) |
742 | 0 | { |
743 | 0 | useCol = StringConverter::parseBool(ni->second); |
744 | 0 | } |
745 | 0 | ni = params->find("dynamic"); |
746 | 0 | if (ni != params->end()) |
747 | 0 | { |
748 | 0 | dynamic = StringConverter::parseBool(ni->second); |
749 | 0 | } |
750 | 0 | } |
751 | |
|
752 | 0 | return OGRE_NEW BillboardChain(name, maxElements, numberOfChains, useTex, useCol, dynamic); |
753 | |
|
754 | 0 | } |
755 | | } |