ribbon.cpp 20 KB

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