ribbon.cpp 20 KB

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