123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- /****************************************************************************
- Copyright (C) 2013 Henry van Merode. All rights reserved.
- Copyright (c) 2015-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos2d-x.org
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #include "extensions/Particle3D/PU/CCPURibbonTrail.h"
- #include "extensions/Particle3D/PU/CCPUParticleSystem3D.h"
- #include "base/CCDirector.h"
- #include "renderer/CCMeshCommand.h"
- #include "renderer/CCRenderer.h"
- #include "renderer/CCTextureCache.h"
- #include "renderer/CCGLProgramState.h"
- #include "renderer/CCGLProgramCache.h"
- #include "renderer/CCVertexIndexBuffer.h"
- #include "2d/CCCamera.h"
- #include "3d/CCSprite3D.h"
- NS_CC_BEGIN
- PURibbonTrail::PURibbonTrail(const std::string& name, const std::string &texFile, size_t maxElements,
- size_t numberOfChains, bool useTextureCoords, bool useColours)
- :PUBillboardChain(name, texFile, maxElements, 0, useTextureCoords, useColours, true),
- _parentNode(nullptr),
- _needTimeUpdate(false)
- {
- setTrailLength(100);
- setNumberOfChains(numberOfChains);
- // use V as varying texture coord, so we can use 1D textures to 'smear'
- setTextureCoordDirection(TCD_V);
- }
- //-----------------------------------------------------------------------
- PURibbonTrail::~PURibbonTrail()
- {
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::addNode(Node* n)
- {
- if (_nodeList.size() == _chainCount)
- {
- CCASSERT(false, " cannot monitor any more nodes, chain count exceeded");
- }
- //if (n->getListener())
- //{
- // OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
- // mName + " cannot monitor node " + n->getName() + " since it already has a listener.",
- // "RibbonTrail::addNode");
- //}
- // get chain index
- size_t chainIndex = _freeChains.back();
- _freeChains.pop_back();
- _nodeToChainSegment.push_back(chainIndex);
- _nodeToSegMap[n] = chainIndex;
- // initialise the chain
- resetTrail(chainIndex, n);
- _nodeList.push_back(n);
- //n->setListener(this);
- }
- //-----------------------------------------------------------------------
- size_t PURibbonTrail::getChainIndexForNode(const Node* n)
- {
- NodeToChainSegmentMap::const_iterator i = _nodeToSegMap.find(n);
- if (i == _nodeToSegMap.end())
- {
- CCASSERT(false, "This node is not being tracked");
- }
- return i->second;
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::removeNode(Node* n)
- {
- NodeList::iterator i = std::find(_nodeList.begin(), _nodeList.end(), n);
- if (i != _nodeList.end())
- {
- // also get matching chain segment
- size_t index = std::distance(_nodeList.begin(), i);
- IndexVector::iterator mi = _nodeToChainSegment.begin();
- std::advance(mi, index);
- size_t chainIndex = *mi;
- PUBillboardChain::clearChain(chainIndex);
- // mark as free now
- _freeChains.push_back(chainIndex);
- //n->setListener(0);
- _nodeList.erase(i);
- _nodeToChainSegment.erase(mi);
- _nodeToSegMap.erase(_nodeToSegMap.find(n));
- }
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setTrailLength(float len)
- {
- _trailLength = len;
- _elemLength = _trailLength / _maxElementsPerChain;
- _squaredElemLength = _elemLength * _elemLength;
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setMaxChainElements(size_t maxElements)
- {
- PUBillboardChain::setMaxChainElements(maxElements);
- _elemLength = _trailLength / _maxElementsPerChain;
- _squaredElemLength = _elemLength * _elemLength;
- resetAllTrails();
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setNumberOfChains(size_t numChains)
- {
- CCASSERT(numChains >= _nodeList.size(), "Can't shrink the number of chains less than number of tracking nodes");
- size_t oldChains = getNumberOfChains();
- PUBillboardChain::setNumberOfChains(numChains);
- _initialColor.resize(numChains, Vec4::ONE);
- _deltaColor.resize(numChains, Vec4::ZERO);
- _initialWidth.resize(numChains, 10);
- _deltaWidth.resize(numChains, 0);
- if (oldChains > numChains)
- {
- // remove free chains
- for (IndexVector::iterator i = _freeChains.begin(); i != _freeChains.end();)
- {
- if (*i >= numChains)
- i = _freeChains.erase(i);
- else
- ++i;
- }
- }
- else if (oldChains < numChains)
- {
- // add new chains, at front to preserve previous ordering (pop_back)
- for (size_t i = oldChains; i < numChains; ++i)
- _freeChains.insert(_freeChains.begin(), i);
- }
- resetAllTrails();
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::clearChain(size_t chainIndex)
- {
- PUBillboardChain::clearChain(chainIndex);
- // Reset if we are tracking for this chain
- IndexVector::iterator i = std::find(_nodeToChainSegment.begin(), _nodeToChainSegment.end(), chainIndex);
- if (i != _nodeToChainSegment.end())
- {
- size_t nodeIndex = std::distance(_nodeToChainSegment.begin(), i);
- resetTrail(*i, _nodeList[nodeIndex]);
- }
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setInitialColour(size_t chainIndex, const Vec4& col)
- {
- setInitialColour(chainIndex, col.x, col.y, col.z, col.w);
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setInitialColour(size_t chainIndex, float r, float g, float b, float a)
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- _initialColor[chainIndex].x = r;
- _initialColor[chainIndex].y = g;
- _initialColor[chainIndex].z = b;
- _initialColor[chainIndex].w = a;
- }
- //-----------------------------------------------------------------------
- const Vec4& PURibbonTrail::getInitialColour(size_t chainIndex) const
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- return _initialColor[chainIndex];
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setInitialWidth(size_t chainIndex, float width)
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- _initialWidth[chainIndex] = width;
- }
- //-----------------------------------------------------------------------
- float PURibbonTrail::getInitialWidth(size_t chainIndex) const
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- return _initialWidth[chainIndex];
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setColourChange(size_t chainIndex, const Vec4& valuePerSecond)
- {
- setColourChange(chainIndex,
- valuePerSecond.x, valuePerSecond.y, valuePerSecond.z, valuePerSecond.w);
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setColourChange(size_t chainIndex, float r, float g, float b, float a)
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- _deltaColor[chainIndex].x = r;
- _deltaColor[chainIndex].y = g;
- _deltaColor[chainIndex].z = b;
- _deltaColor[chainIndex].w = a;
- manageController();
- }
- //-----------------------------------------------------------------------
- const Vec4& PURibbonTrail::getColourChange(size_t chainIndex) const
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- return _deltaColor[chainIndex];
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::setWidthChange(size_t chainIndex, float widthDeltaPerSecond)
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- _deltaWidth[chainIndex] = widthDeltaPerSecond;
- manageController();
- }
- //-----------------------------------------------------------------------
- float PURibbonTrail::getWidthChange(size_t chainIndex) const
- {
- CCASSERT(chainIndex < _chainCount, "chainIndex out of bounds");
- return _deltaWidth[chainIndex];
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::manageController(void)
- {
- _needTimeUpdate = false;
- for (size_t i = 0; i < _chainCount; ++i)
- {
- if (_deltaWidth[i] != 0 || _deltaColor[i] != Vec4::ZERO)
- {
- _needTimeUpdate = true;
- break;
- }
- }
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::nodeUpdated(const Node* node)
- {
- size_t chainIndex = getChainIndexForNode(node);
- updateTrail(chainIndex, node);
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::nodeDestroyed(const Node* node)
- {
- removeNode(const_cast<Node*>(node));
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::updateTrail(size_t index, const Node* node)
- {
- // Repeat this entire process if chain is stretched beyond its natural length
- bool done = false;
- while (!done)
- {
- // Node has changed somehow, we're only interested in the derived position
- ChainSegment& seg = _chainSegmentList[index];
- Element& headElem = _chainElementList[seg.start + seg.head];
- size_t nextElemIdx = seg.head + 1;
- // wrap
- if (nextElemIdx == _maxElementsPerChain)
- nextElemIdx = 0;
- Element& nextElem = _chainElementList[seg.start + nextElemIdx];
- // Vary the head elem, but bake new version if that exceeds element len
- Vec3 newPos = node->getPosition3D();
- if (_parentNode)
- {
- // Transform position to ourself space
- _parentNode->getWorldToNodeTransform().transformPoint(newPos, &newPos);
- }
- Vec3 diff = newPos - nextElem.position;
- float sqlen = diff.lengthSquared();
- if (sqlen >= _squaredElemLength)
- {
- // Move existing head to mElemLength
- Vec3 scaledDiff = diff * (_elemLength / sqrtf(sqlen));
- headElem.position = nextElem.position + scaledDiff;
- // Add a new element to be the new head
- Element newElem( newPos, _initialWidth[index], 0.0f,
- _initialColor[index], node->getRotationQuat() );
- addChainElement(index, newElem);
- // alter diff to represent new head size
- diff = newPos - headElem.position;
- // check whether another step is needed or not
- if (diff.lengthSquared() <= _squaredElemLength)
- done = true;
- }
- else
- {
- // Extend existing head
- headElem.position = newPos;
- done = true;
- }
- // Is this segment full?
- if ((seg.tail + 1) % _maxElementsPerChain == seg.head)
- {
- // If so, shrink tail gradually to match head extension
- Element& tailElem = _chainElementList[seg.start + seg.tail];
- size_t preTailIdx;
- if (seg.tail == 0)
- preTailIdx = _maxElementsPerChain - 1;
- else
- preTailIdx = seg.tail - 1;
- Element& preTailElem = _chainElementList[seg.start + preTailIdx];
- // Measure tail diff from pretail to tail
- Vec3 taildiff = tailElem.position - preTailElem.position;
- float taillen = taildiff.length();
- if (taillen > 1e-06)
- {
- float tailsize = _elemLength - diff.length();
- taildiff *= tailsize / taillen;
- tailElem.position = preTailElem.position + taildiff;
- }
- }
- } // end while
- _vertexContentDirty = true;
- // Need to dirty the parent node, but can't do it using needUpdate() here
- // since we're in the middle of the scene graph update (node listener),
- // so re-entrant calls don't work. Queue.
- //if (mParentNode)
- //{
- // Node::queueNeedUpdate(getParentSceneNode());
- //}
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::timeUpdate(float time)
- {
- // Apply all segment effects
- for (size_t s = 0; s < _chainSegmentList.size(); ++s)
- {
- ChainSegment& seg = _chainSegmentList[s];
- if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
- {
- for(size_t e = seg.head + 1;; ++e) // until break
- {
- e = e % _maxElementsPerChain;
- Element& elem = _chainElementList[seg.start + e];
- elem.width = elem.width - (time * _deltaWidth[s]);
- elem.width = 0.0f < elem.width? elem.width: 0.0f;
- elem.color = elem.color - (_deltaColor[s] * time);
- elem.color.clamp(Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 1.0f));
- if (e == seg.tail)
- break;
- }
- }
- }
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::resetTrail(size_t index, const Node* node)
- {
- assert(index < _chainCount);
- ChainSegment& seg = _chainSegmentList[index];
- // set up this segment
- seg.head = seg.tail = SEGMENT_EMPTY;
- // Create new element, v coord is always 0.0f
- // need to convert to take parent node's position into account
- Vec3 position = node->getPosition3D();
- if (_parentNode)
- {
- // Transform position to ourself space
- _parentNode->getWorldToNodeTransform().transformPoint(position, &position);
- }
- Element e(position,
- _initialWidth[index], 0.0f, _initialColor[index], node->getRotationQuat());
- // Add the start position
- addChainElement(index, e);
- // Add another on the same spot, this will extend
- addChainElement(index, e);
- }
- //-----------------------------------------------------------------------
- void PURibbonTrail::resetAllTrails(void)
- {
- for (size_t i = 0; i < _nodeList.size(); ++i)
- {
- resetTrail(i, _nodeList[i]);
- }
- }
- void PURibbonTrail::update( float deltaTime )
- {
- if (_needTimeUpdate){
- static float lastUpdateTime = 0.0f;
- if (0.5f < lastUpdateTime){
- timeUpdate(deltaTime);
- lastUpdateTime = 0.0f;
- }
- lastUpdateTime += deltaTime;
- }
- for (auto iter : _nodeToSegMap){
- updateTrail(iter.second, iter.first);
- }
- }
- NS_CC_END
|