2
0

ribbon.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2014 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/consoleTypes.h"
  23. #include "console/typeValidators.h"
  24. #include "core/stream/bitStream.h"
  25. #include "T3D/shapeBase.h"
  26. #include "ts/tsShapeInstance.h"
  27. #include "T3D/fx/ribbon.h"
  28. #include "math/mathUtils.h"
  29. #include "math/mathIO.h"
  30. #include "sim/netConnection.h"
  31. #include "gfx/primBuilder.h"
  32. #include "gfx/gfxDrawUtil.h"
  33. #include "materials/sceneData.h"
  34. #include "materials/matInstance.h"
  35. #include "gui/3d/guiTSControl.h"
  36. #include "materials/materialManager.h"
  37. #include "materials/processedShaderMaterial.h"
  38. #include "gfx/gfxTransformSaver.h"
  39. IMPLEMENT_CO_DATABLOCK_V1(RibbonData);
  40. IMPLEMENT_CO_NETOBJECT_V1(Ribbon);
  41. //--------------------------------------------------------------------------
  42. //
  43. RibbonData::RibbonData()
  44. {
  45. for (U8 i = 0; i < NumFields; i++) {
  46. mSizes[i] = 0.0f;
  47. mColours[i].set(0.0f, 0.0f, 0.0f, 1.0f);
  48. mTimes[i] = -1.0f;
  49. }
  50. mRibbonLength = 0;
  51. mUseFadeOut = false;
  52. mFadeAwayStep = 0.032f;
  53. segmentsPerUpdate = 1;
  54. mMatName = StringTable->EmptyString();
  55. mTileScale = 1.0f;
  56. mFixedTexcoords = false;
  57. mSegmentSkipAmount = 0;
  58. mTexcoordsRelativeToDistance = false;
  59. }
  60. //--------------------------------------------------------------------------
  61. void RibbonData::initPersistFields()
  62. {
  63. Parent::initPersistFields();
  64. addGroup("Ribbon");
  65. addField("size", TypeF32, Offset(mSizes, RibbonData), NumFields,
  66. "The size of the ribbon at the specified keyframe.");
  67. addField("color", TypeColorF, Offset(mColours, RibbonData), NumFields,
  68. "The colour of the ribbon at the specified keyframe.");
  69. addField("position", TypeF32, Offset(mTimes, RibbonData), NumFields,
  70. "The position of the keyframe along the lifetime of the ribbon.");
  71. addField("ribbonLength", TypeS32, Offset(mRibbonLength, RibbonData),
  72. "The amount of segments the Ribbon can maximally have in length.");
  73. addField("segmentsPerUpdate", TypeS32, Offset(segmentsPerUpdate, RibbonData),
  74. "How many segments to add each update.");
  75. addField("skipAmount", TypeS32, Offset(mSegmentSkipAmount, RibbonData),
  76. "The amount of segments to skip each update.");
  77. addField("useFadeOut", TypeBool, Offset(mUseFadeOut, RibbonData),
  78. "If true, the ribbon will fade away after deletion.");
  79. addField("fadeAwayStep", TypeF32, Offset(mFadeAwayStep, RibbonData),
  80. "How much to fade the ribbon with each update, after deletion.");
  81. addField("ribbonMaterial", TypeString, Offset(mMatName, RibbonData),
  82. "The material the ribbon uses for rendering.");
  83. addField("tileScale", TypeF32, Offset(mTileScale, RibbonData),
  84. "How much to scale each 'tile' with, where 1 means the material is stretched"
  85. "across the whole ribbon. (If TexcoordsRelativeToDistance is true, this is in meters.)");
  86. addField("fixedTexcoords", TypeBool, Offset(mFixedTexcoords, RibbonData),
  87. "If true, this prevents 'floating' texture coordinates.");
  88. addField("texcoordsRelativeToDistance", TypeBool, Offset(mTexcoordsRelativeToDistance, RibbonData),
  89. "If true, texture coordinates are scaled relative to distance, this prevents"
  90. "'stretched' textures.");
  91. endGroup("Ribbon");
  92. }
  93. //--------------------------------------------------------------------------
  94. bool RibbonData::onAdd()
  95. {
  96. if(!Parent::onAdd())
  97. return false;
  98. return true;
  99. }
  100. bool RibbonData::preload(bool server, String &errorBuffer)
  101. {
  102. if (Parent::preload(server, errorBuffer) == false)
  103. return false;
  104. return true;
  105. }
  106. //--------------------------------------------------------------------------
  107. void RibbonData::packData(BitStream* stream)
  108. {
  109. Parent::packData(stream);
  110. for (U8 i = 0; i < NumFields; i++) {
  111. stream->write(mSizes[i]);
  112. stream->write(mColours[i]);
  113. stream->write(mTimes[i]);
  114. }
  115. stream->write(mRibbonLength);
  116. stream->writeString(mMatName);
  117. stream->writeFlag(mUseFadeOut);
  118. stream->write(mFadeAwayStep);
  119. stream->write(segmentsPerUpdate);
  120. stream->write(mTileScale);
  121. stream->writeFlag(mFixedTexcoords);
  122. stream->writeFlag(mTexcoordsRelativeToDistance);
  123. }
  124. void RibbonData::unpackData(BitStream* stream)
  125. {
  126. Parent::unpackData(stream);
  127. for (U8 i = 0; i < NumFields; i++) {
  128. stream->read(&mSizes[i]);
  129. stream->read(&mColours[i]);
  130. stream->read(&mTimes[i]);
  131. }
  132. stream->read(&mRibbonLength);
  133. mMatName = StringTable->insert(stream->readSTString());
  134. mUseFadeOut = stream->readFlag();
  135. stream->read(&mFadeAwayStep);
  136. stream->read(&segmentsPerUpdate);
  137. stream->read(&mTileScale);
  138. mFixedTexcoords = stream->readFlag();
  139. mTexcoordsRelativeToDistance = stream->readFlag();
  140. }
  141. //--------------------------------------------------------------------------
  142. //--------------------------------------
  143. //
  144. Ribbon::Ribbon()
  145. {
  146. mTypeMask |= StaticObjectType;
  147. VECTOR_SET_ASSOCIATION(mSegmentPoints);
  148. mSegmentPoints.clear();
  149. mRibbonMat = NULL;
  150. mUpdateBuffers = true;
  151. mDeleteOnEnd = false;
  152. mUseFadeOut = false;
  153. mFadeAwayStep = 1.0f;
  154. mFadeOut = 1.0f;
  155. mNetFlags.clear(Ghostable);
  156. mNetFlags.set(IsGhost);
  157. mRadiusSC = NULL;
  158. mRibbonProjSC = NULL;
  159. mSegmentOffset = 0;
  160. mSegmentIdx = 0;
  161. mTravelledDistance = 0;
  162. }
  163. Ribbon::~Ribbon()
  164. {
  165. //Make sure we cleanup
  166. SAFE_DELETE(mRibbonMat);
  167. }
  168. //--------------------------------------------------------------------------
  169. void Ribbon::initPersistFields()
  170. {
  171. Parent::initPersistFields();
  172. }
  173. bool Ribbon::onAdd()
  174. {
  175. if(!Parent::onAdd())
  176. return false;
  177. // add to client side mission cleanup
  178. SimGroup *cleanup = dynamic_cast<SimGroup *>( Sim::findObject( "ClientMissionCleanup") );
  179. if( cleanup != NULL )
  180. {
  181. cleanup->addObject( this );
  182. }
  183. else
  184. {
  185. AssertFatal( false, "Error, could not find ClientMissionCleanup group" );
  186. return false;
  187. }
  188. if (!isServerObject()) {
  189. if(GFX->getPixelShaderVersion() >= 1.1 && dStrlen(mDataBlock->mMatName) > 0 )
  190. {
  191. mRibbonMat = MATMGR->createMatInstance( mDataBlock->mMatName );
  192. GFXStateBlockDesc desc;
  193. desc.setZReadWrite( true, false );
  194. desc.cullDefined = true;
  195. desc.cullMode = GFXCullNone;
  196. desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  197. desc.samplersDefined = true;
  198. GFXSamplerStateDesc sDesc(GFXSamplerStateDesc::getClampLinear());
  199. sDesc.addressModeV = GFXAddressWrap;
  200. desc.samplers[0] = sDesc;
  201. mRibbonMat->addStateBlockDesc( desc );
  202. mRibbonMat->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCNTT>());
  203. mRadiusSC = mRibbonMat->getMaterialParameterHandle( "$radius" );
  204. mRibbonProjSC = mRibbonMat->getMaterialParameterHandle( "$ribbonProj" );
  205. } else {
  206. Con::warnf( "Invalid Material name: %s: for Ribbon", mDataBlock->mMatName );
  207. #ifdef TORQUE_DEBUG
  208. Con::warnf( "- This could be caused by having the shader data datablocks in server-only code." );
  209. #endif
  210. mRibbonMat = NULL;
  211. }
  212. }
  213. mObjBox.minExtents.set( 1.0f, 1.0f, 1.0f );
  214. mObjBox.maxExtents.set( 2.0f, 2.0f, 2.0f );
  215. // Reset the World Box.
  216. resetWorldBox();
  217. // Set the Render Transform.
  218. setRenderTransform(mObjToWorld);
  219. addToScene();
  220. return true;
  221. }
  222. void Ribbon::onRemove()
  223. {
  224. removeFromScene();
  225. SAFE_DELETE(mRibbonMat);
  226. Parent::onRemove();
  227. }
  228. bool Ribbon::onNewDataBlock(GameBaseData* dptr, bool reload)
  229. {
  230. mDataBlock = dynamic_cast<RibbonData*>(dptr);
  231. if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
  232. return false;
  233. return true;
  234. }
  235. void Ribbon::processTick(const Move* move)
  236. {
  237. Parent::processTick(move);
  238. if (mDeleteOnEnd) {
  239. if (mUseFadeOut) {
  240. if (mFadeOut <= 0.0f) {
  241. mFadeOut = 0.0f;
  242. //delete this class
  243. mDeleteOnEnd = false;
  244. safeDeleteObject();
  245. return;
  246. }
  247. mFadeOut -= mFadeAwayStep;
  248. if (mFadeOut < 0.0f) {
  249. mFadeOut = 0.0f;
  250. }
  251. mUpdateBuffers = true;
  252. } else {
  253. //if (mSegmentPoints.size() == 0) {
  254. //delete this class
  255. mDeleteOnEnd = false;
  256. safeDeleteObject();
  257. return;
  258. //}
  259. //mSegmentPoints.pop_back();
  260. }
  261. }
  262. }
  263. void Ribbon::advanceTime(F32 dt)
  264. {
  265. Parent::advanceTime(dt);
  266. }
  267. void Ribbon::interpolateTick(F32 delta)
  268. {
  269. Parent::interpolateTick(delta);
  270. }
  271. void Ribbon::addSegmentPoint(Point3F &point, MatrixF &mat) {
  272. //update our position
  273. setRenderTransform(mat);
  274. MatrixF xform(true);
  275. xform.setColumn(3, point);
  276. setTransform(xform);
  277. if(mSegmentIdx < mDataBlock->mSegmentSkipAmount)
  278. {
  279. mSegmentIdx++;
  280. return;
  281. }
  282. mSegmentIdx = 0;
  283. U32 segmentsToDelete = checkRibbonDistance(mDataBlock->segmentsPerUpdate);
  284. for (U32 i = 0; i < segmentsToDelete; i++) {
  285. S32 last = mSegmentPoints.size() - 1;
  286. if (last < 0)
  287. break;
  288. mTravelledDistance += last ? (mSegmentPoints[last] - mSegmentPoints[last-1]).len() : 0;
  289. mSegmentPoints.pop_back();
  290. mUpdateBuffers = true;
  291. mSegmentOffset++;
  292. }
  293. //If there is no other points, just add a new one.
  294. if (mSegmentPoints.size() == 0) {
  295. mSegmentPoints.push_front(point);
  296. mUpdateBuffers = true;
  297. return;
  298. }
  299. Point3F startPoint = mSegmentPoints[0];
  300. //add X points based on how many segments Per Update from last point to current point
  301. for (U32 i = 0; i < mDataBlock->segmentsPerUpdate; i++) {
  302. F32 interp = (F32(i+1) / (F32)mDataBlock->segmentsPerUpdate);
  303. //(end - start) * percentage) + start
  304. Point3F derivedPoint = ((point - startPoint) * interp) + startPoint;
  305. mSegmentPoints.push_front(derivedPoint);
  306. mUpdateBuffers = true;
  307. }
  308. if (mSegmentPoints.size() > 1) {
  309. Point3F pointA = mSegmentPoints[mSegmentPoints.size()-1];
  310. Point3F pointB = mSegmentPoints[0];
  311. Point3F diffSize = pointA - pointB;
  312. if (diffSize.x == 0.0f)
  313. diffSize.x = 1.0f;
  314. if (diffSize.y == 0.0f)
  315. diffSize.y = 1.0f;
  316. if (diffSize.z == 0.0f)
  317. diffSize.z = 1.0f;
  318. Box3F objBox;
  319. objBox.minExtents.set( diffSize * -1 );
  320. objBox.maxExtents.set( diffSize );
  321. if (objBox.minExtents.x > objBox.maxExtents.x) {
  322. F32 tmp = objBox.minExtents.x;
  323. objBox.minExtents.x = objBox.maxExtents.x;
  324. objBox.maxExtents.x = tmp;
  325. }
  326. if (objBox.minExtents.y > objBox.maxExtents.y) {
  327. F32 tmp = objBox.minExtents.y;
  328. objBox.minExtents.y = objBox.maxExtents.y;
  329. objBox.maxExtents.y = tmp;
  330. }
  331. if (objBox.minExtents.z > objBox.maxExtents.z) {
  332. F32 tmp = objBox.minExtents.z;
  333. objBox.minExtents.z = objBox.maxExtents.z;
  334. objBox.maxExtents.z = tmp;
  335. }
  336. if (objBox.isValidBox()) {
  337. mObjBox = objBox;
  338. // Reset the World Box.
  339. resetWorldBox();
  340. }
  341. }
  342. }
  343. void Ribbon::deleteOnEnd() {
  344. mDeleteOnEnd = true;
  345. mUseFadeOut = mDataBlock->mUseFadeOut;
  346. mFadeAwayStep = mDataBlock->mFadeAwayStep;
  347. }
  348. U32 Ribbon::checkRibbonDistance(S32 segments) {
  349. S32 len = mSegmentPoints.size();
  350. S32 difference = (mDataBlock->mRibbonLength/(mDataBlock->mSegmentSkipAmount+1)) - len;
  351. if (difference < 0)
  352. return mAbs(difference);
  353. return 0; //do not delete any points
  354. }
  355. void Ribbon::setShaderParams() {
  356. F32 numSegments = (F32)mSegmentPoints.size();
  357. F32 length = (F32)mDataBlock->mRibbonLength;
  358. Point3F radius(numSegments / length, numSegments, length);
  359. MaterialParameters* matParams = mRibbonMat->getMaterialParameters();
  360. matParams->setSafe( mRadiusSC, radius );
  361. }
  362. //--------------------------------------------------------------------------
  363. //U32 Ribbon::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
  364. //{
  365. // U32 retMask = Parent::packUpdate(con, mask, stream);
  366. // return retMask;
  367. //}
  368. //
  369. //void Ribbon::unpackUpdate(NetConnection* con, BitStream* stream)
  370. //{
  371. // Parent::unpackUpdate(con, stream);
  372. //}
  373. //--------------------------------------------------------------------------
  374. void Ribbon::prepRenderImage(SceneRenderState *state)
  375. {
  376. if (mFadeOut == 0.0f)
  377. return;
  378. if(!mRibbonMat)
  379. return;
  380. if (mDeleteOnEnd == true && mUseFadeOut == false) {
  381. return;
  382. }
  383. // We only render during the normal diffuse render pass.
  384. if( !state->isDiffusePass() )
  385. return;
  386. U32 segments = mSegmentPoints.size();
  387. if (segments < 2)
  388. return;
  389. MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>();
  390. ri->type = RenderPassManager::RIT_Translucent;
  391. ri->translucentSort = true;
  392. ri->sortDistSq = ( mSegmentPoints[0] - state->getCameraPosition() ).lenSquared();
  393. RenderPassManager *renderPass = state->getRenderPass();
  394. MatrixF *proj = renderPass->allocUniqueXform(MatrixF( true ));
  395. proj->mul(GFX->getProjectionMatrix());
  396. proj->mul(GFX->getWorldMatrix());
  397. ri->objectToWorld = &MatrixF::Identity;
  398. ri->worldToCamera = &MatrixF::Identity;
  399. ri->projection = proj;
  400. ri->matInst = mRibbonMat;
  401. // Set up our vertex buffer and primitive buffer
  402. if(mUpdateBuffers)
  403. createBuffers(state, verts, primBuffer, segments);
  404. ri->vertBuff = &verts;
  405. ri->primBuff = &primBuffer;
  406. ri->visibility = 1.0f;
  407. ri->prim = renderPass->allocPrim();
  408. ri->prim->type = GFXTriangleList;
  409. ri->prim->minIndex = 0;
  410. ri->prim->startIndex = 0;
  411. ri->prim->numPrimitives = (segments-1) * 2;
  412. ri->prim->startVertex = 0;
  413. ri->prim->numVertices = segments * 2;
  414. if (mRibbonMat) {
  415. ri->defaultKey = mRibbonMat->getStateHint();
  416. } else {
  417. ri->defaultKey = 1;
  418. }
  419. ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
  420. state->getRenderPass()->addInst(ri);
  421. }
  422. void Ribbon::createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVertexPCNTT> &verts, GFXPrimitiveBufferHandle &pb, U32 segments) {
  423. PROFILE_SCOPE( Ribbon_createBuffers );
  424. Point3F cameraPos = state->getCameraPosition();
  425. U32 count = 0;
  426. U32 indexCount = 0;
  427. verts.set(GFX, (segments*2), GFXBufferTypeDynamic);
  428. // create index buffer based on that size
  429. U32 indexListSize = (segments-1) * 6;
  430. pb.set( GFX, indexListSize, 0, GFXBufferTypeDynamic );
  431. U16 *indices = NULL;
  432. verts.lock();
  433. pb.lock( &indices );
  434. F32 totalLength = 0;
  435. if(mDataBlock->mTexcoordsRelativeToDistance)
  436. {
  437. for (U32 i = 0; i < segments; i++)
  438. if (i != 0)
  439. totalLength += (mSegmentPoints[i] - mSegmentPoints[i-1]).len();
  440. }
  441. U8 fixedAppend = 0;
  442. F32 curLength = 0;
  443. for (U32 i = 0; i < segments; i++) {
  444. F32 interpol = ((F32)i / (F32)(segments-1));
  445. Point3F leftvert = mSegmentPoints[i];
  446. Point3F rightvert = mSegmentPoints[i];
  447. F32 tRadius = mDataBlock->mSizes[0];
  448. ColorF tColor = mDataBlock->mColours[0];
  449. for (U8 j = 0; j < RibbonData::NumFields-1; j++) {
  450. F32 curPosition = mDataBlock->mTimes[j];
  451. F32 curRadius = mDataBlock->mSizes[j];
  452. ColorF curColor = mDataBlock->mColours[j];
  453. F32 nextPosition = mDataBlock->mTimes[j+1];
  454. F32 nextRadius = mDataBlock->mSizes[j+1];
  455. ColorF nextColor = mDataBlock->mColours[j+1];
  456. if ( curPosition < 0
  457. || curPosition > interpol )
  458. break;
  459. F32 positionDiff = (interpol - curPosition) / (nextPosition - curPosition);
  460. tRadius = curRadius + (nextRadius - curRadius) * positionDiff;
  461. tColor.interpolate(curColor, nextColor, positionDiff);
  462. }
  463. Point3F diff;
  464. F32 length;
  465. if (i == 0) {
  466. diff = mSegmentPoints[i+1] - mSegmentPoints[i];
  467. length = 0;
  468. } else if (i == segments-1) {
  469. diff = mSegmentPoints[i] - mSegmentPoints[i-1];
  470. length = diff.len();
  471. } else {
  472. diff = mSegmentPoints[i+1] - mSegmentPoints[i-1];
  473. length = (mSegmentPoints[i] - mSegmentPoints[i-1]).len();
  474. }
  475. //left point
  476. Point3F eyeMinPos = cameraPos - leftvert;
  477. Point3F perpendicular = mCross(diff, eyeMinPos);
  478. perpendicular.normalize();
  479. perpendicular = perpendicular * tRadius * -1.0f;
  480. perpendicular += mSegmentPoints[i];
  481. verts[count].point.set(perpendicular);
  482. ColorF color = tColor;
  483. if (mDataBlock->mUseFadeOut)
  484. color.alpha *= mFadeOut;
  485. F32 texCoords;
  486. if(mDataBlock->mFixedTexcoords && !mDataBlock->mTexcoordsRelativeToDistance)
  487. {
  488. U32 fixedIdx = (i+mDataBlock->mRibbonLength-mSegmentOffset)%mDataBlock->mRibbonLength;
  489. if(fixedIdx == 0 && i > 0)
  490. fixedAppend++;
  491. F32 fixedInterpol = (F32)fixedIdx / (F32)(mDataBlock->mRibbonLength);
  492. fixedInterpol += fixedAppend;
  493. texCoords = (1.0f - fixedInterpol)*mDataBlock->mTileScale;
  494. }
  495. else if(mDataBlock->mTexcoordsRelativeToDistance)
  496. texCoords = (mTravelledDistance + (totalLength - (curLength + length)))*mDataBlock->mTileScale;
  497. else
  498. texCoords = (1.0f - interpol)*mDataBlock->mTileScale;
  499. verts[count].color = color;
  500. verts[count].texCoord[1] = Point2F(interpol, 0);
  501. verts[count].texCoord[0] = Point2F(0.0f, texCoords);
  502. verts[count].normal.set(diff);
  503. //Triangle strip style indexing, so grab last 2
  504. if (count > 1) {
  505. indices[indexCount] = count-2;
  506. indexCount++;
  507. indices[indexCount] = count;
  508. indexCount++;
  509. indices[indexCount] = count-1;
  510. indexCount++;
  511. }
  512. count++;
  513. eyeMinPos = cameraPos - rightvert;
  514. perpendicular = mCross(diff, eyeMinPos);
  515. perpendicular.normalize();
  516. perpendicular = perpendicular * tRadius;
  517. perpendicular += mSegmentPoints[i];
  518. verts[count].point.set(perpendicular);
  519. color = tColor;
  520. if (mDataBlock->mUseFadeOut)
  521. color.alpha *= mFadeOut;
  522. verts[count].color = color;
  523. verts[count].texCoord[1] = Point2F(interpol, 1);
  524. verts[count].texCoord[0] = Point2F(1.0f, texCoords);
  525. verts[count].normal.set(diff);
  526. //Triangle strip style indexing, so grab last 2
  527. if (count > 1) {
  528. indices[indexCount] = count-2;
  529. indexCount++;
  530. indices[indexCount] = count-1;
  531. indexCount++;
  532. indices[indexCount] = count;
  533. indexCount++;
  534. }
  535. count++;
  536. curLength += length;
  537. }
  538. Point3F pointA = verts[count-1].point;
  539. Point3F pointB = verts[0].point;
  540. pb.unlock();
  541. verts.unlock();
  542. Point3F diffSize = pointA - pointB;
  543. Box3F objBox;
  544. objBox.minExtents.set( diffSize * -1 );
  545. objBox.maxExtents.set( diffSize );
  546. if (objBox.minExtents.x > objBox.maxExtents.x) {
  547. F32 tmp = objBox.minExtents.x;
  548. objBox.minExtents.x = objBox.maxExtents.x;
  549. objBox.maxExtents.x = tmp;
  550. }
  551. if (objBox.minExtents.y > objBox.maxExtents.y) {
  552. F32 tmp = objBox.minExtents.y;
  553. objBox.minExtents.y = objBox.maxExtents.y;
  554. objBox.maxExtents.y = tmp;
  555. }
  556. if (objBox.minExtents.z > objBox.maxExtents.z) {
  557. F32 tmp = objBox.minExtents.z;
  558. objBox.minExtents.z = objBox.maxExtents.z;
  559. objBox.maxExtents.z = tmp;
  560. }
  561. if (objBox.isValidBox()) {
  562. mObjBox = objBox;
  563. // Reset the World Box.
  564. resetWorldBox();
  565. }
  566. mUpdateBuffers = false;
  567. }