gizmo.cpp 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 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 "platform/platform.h"
  23. #include "gui/worldEditor/gizmo.h"
  24. #include "console/consoleTypes.h"
  25. #include "gfx/primBuilder.h"
  26. #include "gfx/gfxTransformSaver.h"
  27. #include "gfx/util/gfxFrustumSaver.h"
  28. #include "gfx/gfxDrawUtil.h"
  29. #include "T3D/gameBase/gameConnection.h"
  30. //#include "math/mathUtils.h"
  31. using namespace MathUtils;
  32. // Developer Notes:
  33. // How to... Calculate the SelectionAxis index representing the normal
  34. // of a plane, given a SelectionPlane index
  35. // normal = axisVector[2 - (planeIdx - 3 )];
  36. // How to... Get the two AxisVectors of a selected plane
  37. // vec0 = mProjAxisVector[mAxisGizmoPlanarVectors[mSelectionIdx-3][0]];
  38. // vec1 = mProjAxisVector[mAxisGizmoPlanarVectors[mSelectionIdx-3][1]];
  39. ImplementEnumType(GizmoAlignment,
  40. "Whether the gizmo should be aligned with the world, or with the object.\n"
  41. "@internal\n\n")
  42. { World, "World", "Align the gizmo with the world.\n" },
  43. { Object, "Object", "Align the gizmo with the object.\n" }
  44. EndImplementEnumType;
  45. ImplementEnumType( GizmoMode,
  46. "@internal" )
  47. { NoneMode, "None" },
  48. { MoveMode, "Move" },
  49. { RotateMode, "Rotate" },
  50. { ScaleMode, "Scale" }
  51. EndImplementEnumType;
  52. //-------------------------------------------------------------------------
  53. // Unnamed namespace for static data
  54. //-------------------------------------------------------------------------
  55. namespace {
  56. static S32 sgAxisRemap[3][3] = {
  57. {0, 1, 2},
  58. {2, 0, 1},
  59. {1, 2, 0},
  60. };
  61. static VectorF sgAxisVectors[3] = {
  62. VectorF(1.0f,0.0f,0.0f),
  63. VectorF(0.0f,1.0f,0.0f),
  64. VectorF(0.0f,0.0f,1.0f)
  65. };
  66. static U32 sgPlanarVectors[3][2] = {
  67. { 0, 1 }, // XY
  68. { 0, 2 }, // XZ
  69. { 1, 2 } // YZ
  70. };
  71. static Point3F sgBoxPnts[] = {
  72. Point3F(0.0f,0.0f,0.0f),
  73. Point3F(0.0f,0.0f,1.0f),
  74. Point3F(0.0f,1.0f,0.0f),
  75. Point3F(0.0f,1.0f,1.0f),
  76. Point3F(1.0f,0.0f,0.0f),
  77. Point3F(1.0f,0.0f,1.0f),
  78. Point3F(1.0f,1.0f,0.0f),
  79. Point3F(1.0f,1.0f,1.0f)
  80. };
  81. static U32 sgBoxVerts[][4] = {
  82. {0,2,3,1}, // -x
  83. {7,6,4,5}, // +x
  84. {0,1,5,4}, // -y
  85. {3,2,6,7}, // +y
  86. {0,4,6,2}, // -z
  87. {3,7,5,1} // +z
  88. };
  89. static Point3F sgBoxNormals[] = {
  90. Point3F(-1.0f, 0.0f, 0.0f),
  91. Point3F( 1.0f, 0.0f, 0.0f),
  92. Point3F( 0.0f,-1.0f, 0.0f),
  93. Point3F( 0.0f, 1.0f, 0.0f),
  94. Point3F( 0.0f, 0.0f,-1.0f),
  95. Point3F( 0.0f, 0.0f, 1.0f)
  96. };
  97. static Point3F sgConePnts[] = {
  98. Point3F(0.0f, 0.0f, 0.0f),
  99. Point3F(-1.0f, 0.0f, -0.25f),
  100. Point3F(-1.0f, -0.217f, -0.125f),
  101. Point3F(-1.0f, -0.217f, 0.125f),
  102. Point3F(-1.0f, 0.0f, 0.25f),
  103. Point3F(-1.0f, 0.217f, 0.125f),
  104. Point3F(-1.0f, 0.217f, -0.125f),
  105. Point3F(-1.0f, 0.0f, 0.0f)
  106. };
  107. static U32 sgConeVerts[][3] = {
  108. {0, 2, 1},
  109. {0, 3, 2},
  110. {0, 4, 3},
  111. {0, 5, 4},
  112. {0, 6, 5},
  113. {0, 1, 6},
  114. {7, 1, 6}, // Base
  115. {7, 6, 5},
  116. {7, 5, 4},
  117. {7, 4, 3},
  118. {7, 3, 2},
  119. {7, 2, 1}
  120. };
  121. static Point3F sgCenterBoxPnts[] = {
  122. Point3F(-0.5f, -0.5f, -0.5f),
  123. Point3F(-0.5f, -0.5f, 0.5f),
  124. Point3F(-0.5f, 0.5f, -0.5f),
  125. Point3F(-0.5f, 0.5f, 0.5f),
  126. Point3F( 0.5f, -0.5f, -0.5f),
  127. Point3F( 0.5f, -0.5f, 0.5f),
  128. Point3F( 0.5f, 0.5f, -0.5f),
  129. Point3F( 0.5f, 0.5f, 0.5f)
  130. };
  131. static Point3F sgCirclePnts[] = {
  132. Point3F(0.0f, 0.0f, -0.5f),
  133. Point3F(0.0f, 0.354f, -0.354f),
  134. Point3F(0.0f, 0.5f, 0),
  135. Point3F(0.0f, 0.354f, 0.354f),
  136. Point3F(0.0f, 0.0f, 0.5f),
  137. Point3F(0.0f, -0.354f, 0.354f),
  138. Point3F(0.0f, -0.5f, 0),
  139. Point3F(0.0f, -0.354f, -0.354f),
  140. Point3F(0.0f, 0.0f, -0.5f),
  141. };
  142. }
  143. //-------------------------------------------------------------------------
  144. // GizmoProfile Class
  145. //-------------------------------------------------------------------------
  146. GizmoProfile::GizmoProfile()
  147. {
  148. mode = MoveMode;
  149. alignment = World;
  150. screenLen = 100;
  151. renderWhenUsed = false;
  152. renderInfoText = true;
  153. renderPlane = true;
  154. renderPlaneHashes = true;
  155. renderSolid = false;
  156. renderMoveGrid = true;
  157. gridColor.set(255,255,255,20);
  158. planeDim = 500.0f;
  159. gridSize.set(1,1,1);
  160. snapToGrid = false;
  161. allowSnapRotations = true;
  162. rotationSnap = 15.0f;
  163. allowSnapScale = true;
  164. scaleSnap = 0.1f;
  165. forceSnapRotations = false;
  166. rotateScalar = 0.8f;
  167. scaleScalar = 0.8f;
  168. axisColors[0].set( 255, 0, 0 );
  169. axisColors[1].set( 0, 255, 0 );
  170. axisColors[2].set( 0, 0, 255 );
  171. activeColor.set( 237, 219, 0 );
  172. inActiveColor.set( 170, 170, 170 );
  173. centroidColor.set( 255, 255, 255 );
  174. centroidHighlightColor.set( 255, 0, 255 );
  175. hideDisabledAxes = true;
  176. restoreDefaultState();
  177. }
  178. void GizmoProfile::restoreDefaultState()
  179. {
  180. flags = U32_MAX;
  181. flags &= ~CanRotateUniform;
  182. allAxesScaleUniform = false;
  183. }
  184. IMPLEMENT_CONOBJECT( GizmoProfile );
  185. ConsoleDocClass( GizmoProfile,
  186. "@brief This class contains behavior and rendering properties used "
  187. "by the Gizmo class\n\n"
  188. "Not intended for game development, for editors or internal use only.\n\n "
  189. "@internal");
  190. bool GizmoProfile::onAdd()
  191. {
  192. if ( !Parent::onAdd() )
  193. return false;
  194. const char* fontCacheDirectory = Con::getVariable("$GUI::fontCacheDirectory");
  195. font = GFont::create( "Arial", 10, fontCacheDirectory, TGE_ANSI_CHARSET);
  196. if ( !font )
  197. {
  198. Con::errorf( "GizmoProfile::onAdd - failed to load font!" );
  199. return false;
  200. }
  201. return true;
  202. }
  203. void GizmoProfile::initPersistFields()
  204. {
  205. addField( "alignment", TYPEID< GizmoAlignment >(), Offset(alignment, GizmoProfile ) );
  206. addField( "mode", TYPEID< GizmoMode >(), Offset(mode, GizmoProfile ) );
  207. addField( "snapToGrid", TypeBool, Offset(snapToGrid, GizmoProfile) );
  208. addField( "allowSnapRotations", TypeBool, Offset(allowSnapRotations, GizmoProfile) );
  209. addField( "rotationSnap", TypeF32, Offset(rotationSnap, GizmoProfile) );
  210. addField( "allowSnapScale", TypeBool, Offset(allowSnapScale, GizmoProfile) );
  211. addField( "scaleSnap", TypeF32, Offset(scaleSnap, GizmoProfile) );
  212. addField( "forceSnapRotations", TypeBool, Offset(forceSnapRotations, GizmoProfile));
  213. addField( "renderWhenUsed", TypeBool, Offset(renderWhenUsed, GizmoProfile) );
  214. addField( "renderInfoText", TypeBool, Offset(renderInfoText, GizmoProfile) );
  215. addField( "renderPlane", TypeBool, Offset(renderPlane, GizmoProfile) );
  216. addField( "renderPlaneHashes", TypeBool, Offset(renderPlaneHashes, GizmoProfile) );
  217. addField( "renderSolid", TypeBool, Offset(renderSolid, GizmoProfile) );
  218. addField( "renderMoveGrid", TypeBool, Offset( renderMoveGrid, GizmoProfile ) );
  219. addField( "gridColor", TypeColorI, Offset(gridColor, GizmoProfile) );
  220. addField( "planeDim", TypeF32, Offset(planeDim, GizmoProfile) );
  221. addField( "gridSize", TypePoint3F, Offset(gridSize, GizmoProfile) );
  222. addField( "screenLength", TypeS32, Offset(screenLen, GizmoProfile) );
  223. addField( "rotateScalar", TypeF32, Offset(rotateScalar, GizmoProfile) );
  224. addField( "scaleScalar", TypeF32, Offset(scaleScalar, GizmoProfile) );
  225. addField( "flags", TypeS32, Offset(flags, GizmoProfile) );
  226. }
  227. void GizmoProfile::consoleInit()
  228. {
  229. Parent::consoleInit();
  230. Con::setIntVariable( "$GizmoFlag::CanRotate", CanRotate );
  231. Con::setIntVariable( "$GizmoFlag::CanRotateX", CanRotateX );
  232. Con::setIntVariable( "$GizmoFlag::CanRotateY", CanRotateY );
  233. Con::setIntVariable( "$GizmoFlag::CanRotateZ", CanRotateZ );
  234. Con::setIntVariable( "$GizmoFlag::CanRotateScreen", CanRotateScreen );
  235. Con::setIntVariable( "$GizmoFlag::CanRotateUniform", CanRotateUniform );
  236. Con::setIntVariable( "$GizmoFlag::CanScale", CanScale );
  237. Con::setIntVariable( "$GizmoFlag::CanScaleX", CanScaleX );
  238. Con::setIntVariable( "$GizmoFlag::CanScaleY", CanScaleY );
  239. Con::setIntVariable( "$GizmoFlag::CanScaleZ", CanScaleZ );
  240. Con::setIntVariable( "$GizmoFlag::CanScaleUniform", CanScaleUniform );
  241. Con::setIntVariable( "$GizmoFlag::CanTranslate", CanTranslate );
  242. Con::setIntVariable( "$GizmoFlag::CanTranslateX", CanTranslateX );
  243. Con::setIntVariable( "$GizmoFlag::CanTranslateY", CanTranslateY );
  244. Con::setIntVariable( "$GizmoFlag::CanTranslateZ", CanTranslateZ );
  245. Con::setIntVariable( "$GizmoFlag::CanTranslateUniform", CanTranslateUniform );
  246. Con::setIntVariable( "$GizmoFlag::PlanarHandlesOn", PlanarHandlesOn );
  247. }
  248. //-------------------------------------------------------------------------
  249. // Gizmo Class
  250. //-------------------------------------------------------------------------
  251. F32 Gizmo::smProjectDistance = 20000.0f;
  252. Gizmo::Gizmo()
  253. : mProfile( NULL ),
  254. mObjectMat( true ),
  255. mTransform( true ),
  256. mCameraMat( true ),
  257. mProjLen(1000.0f),
  258. mSelectionIdx( -1 ),
  259. mObjectMatInv( true ),
  260. mCurrentTransform( true ),
  261. mSavedTransform( true ),
  262. mSavedScale( 0,0,0 ),
  263. mDeltaScale( 0,0,0 ),
  264. mDeltaRot( 0,0,0 ),
  265. mDeltaPos( 0,0,0 ),
  266. mCurrentAlignment( World ),
  267. mDeltaTotalScale( 0,0,0 ),
  268. mDeltaTotalRot( 0,0,0 ),
  269. mDeltaAngle(0.0f),
  270. mLastAngle(0.0f),
  271. mDeltaTotalPos( 0,0,0 ),
  272. mCurrentMode( MoveMode ),
  273. mMouseDownPos( -1,-1 ),
  274. mDirty( false ),
  275. mSign(0.0f),
  276. mMouseDown( false ),
  277. mLastWorldMat( true ),
  278. mLastProjMat( true ),
  279. mLastViewport( 0, 0, 10, 10 ),
  280. mLastCameraFOV( 1.f ),
  281. mHighlightCentroidHandle( false ),
  282. mElipseCursorCollidePntSS( 0.0f, 0.0f, 0.0f ),
  283. mElipseCursorCollideVecSS( 1.0f, 0.0f, 0.0f ),
  284. mGridPlaneEnabled( true ),
  285. mHighlightAll( false ),
  286. mMoveGridEnabled( true ),
  287. mMoveGridSize( 20.f ),
  288. mMoveGridSpacing( 1.f ),
  289. mUniformHandleEnabled(true),
  290. mScreenRotateHandleEnabled(false)
  291. {
  292. mAxisEnabled[0] = mAxisEnabled[1] = mAxisEnabled[2] = true;
  293. }
  294. Gizmo::~Gizmo()
  295. {
  296. }
  297. IMPLEMENT_CONOBJECT( Gizmo );
  298. ConsoleDocClass( Gizmo,
  299. "@brief This class contains code for rendering and manipulating a 3D gizmo\n\n"
  300. "It is usually used as a helper within a TSEdit-derived control. "
  301. "Not intended for game development, for editors or internal use only.\n\n "
  302. "@internal");
  303. // SimObject Methods...
  304. bool Gizmo::onAdd()
  305. {
  306. if ( !Parent::onAdd() )
  307. return false;
  308. if ( !mProfile )
  309. return false;
  310. mCurrentAlignment = mProfile->alignment;
  311. mCurrentMode = mProfile->mode;
  312. return true;
  313. }
  314. void Gizmo::onRemove()
  315. {
  316. Parent::onRemove();
  317. }
  318. void Gizmo::initPersistFields()
  319. {
  320. Parent::initPersistFields();
  321. //addField( "profile",)
  322. }
  323. // Gizmo Accessors and Mutators...
  324. void Gizmo::set( const MatrixF &objMat, const Point3F &worldPos, const Point3F &objScale )
  325. {
  326. if ( mMouseDown )
  327. return;
  328. mCurrentAlignment = _filteredAlignment();
  329. if ( mCurrentAlignment == World )
  330. {
  331. mTransform.identity();
  332. mTransform.setPosition( worldPos );
  333. mScale = objScale;
  334. mObjectMat = objMat;
  335. }
  336. else
  337. {
  338. mTransform = objMat;
  339. mTransform.setPosition( worldPos );
  340. mScale = objScale;
  341. mObjectMat.identity();
  342. }
  343. mCurrentTransform = objMat;
  344. mObjectMat.invertTo( &mObjectMatInv );
  345. }
  346. Gizmo::Selection Gizmo::getSelection()
  347. {
  348. if ( mProfile->mode == NoneMode )
  349. return None;
  350. return (Selection)mSelectionIdx;
  351. }
  352. VectorF Gizmo::selectionToAxisVector( Selection axis )
  353. {
  354. if ( axis < Axis_X || axis > Axis_Z )
  355. return VectorF(0,0,0);
  356. return sgAxisVectors[(U32)axis];
  357. }
  358. bool Gizmo::collideAxisGizmo( const Gui3DMouseEvent & event )
  359. {
  360. if ( mProfile->mode == NoneMode )
  361. return false;
  362. _calcAxisInfo();
  363. // Early out if we are in a mode that is disabled.
  364. if ( mProfile->mode == RotateMode && !(mProfile->flags & GizmoProfile::CanRotate ) )
  365. return false;
  366. if ( mProfile->mode == MoveMode && !(mProfile->flags & GizmoProfile::CanTranslate ) )
  367. return false;
  368. if ( mProfile->mode == ScaleMode && !(mProfile->flags & GizmoProfile::CanScale ) )
  369. return false;
  370. VectorF camPos;
  371. if( GFX->isFrustumOrtho() )
  372. camPos = event.pos;
  373. else
  374. camPos = mCameraPos;
  375. VectorF toGizmoVec;
  376. // get the projected size...
  377. toGizmoVec = mOrigin - mCameraPos;
  378. toGizmoVec.normalizeSafe();
  379. PlaneF clipPlane( mOrigin, toGizmoVec );
  380. mSelectionIdx = -1;
  381. Point3F end = camPos + event.vec * smProjectDistance;
  382. if ( mProfile->mode == RotateMode )
  383. {
  384. const Point3F mousePntSS( (F32)event.mousePoint.x, (F32)event.mousePoint.y, 0.0f );
  385. const F32 axisCollisionThresholdSS = 10.0f;
  386. Point3F originSS;
  387. MathUtils::mProjectWorldToScreen( mOrigin, &originSS, mLastViewport, mLastWorldMat, mLastProjMat );
  388. originSS.z = 0.0f;
  389. const F32 originDistSS = mAbs( ( mousePntSS - originSS ).len() );
  390. // Check for camera facing axis rotation handle collision.
  391. if ( mScreenRotateHandleEnabled )
  392. {
  393. const F32 distSS = mAbs( ( (F32)mProfile->screenLen * 0.7f ) - originDistSS );
  394. if ( distSS < axisCollisionThresholdSS )
  395. {
  396. mSelectionIdx = Custom1;
  397. Point3F normal = mousePntSS - originSS;
  398. normal.normalizeSafe();
  399. Point3F tangent = mCross( -normal, Point3F(0,0,1) );
  400. tangent.normalizeSafe();
  401. mElipseCursorCollidePntSS = mousePntSS;
  402. mElipseCursorCollideVecSS = tangent;
  403. mElipseCursorCollideVecSS.z = 0.0f;
  404. mElipseCursorCollideVecSS.normalizeSafe();
  405. return true;
  406. }
  407. }
  408. // Check for x/y/z axis ellipse handle collision.
  409. // We do this as a screen-space pixel distance test between
  410. // the cursor position and the ellipse handle projected to the screen
  411. // as individual segments.
  412. {
  413. const F32 ellipseRadiusWS = mProjLen * 0.5f;
  414. const U32 segments = 40;
  415. const F32 stepRadians = mDegToRad(360.0f) / segments;
  416. U32 x,y,z;
  417. F32 ang0, ang1, distSS;
  418. Point3F temp, pnt0, pnt1, closestPntSS;
  419. bool valid0, valid1;
  420. MatrixF worldToGizmo = mTransform;
  421. worldToGizmo.inverse();
  422. PlaneF clipPlaneGS; // Clip plane in gizmo space.
  423. mTransformPlane( worldToGizmo, Point3F(1,1,1), clipPlane, &clipPlaneGS );
  424. for ( U32 i = 0; i < 3; i++ )
  425. {
  426. if ( !mAxisEnabled[i] )
  427. continue;
  428. x = sgAxisRemap[i][0];
  429. y = sgAxisRemap[i][1];
  430. z = sgAxisRemap[i][2];
  431. for ( U32 j = 1; j <= segments; j++ )
  432. {
  433. ang0 = (j-1) * stepRadians;
  434. ang1 = j * stepRadians;
  435. temp.x = 0.0f;
  436. temp.y = mCos(ang0) * ellipseRadiusWS;
  437. temp.z = mSin(ang0) * ellipseRadiusWS;
  438. pnt0.set( temp[x], temp[y], temp[z] );
  439. temp.x = 0.0f;
  440. temp.y = mCos(ang1) * ellipseRadiusWS;
  441. temp.z = mSin(ang1) * ellipseRadiusWS;
  442. pnt1.set( temp[x], temp[y], temp[z] );
  443. valid0 = ( clipPlaneGS.whichSide(pnt0) == PlaneF::Back );
  444. valid1 = ( clipPlaneGS.whichSide(pnt1) == PlaneF::Back );
  445. if ( !valid0 || !valid1 )
  446. continue;
  447. // Transform points from gizmo space to world space.
  448. mTransform.mulP( pnt0 );
  449. mTransform.mulP( pnt1 );
  450. // Transform points from gizmo space to screen space.
  451. valid0 = MathUtils::mProjectWorldToScreen( pnt0, &pnt0, mLastViewport, mLastWorldMat, mLastProjMat );
  452. valid1 = MathUtils::mProjectWorldToScreen( pnt1, &pnt1, mLastViewport, mLastWorldMat, mLastProjMat );
  453. // Get distance from the cursor.
  454. closestPntSS = MathUtils::mClosestPointOnSegment( Point3F( pnt0.x, pnt0.y, 0.0f ), Point3F( pnt1.x, pnt1.y, 0.0f ), mousePntSS );
  455. distSS = ( closestPntSS - mousePntSS ).len();
  456. if ( distSS < axisCollisionThresholdSS )
  457. {
  458. mSelectionIdx = i;
  459. mElipseCursorCollidePntSS = mousePntSS;
  460. mElipseCursorCollideVecSS = pnt1 - pnt0;
  461. mElipseCursorCollideVecSS.z = 0.0f;
  462. mElipseCursorCollideVecSS.normalizeSafe();
  463. return true;
  464. }
  465. }
  466. }
  467. }
  468. // Check for sphere surface collision
  469. if ( originDistSS <= (F32)mProfile->screenLen * 0.5f )
  470. {
  471. // If this style manipulation is desired it must also be implemented in onMouseDragged.
  472. //mSelectionIdx = Custom2;
  473. //return true;
  474. }
  475. }
  476. // Check if we've hit the uniform scale handle...
  477. if ( mUniformHandleEnabled )
  478. {
  479. F32 tipScale = mProjLen * 0.1f;
  480. Point3F sp( tipScale, tipScale, tipScale );
  481. Point3F min = mOrigin - sp;
  482. Point3F max = mOrigin + sp;
  483. Box3F uhandle(min, max);
  484. if ( uhandle.collideLine( camPos, end ) )
  485. {
  486. mSelectionIdx = Centroid;
  487. return true;
  488. }
  489. }
  490. // Check if we've hit the planar handles...
  491. if ( ( mProfile->mode == MoveMode || mProfile->mode == ScaleMode ) &&
  492. ( mProfile->flags & GizmoProfile::PlanarHandlesOn ) )
  493. {
  494. for ( U32 i = 0; i < 3; i++ )
  495. {
  496. Point3F p1 = mProjAxisVector[sgPlanarVectors[i][0]];
  497. Point3F p2 = mProjAxisVector[sgPlanarVectors[i][1]];
  498. VectorF normal;
  499. mCross(p1, p2, &normal);
  500. if(normal.isZero())
  501. continue;
  502. PlaneF plane(mOrigin, normal);
  503. p1 *= mProjLen * 0.5f;
  504. p2 *= mProjLen * 0.5f;
  505. F32 scale = 0.5f;
  506. Point3F poly [] = {
  507. Point3F(mOrigin + p1 + p2 * scale),
  508. Point3F(mOrigin + p1 + p2),
  509. Point3F(mOrigin + p1 * scale + p2),
  510. Point3F(mOrigin + (p1 + p2) * scale)
  511. };
  512. Point3F endProj = camPos + event.vec * smProjectDistance;
  513. F32 t = plane.intersect(camPos, endProj);
  514. if ( t >= 0 && t <= 1 )
  515. {
  516. Point3F pos;
  517. pos.interpolate(camPos, endProj, t);
  518. // check if inside our 'poly' of this axisIdx vector...
  519. bool inside = true;
  520. for(U32 j = 0; inside && (j < 4); j++)
  521. {
  522. U32 k = (j+1) % 4;
  523. VectorF vec1 = poly[k] - poly[j];
  524. VectorF vec2 = pos - poly[k];
  525. if(mDot(vec1, vec2) > 0.f)
  526. inside = false;
  527. }
  528. //
  529. if ( inside )
  530. {
  531. mSelectionIdx = i+3;
  532. //mAxisGizmoSelPlane = plane;
  533. //mAxisGizmoSelPlaneIndex = i;
  534. //mAxisGizmoSelPlanePoint = pos;
  535. //mAxisGizmoSelStart = camPos;
  536. return true;
  537. }
  538. }
  539. }
  540. }
  541. if ( mCurrentMode == RotateMode )
  542. return false;
  543. // Check if we've hit an axis...
  544. for ( U32 i = 0; i < 3; i++ )
  545. {
  546. if ( !mAxisEnabled[i] )
  547. continue;
  548. VectorF up, normal;
  549. mCross(toGizmoVec, mProjAxisVector[i], &up);
  550. mCross(up, mProjAxisVector[i], &normal);
  551. if ( normal.isZero() )
  552. continue;
  553. PlaneF plane( mOrigin, normal );
  554. // width of the axisIdx poly is 1/10 the run
  555. Point3F a = up * mProjLen / 10;
  556. Point3F b = mProjAxisVector[i] * mProjLen;
  557. Point3F poly [] = {
  558. Point3F(mOrigin + a),
  559. Point3F(mOrigin + a + b),
  560. Point3F(mOrigin - a + b),
  561. Point3F(mOrigin - a)
  562. };
  563. F32 t = plane.intersect(camPos, end);
  564. if ( t >= 0 && t <= 1 )
  565. {
  566. Point3F pos;
  567. pos.interpolate(camPos, end, t);
  568. // check if inside our 'poly' of this axisIdx vector...
  569. bool inside = true;
  570. for ( U32 j = 0; inside && (j < 4); j++ )
  571. {
  572. U32 k = (j+1) % 4;
  573. VectorF vec1 = poly[k] - poly[j];
  574. VectorF vec2 = pos - poly[k];
  575. if ( mDot(vec1, vec2) > 0.f )
  576. inside = false;
  577. }
  578. //
  579. if(inside)
  580. {
  581. mSelectionIdx = i;
  582. return true;
  583. }
  584. }
  585. }
  586. return false;
  587. }
  588. void Gizmo::on3DMouseDown( const Gui3DMouseEvent & event )
  589. {
  590. _updateState();
  591. mMouseDown = true;
  592. if ( mProfile->mode == NoneMode )
  593. return;
  594. // Save the current transforms, need this for some
  595. // operations that occur on3DMouseDragged.
  596. mSavedTransform = mTransform;
  597. mSavedScale = mScale;
  598. mSavedRot = mTransform.toEuler();
  599. mMouseDownPos = event.mousePoint;
  600. mLastAngle = 0.0f;
  601. mLastScale = mScale;
  602. mLastMouseEvent = event;
  603. mSign = 0.0f;
  604. _calcAxisInfo();
  605. // Calculate mMouseCollideLine and mMouseDownProjPnt
  606. // which are used in on3DMouseDragged.
  607. if ( mProfile->mode == MoveMode || mProfile->mode == ScaleMode )
  608. {
  609. if ( mSelectionIdx >= Axis_X && mSelectionIdx <= Axis_Z )
  610. {
  611. MathUtils::Line clickLine;
  612. clickLine.origin = event.pos;
  613. clickLine.direction = event.vec;
  614. VectorF objectAxisVector = sgAxisVectors[mSelectionIdx];
  615. VectorF worldAxisVector = objectAxisVector;
  616. mTransform.mulV( worldAxisVector );
  617. MathUtils::Line axisLine;
  618. axisLine.origin = mTransform.getPosition();
  619. axisLine.direction = worldAxisVector;
  620. mMouseCollideLine = axisLine;
  621. LineSegment segment;
  622. mShortestSegmentBetweenLines( clickLine, axisLine, &segment );
  623. mMouseDownProjPnt = segment.p1;
  624. }
  625. else if ( mSelectionIdx >= Plane_XY && mSelectionIdx <= Plane_YZ )
  626. {
  627. VectorF objectPlaneNormal = sgAxisVectors[2 - (mSelectionIdx - 3 )];
  628. VectorF worldPlaneNormal = objectPlaneNormal;
  629. mTransform.mulV( worldPlaneNormal );
  630. PlaneF plane( mTransform.getPosition(), worldPlaneNormal );
  631. mMouseCollidePlane = plane;
  632. Point3F intersectPnt;
  633. if ( plane.intersect( event.pos, event.vec, &intersectPnt ) )
  634. {
  635. mMouseDownProjPnt = intersectPnt;
  636. }
  637. // We also calculate the line to be used later.
  638. VectorF objectAxisVector(0,0,0);
  639. objectAxisVector += sgAxisVectors[sgPlanarVectors[mSelectionIdx-3][0]];
  640. objectAxisVector += sgAxisVectors[sgPlanarVectors[mSelectionIdx-3][1]];
  641. objectAxisVector.normalize();
  642. VectorF worldAxisVector = objectAxisVector;
  643. mTransform.mulV( worldAxisVector );
  644. MathUtils::Line axisLine;
  645. axisLine.origin = mTransform.getPosition();
  646. axisLine.direction = worldAxisVector;
  647. mMouseCollideLine = axisLine;
  648. }
  649. else if ( mSelectionIdx == Centroid )
  650. {
  651. VectorF normal;
  652. mCameraMat.getColumn(1,&normal);
  653. normal = -normal;
  654. PlaneF plane( mOrigin, normal );
  655. mMouseCollidePlane = plane;
  656. Point3F intersectPnt;
  657. if ( plane.intersect( event.pos, event.vec, &intersectPnt ) )
  658. {
  659. mMouseDownProjPnt = intersectPnt;
  660. }
  661. }
  662. }
  663. else if ( mProfile->mode == RotateMode )
  664. {
  665. VectorF camPos;
  666. if( GFX->isFrustumOrtho() )
  667. camPos = event.pos;
  668. else
  669. camPos = mCameraPos;
  670. if ( 0 <= mSelectionIdx && mSelectionIdx <= 2 )
  671. {
  672. // Nothing to do, we already have mElipseCursorCollidePntSS
  673. // and mElipseCursorCollideVecSS set.
  674. }
  675. else if ( mSelectionIdx == Custom1 )
  676. {
  677. // Nothing to do, we already have mElipseCursorCollidePntSS
  678. // and mElipseCursorCollideVecSS set.
  679. }
  680. else if ( mSelectionIdx == Centroid )
  681. {
  682. // The Centroid handle for rotation mode is not implemented to do anything.
  683. // It can be handled by the class making use of the Gizmo.
  684. }
  685. }
  686. }
  687. void Gizmo::on3DMouseUp( const Gui3DMouseEvent &event )
  688. {
  689. _updateState();
  690. mMouseDown = false;
  691. mDeltaTotalPos.zero();
  692. mDeltaTotalScale.zero();
  693. mDeltaTotalRot.zero();
  694. // Done with a drag operation, recenter our orientation to the world.
  695. if ( mCurrentAlignment == World )
  696. {
  697. Point3F pos = mTransform.getPosition();
  698. mTransform.identity();
  699. mTransform.setPosition( pos );
  700. }
  701. }
  702. void Gizmo::on3DMouseMove( const Gui3DMouseEvent & event )
  703. {
  704. _updateState( false );
  705. if ( mProfile->mode == NoneMode )
  706. return;
  707. collideAxisGizmo( event );
  708. mLastMouseEvent = event;
  709. }
  710. void Gizmo::on3DMouseDragged( const Gui3DMouseEvent & event )
  711. {
  712. _updateState( false );
  713. if ( !mProfile || mProfile->mode == NoneMode || mSelectionIdx == None )
  714. return;
  715. // If we got a dragged event without the mouseDown flag the drag operation
  716. // must have been canceled by a mode change, ignore further dragged events.
  717. if ( !mMouseDown )
  718. return;
  719. _calcAxisInfo();
  720. if ( mProfile->mode == MoveMode || mProfile->mode == ScaleMode )
  721. {
  722. Point3F projPnt = mOrigin;
  723. // Project the mouse position onto the line/plane of manipulation...
  724. if ( mSelectionIdx >= 0 && mSelectionIdx <= 2 )
  725. {
  726. MathUtils::Line clickLine;
  727. clickLine.origin = event.pos;
  728. clickLine.direction = event.vec;
  729. LineSegment segment;
  730. mShortestSegmentBetweenLines( clickLine, mMouseCollideLine, &segment );
  731. projPnt = segment.p1;
  732. // snap to the selected axisIdx, if required
  733. Point3F snapPnt = _snapPoint(projPnt);
  734. if ( mSelectionIdx < 3 )
  735. {
  736. projPnt[mSelectionIdx] = snapPnt[mSelectionIdx];
  737. }
  738. else
  739. {
  740. projPnt[sgPlanarVectors[mSelectionIdx-3][0]] = snapPnt[sgPlanarVectors[mSelectionIdx-3][0]];
  741. projPnt[sgPlanarVectors[mSelectionIdx-3][1]] = snapPnt[sgPlanarVectors[mSelectionIdx-3][1]];
  742. }
  743. }
  744. else if ( 3 <= mSelectionIdx && mSelectionIdx <= 5 )
  745. {
  746. if ( mProfile->mode == MoveMode )
  747. {
  748. Point3F intersectPnt;
  749. if ( mMouseCollidePlane.intersect( event.pos, event.vec, &intersectPnt ) )
  750. {
  751. projPnt = intersectPnt;
  752. // snap to the selected axisIdx, if required
  753. Point3F snapPnt = _snapPoint(projPnt);
  754. projPnt[sgPlanarVectors[mSelectionIdx-3][0]] = snapPnt[sgPlanarVectors[mSelectionIdx-3][0]];
  755. projPnt[sgPlanarVectors[mSelectionIdx-3][1]] = snapPnt[sgPlanarVectors[mSelectionIdx-3][1]];
  756. }
  757. }
  758. else // ScaleMode
  759. {
  760. MathUtils::Line clickLine;
  761. clickLine.origin = event.pos;
  762. clickLine.direction = event.vec;
  763. LineSegment segment;
  764. mShortestSegmentBetweenLines( clickLine, mMouseCollideLine, &segment );
  765. projPnt = segment.p1;
  766. }
  767. }
  768. else if ( mSelectionIdx == Centroid )
  769. {
  770. Point3F intersectPnt;
  771. if ( mMouseCollidePlane.intersect( event.pos, event.vec, &intersectPnt ) )
  772. {
  773. projPnt = _snapPoint( intersectPnt );
  774. }
  775. }
  776. // Perform the manipulation...
  777. if ( mProfile->mode == MoveMode )
  778. {
  779. // Clear deltas we aren't using...
  780. mDeltaRot.zero();
  781. mDeltaScale.zero();
  782. Point3F newPosition;
  783. if( mProfile->snapToGrid )
  784. {
  785. Point3F snappedMouseDownProjPnt = _snapPoint( mMouseDownProjPnt );
  786. mDeltaTotalPos = projPnt - snappedMouseDownProjPnt;
  787. newPosition = projPnt;
  788. }
  789. else
  790. {
  791. mDeltaTotalPos = projPnt - mMouseDownProjPnt;
  792. newPosition = mSavedTransform.getPosition() + mDeltaTotalPos;
  793. }
  794. mDeltaPos = newPosition - mTransform.getPosition();
  795. mTransform.setPosition( newPosition );
  796. mCurrentTransform.setPosition( newPosition );
  797. }
  798. else // ScaleMode
  799. {
  800. // This is the world-space axis we want to scale
  801. //VectorF axis = sgAxisVectors[mSelectionIdx];
  802. // Find its object-space components...
  803. //MatrixF mat = mObjectMat;
  804. //mat.inverse();
  805. //mat.mulV(axis);
  806. // Which needs to always be positive, this is a 'scale' transformation
  807. // not really a 'vector' transformation.
  808. //for ( U32 i = 0; i < 3; i++ )
  809. // axis[i] = mFabs(axis[i]);
  810. //axis.normalizeSafe();
  811. // Clear deltas we aren't using...
  812. mDeltaRot.zero();
  813. mDeltaPos.zero();
  814. // Calculate the deltaScale...
  815. VectorF deltaScale(0,0,0);
  816. if ( 0 <= mSelectionIdx && mSelectionIdx <= 2 )
  817. {
  818. // Are we above or below the starting position relative to this axis?
  819. PlaneF plane( mMouseDownProjPnt, mProjAxisVector[mSelectionIdx] );
  820. F32 sign = ( plane.whichSide( projPnt ) == PlaneF::Front ) ? 1 : -1;
  821. F32 diff = ( projPnt - mMouseDownProjPnt ).len();
  822. if ( mProfile->allAxesScaleUniform )
  823. {
  824. deltaScale.set(1,1,1);
  825. deltaScale = deltaScale * sign * diff;
  826. }
  827. else
  828. deltaScale[mSelectionIdx] = diff * sign;
  829. }
  830. else if ( 3 <= mSelectionIdx && mSelectionIdx <= 5 )
  831. {
  832. PlaneF plane( mMouseDownProjPnt, mMouseCollideLine.direction );
  833. F32 sign = ( plane.whichSide( projPnt ) == PlaneF::Front ) ? 1 : -1;
  834. F32 diff = ( projPnt - mMouseDownProjPnt ).len();
  835. if ( mProfile->allAxesScaleUniform )
  836. {
  837. deltaScale.set(1,1,1);
  838. deltaScale = deltaScale * sign * diff;
  839. }
  840. else
  841. {
  842. deltaScale[sgPlanarVectors[mSelectionIdx-3][0]] = diff * sign;
  843. deltaScale[sgPlanarVectors[mSelectionIdx-3][1]] = diff * sign;
  844. }
  845. }
  846. else // mSelectionIdx == 6
  847. {
  848. // Are we above or below the starting position relative to the camera?
  849. VectorF normal;
  850. mCameraMat.getColumn( 2, &normal );
  851. PlaneF plane( mMouseDownProjPnt, normal );
  852. F32 sign = ( plane.whichSide( projPnt ) == PlaneF::Front ) ? 1 : -1;
  853. F32 diff = ( projPnt - mMouseDownProjPnt ).len();
  854. deltaScale.set(1,1,1);
  855. deltaScale = deltaScale * sign * diff;
  856. }
  857. // Save current scale, then set mDeltaScale
  858. // to the amount it changes during this call.
  859. mDeltaScale = mScale;
  860. mDeltaTotalScale = deltaScale;
  861. mScale = mSavedScale;
  862. mScale += deltaScale * mProfile->scaleScalar;
  863. mDeltaScale = mScale - mDeltaScale;
  864. mScale.setMax( Point3F( 0.01f ) );
  865. }
  866. mDirty = true;
  867. }
  868. else if ( mProfile->mode == RotateMode &&
  869. mSelectionIdx != Centroid )
  870. {
  871. // Clear deltas we aren't using...
  872. mDeltaScale.zero();
  873. mDeltaPos.zero();
  874. bool doScreenRot = ( mSelectionIdx == Custom1 );
  875. U32 rotAxisIdx = ( doScreenRot ) ? 1 : mSelectionIdx;
  876. Point3F mousePntSS( event.mousePoint.x, event.mousePoint.y, 0.0f );
  877. Point3F pntSS0 = mElipseCursorCollidePntSS + mElipseCursorCollideVecSS * 10000.0f;
  878. Point3F pntSS1 = mElipseCursorCollidePntSS - mElipseCursorCollideVecSS * 10000.0f;
  879. Point3F closestPntSS = MathUtils::mClosestPointOnSegment( pntSS0, pntSS1, mousePntSS );
  880. Point3F offsetDir = closestPntSS - mElipseCursorCollidePntSS;
  881. F32 offsetDist = offsetDir.len();
  882. offsetDir.normalizeSafe();
  883. F32 dot = mDot( mElipseCursorCollideVecSS, offsetDir );
  884. mSign = mIsZero( dot ) ? 0.0f : ( dot > 0.0f ) ? -1.0f : 1.0f;
  885. // The angle that we will rotate the (saved) gizmo transform by to
  886. // generate the current gizmo transform.
  887. F32 angle = offsetDist * mSign * mProfile->rotateScalar;
  888. angle *= 0.02f; // scale down to not require rotate scalar to be microscopic
  889. //
  890. if((mProfile->forceSnapRotations && event.modifier | SI_SHIFT) || (mProfile->allowSnapRotations && event.modifier & SI_SHIFT ))
  891. angle = mDegToRad( _snapFloat( mRadToDeg( angle ), mProfile->rotationSnap ) );
  892. mDeltaAngle = angle - mLastAngle;
  893. mLastAngle = angle;
  894. if ( doScreenRot )
  895. {
  896. // Rotate relative to the camera.
  897. // We rotate around the y/forward vector pointing from the camera
  898. // to the gizmo.
  899. // NOTE: This does NOT work
  900. // Calculate mDeltaAngle and mDeltaTotalRot
  901. //{
  902. // VectorF fvec( mOrigin - mCameraPos );
  903. // fvec.normalizeSafe();
  904. // AngAxisF aa( fvec, mDeltaAngle );
  905. // MatrixF mat;
  906. // aa.setMatrix( &mat );
  907. // mDeltaRot = mat.toEuler();
  908. // aa.set( fvec, mLastAngle );
  909. // aa.setMatrix( &mat );
  910. // mDeltaTotalRot = mat.toEuler();
  911. //}
  912. //MatrixF rotMat( mDeltaTotalRot );
  913. //if ( mCurrentAlignment == World )
  914. //{
  915. // //aa.setMatrix( &rotMat );
  916. // mTransform = mSavedTransform * rotMat;
  917. // mTransform.setPosition( mOrigin );
  918. // rotMat.inverse();
  919. // mCurrentTransform = mObjectMatInv * rotMat;
  920. // mCurrentTransform.inverse();
  921. // mCurrentTransform.setPosition( mOrigin );
  922. //}
  923. //else
  924. //{
  925. // rotMat.inverse();
  926. // MatrixF m0;
  927. // mSavedTransform.invertTo(&m0);
  928. //
  929. // mTransform = m0 * rotMat;
  930. // mTransform.inverse();
  931. // mTransform.setPosition( mOrigin );
  932. // mCurrentTransform = mTransform;
  933. //}
  934. }
  935. else
  936. {
  937. // Normal rotation, eg, not screen relative.
  938. mDeltaRot.set(0,0,0);
  939. mDeltaRot[rotAxisIdx] = mDeltaAngle;
  940. mDeltaTotalRot.set(0,0,0);
  941. mDeltaTotalRot[rotAxisIdx] = angle;
  942. MatrixF rotMat( mDeltaTotalRot );
  943. mTransform = mSavedTransform * rotMat;
  944. mTransform.setPosition( mSavedTransform.getPosition() );
  945. if ( mCurrentAlignment == World )
  946. {
  947. MatrixF mat0 = mCurrentTransform;
  948. rotMat.inverse();
  949. mCurrentTransform = mObjectMatInv * rotMat;
  950. mCurrentTransform.inverse();
  951. mCurrentTransform.setPosition( mOrigin );
  952. MatrixF mat1 = mCurrentTransform;
  953. mat0.inverse();
  954. MatrixF mrot;
  955. mrot = mat0 * mat1;
  956. mDeltaRot = mrot.toEuler();
  957. }
  958. else
  959. {
  960. mCurrentTransform = mTransform;
  961. }
  962. }
  963. mDirty = true;
  964. }
  965. mLastMouseEvent = event;
  966. }
  967. //------------------------------------------------------------------------------
  968. void Gizmo::renderGizmo(const MatrixF &cameraTransform, F32 cameraFOV )
  969. {
  970. mLastWorldMat = GFX->getWorldMatrix();
  971. mLastProjMat = GFX->getProjectionMatrix();
  972. mLastViewport = GFX->getViewport();
  973. mLastWorldToScreenScale = GFX->getWorldToScreenScale();
  974. mLastCameraFOV = cameraFOV;
  975. // Save the Camera transform matrix, used all over...
  976. mCameraMat = cameraTransform;
  977. mCameraPos = mCameraMat.getPosition();
  978. GFXFrustumSaver fsaver;
  979. // Change the far plane distance so that the gizmo is always visible.
  980. Frustum frustum = GFX->getFrustum();
  981. frustum.setFarDist( 100000.0f );
  982. GFX->setFrustum( frustum );
  983. _updateEnabledAxices();
  984. _updateState();
  985. _calcAxisInfo();
  986. if( mMouseDown )
  987. {
  988. if( mProfile->renderMoveGrid && mMoveGridEnabled && mCurrentMode == MoveMode )
  989. {
  990. GFXStateBlockDesc desc;
  991. desc.setBlend( true );
  992. desc.setZReadWrite( true, true );
  993. GFXDrawUtil::Plane plane = GFXDrawUtil::PlaneXY;
  994. ColorI color( 128, 128, 128, 200 );
  995. switch( mSelectionIdx )
  996. {
  997. case Axis_Z:
  998. case Plane_XY:
  999. plane = GFXDrawUtil::PlaneXY;
  1000. break;
  1001. case Axis_X:
  1002. case Plane_YZ:
  1003. plane = GFXDrawUtil::PlaneYZ;
  1004. break;
  1005. case Axis_Y:
  1006. case Plane_XZ:
  1007. plane = GFXDrawUtil::PlaneXZ;
  1008. break;
  1009. }
  1010. GFX->getDrawUtil()->drawPlaneGrid(
  1011. desc,
  1012. mTransform.getPosition(),
  1013. Point2F( mMoveGridSize, mMoveGridSize ),
  1014. Point2F( mMoveGridSpacing, mMoveGridSpacing ),
  1015. color,
  1016. plane
  1017. );
  1018. }
  1019. if( !mProfile->renderWhenUsed )
  1020. return;
  1021. }
  1022. mHighlightAll = mProfile->allAxesScaleUniform && mSelectionIdx >= 0 && mSelectionIdx <= 3;
  1023. // Render plane (if set to render) behind the gizmo
  1024. if ( mProfile->mode != NoneMode )
  1025. _renderPlane();
  1026. _setStateBlock();
  1027. // Special case for NoneMode,
  1028. // we only render the primary axis with no tips.
  1029. if ( mProfile->mode == NoneMode )
  1030. {
  1031. _renderPrimaryAxis();
  1032. return;
  1033. }
  1034. if ( mProfile->mode == RotateMode )
  1035. {
  1036. PrimBuild::begin( GFXLineList, 6 );
  1037. // Render the primary axisIdx
  1038. for(U32 i = 0; i < 3; i++)
  1039. {
  1040. PrimBuild::color( ( mHighlightAll || i == mSelectionIdx ) ? mProfile->axisColors[i] : mProfile->inActiveColor );
  1041. PrimBuild::vertex3fv( mOrigin );
  1042. PrimBuild::vertex3fv( mOrigin + mProjAxisVector[i] * mProjLen * 0.25f );
  1043. }
  1044. PrimBuild::end();
  1045. _renderAxisCircles();
  1046. }
  1047. else
  1048. {
  1049. // Both Move and Scale modes render basis vectors as
  1050. // large stick lines.
  1051. _renderPrimaryAxis();
  1052. // Render the tips based on current operation.
  1053. GFXTransformSaver saver( true, false );
  1054. GFX->multWorld(mTransform);
  1055. if ( mProfile->mode == ScaleMode )
  1056. {
  1057. _renderAxisBoxes();
  1058. }
  1059. else if ( mProfile->mode == MoveMode )
  1060. {
  1061. _renderAxisArrows();
  1062. }
  1063. saver.restore();
  1064. }
  1065. // Render the planar handles...
  1066. if ( mCurrentMode != RotateMode )
  1067. {
  1068. Point3F midpnt[3];
  1069. for(U32 i = 0; i < 3; i++)
  1070. midpnt[i] = mProjAxisVector[i] * mProjLen * 0.5f;
  1071. PrimBuild::begin( GFXLineList, 12 );
  1072. for(U32 i = 0; i < 3; i++)
  1073. {
  1074. U32 axis0 = sgPlanarVectors[i][0];
  1075. U32 axis1 = sgPlanarVectors[i][1];
  1076. const Point3F &p0 = midpnt[axis0];
  1077. const Point3F &p1 = midpnt[axis1];
  1078. bool selected0 = false;
  1079. bool selected1 = false;
  1080. if ( i + 3 == mSelectionIdx )
  1081. selected0 = selected1 = true;
  1082. bool inactive = !mAxisEnabled[axis0] || !mAxisEnabled[axis1] || !(mProfile->flags & GizmoProfile::PlanarHandlesOn);
  1083. if ( inactive )
  1084. PrimBuild::color( mProfile->hideDisabledAxes ? ColorI::ZERO : mProfile->inActiveColor );
  1085. else
  1086. PrimBuild::color( selected0 ? mProfile->activeColor : mProfile->axisColors[axis0] );
  1087. PrimBuild::vertex3fv( mOrigin + p0 );
  1088. PrimBuild::vertex3fv( mOrigin + p0 + p1 );
  1089. if ( inactive )
  1090. PrimBuild::color( mProfile->hideDisabledAxes ? ColorI::ZERO : mProfile->inActiveColor );
  1091. else
  1092. PrimBuild::color( selected1 ? mProfile->activeColor : mProfile->axisColors[axis1] );
  1093. PrimBuild::vertex3fv( mOrigin + p1 );
  1094. PrimBuild::vertex3fv( mOrigin + p0 + p1 );
  1095. }
  1096. PrimBuild::end();
  1097. // Render planar handle as solid if selected.
  1098. ColorI planeColorSEL( mProfile->activeColor );
  1099. planeColorSEL.alpha = 75;
  1100. ColorI planeColorNA( 0, 0, 0, 0 );
  1101. PrimBuild::begin( GFXTriangleList, 18 );
  1102. for(U32 i = 0; i < 3; i++)
  1103. {
  1104. U32 axis0 = sgPlanarVectors[i][0];
  1105. U32 axis1 = sgPlanarVectors[i][1];
  1106. const Point3F &p0 = midpnt[axis0];
  1107. const Point3F &p1 = midpnt[axis1];
  1108. if ( i + 3 == mSelectionIdx )
  1109. PrimBuild::color( planeColorSEL );
  1110. else
  1111. PrimBuild::color( planeColorNA );
  1112. PrimBuild::vertex3fv( mOrigin );
  1113. PrimBuild::vertex3fv( mOrigin + p0 );
  1114. PrimBuild::vertex3fv( mOrigin + p0 + p1 );
  1115. PrimBuild::vertex3fv( mOrigin );
  1116. PrimBuild::vertex3fv( mOrigin + p0 + p1 );
  1117. PrimBuild::vertex3fv( mOrigin + p1 );
  1118. }
  1119. PrimBuild::end();
  1120. }
  1121. // Render Centroid Handle...
  1122. if ( mUniformHandleEnabled )
  1123. {
  1124. F32 tipScale = mProjLen * 0.075f;
  1125. GFXTransformSaver saver;
  1126. GFX->multWorld( mTransform );
  1127. if ( mSelectionIdx == Centroid || mHighlightAll || mHighlightCentroidHandle )
  1128. PrimBuild::color( mProfile->centroidHighlightColor );
  1129. else
  1130. PrimBuild::color( mProfile->centroidColor );
  1131. for(U32 j = 0; j < 6; j++)
  1132. {
  1133. PrimBuild::begin( GFXTriangleStrip, 4 );
  1134. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][0]] * tipScale);
  1135. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][1]] * tipScale);
  1136. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][2]] * tipScale);
  1137. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][3]] * tipScale);
  1138. PrimBuild::end();
  1139. }
  1140. }
  1141. }
  1142. void Gizmo::renderText( const RectI &viewPort, const MatrixF &modelView, const MatrixF &projection )
  1143. {
  1144. if ( mProfile->mode == NoneMode )
  1145. return;
  1146. if ( mMouseDown && !mProfile->renderWhenUsed )
  1147. return;
  1148. GFXDrawUtil *drawer = GFX->getDrawUtil();
  1149. _setStateBlock();
  1150. char axisText[] = "xyz";
  1151. F32 projLen = mProjLen * 1.05f;
  1152. if ( mProfile->mode == RotateMode )
  1153. projLen *= 0.28f;
  1154. for ( U32 i = 0; i < 3; i++ )
  1155. {
  1156. if ( !mAxisEnabled[i] && mProfile->hideDisabledAxes )
  1157. continue;
  1158. const Point3F & centroid = mOrigin;
  1159. Point3F pos(centroid.x + mProjAxisVector[i].x * projLen,
  1160. centroid.y + mProjAxisVector[i].y * projLen,
  1161. centroid.z + mProjAxisVector[i].z * projLen);
  1162. Point3F sPos;
  1163. if ( MathUtils::mProjectWorldToScreen( pos, &sPos, viewPort, modelView, projection ) )
  1164. {
  1165. ColorI textColor = ColorI(170,170,170);
  1166. if ( mProfile->mode == RotateMode )
  1167. {
  1168. textColor.set(170,170,170);
  1169. if ( i == mSelectionIdx )
  1170. textColor = mProfile->axisColors[i];
  1171. }
  1172. else
  1173. {
  1174. if ( i == mSelectionIdx || !mAxisEnabled[i] )
  1175. textColor = mProfile->inActiveColor;
  1176. else
  1177. textColor = mProfile->axisColors[i];
  1178. }
  1179. char buf[2];
  1180. buf[0] = axisText[i]; buf[1] = '\0';
  1181. drawer->setBitmapModulation(textColor);
  1182. drawer->drawText( mProfile->font, Point2I((S32)sPos.x, (S32)sPos.y), buf );
  1183. }
  1184. }
  1185. }
  1186. // Gizmo Internal Methods...
  1187. void Gizmo::_calcAxisInfo()
  1188. {
  1189. mOrigin = mTransform.getPosition();
  1190. for ( U32 i = 0; i < 3; i++ )
  1191. {
  1192. VectorF tmp;
  1193. mTransform.mulV(sgAxisVectors[i], &tmp);
  1194. mProjAxisVector[i] = tmp;
  1195. mProjAxisVector[i].normalizeSafe();
  1196. }
  1197. // get the projected size...
  1198. mProjLen = _getProjectionLength( mProfile->screenLen );
  1199. }
  1200. void Gizmo::_renderPrimaryAxis()
  1201. {
  1202. // Render the primary axis(s)
  1203. for ( U32 i = 0; i < 3; i++ )
  1204. {
  1205. ColorI color = mProfile->axisColors[i];
  1206. if ( !mAxisEnabled[i] )
  1207. {
  1208. color = mProfile->inActiveColor;
  1209. if ( mProfile->hideDisabledAxes )
  1210. color.alpha = 0;
  1211. }
  1212. else
  1213. {
  1214. if ( 0 <= mSelectionIdx && mSelectionIdx <= 2 )
  1215. {
  1216. if ( i == mSelectionIdx )
  1217. color = mProfile->activeColor;
  1218. }
  1219. else if ( 3 <= mSelectionIdx && mSelectionIdx <= 5 )
  1220. {
  1221. if ( i == sgPlanarVectors[mSelectionIdx-3][0] ||
  1222. i == sgPlanarVectors[mSelectionIdx-3][1] )
  1223. color = mProfile->activeColor;
  1224. }
  1225. else if ( mSelectionIdx == 6 )
  1226. color = mProfile->activeColor;
  1227. }
  1228. if ( mHighlightAll )
  1229. {
  1230. // Previous logic is complex so do this outside.
  1231. // Don't change the alpha calculated previously but override
  1232. // the color to the activeColor.
  1233. U8 saveAlpha = color.alpha;
  1234. color = mProfile->activeColor;
  1235. color.alpha = saveAlpha;
  1236. }
  1237. PrimBuild::begin( GFXLineList, 2 );
  1238. PrimBuild::color( color );
  1239. PrimBuild::vertex3fv( mOrigin );
  1240. PrimBuild::vertex3fv( mOrigin + mProjAxisVector[i] * mProjLen );
  1241. PrimBuild::end();
  1242. }
  1243. }
  1244. void Gizmo::_renderAxisArrows()
  1245. {
  1246. F32 tipScale = mProjLen * 0.25;
  1247. S32 x, y, z;
  1248. Point3F pnt;
  1249. for ( U32 axisIdx = 0; axisIdx < 3; axisIdx++ )
  1250. {
  1251. if ( mProfile->hideDisabledAxes && !mAxisEnabled[axisIdx] )
  1252. continue;
  1253. PrimBuild::begin( GFXTriangleList, 12*3 );
  1254. if ( !mAxisEnabled[axisIdx] )
  1255. PrimBuild::color( mProfile->inActiveColor );
  1256. else
  1257. PrimBuild::color( mProfile->axisColors[axisIdx] );
  1258. x = sgAxisRemap[axisIdx][0];
  1259. y = sgAxisRemap[axisIdx][1];
  1260. z = sgAxisRemap[axisIdx][2];
  1261. for ( U32 i = 0; i < sizeof(sgConeVerts) / (sizeof(U32)*3); ++i )
  1262. {
  1263. const Point3F& conePnt0 = sgConePnts[sgConeVerts[i][0]];
  1264. pnt.set(conePnt0[x], conePnt0[y], conePnt0[z]);
  1265. PrimBuild::vertex3fv(pnt * tipScale + sgAxisVectors[axisIdx] * mProjLen);
  1266. const Point3F& conePnt1 = sgConePnts[sgConeVerts[i][1]];
  1267. pnt.set(conePnt1[x], conePnt1[y], conePnt1[z]);
  1268. PrimBuild::vertex3fv(pnt * tipScale + sgAxisVectors[axisIdx] * mProjLen);
  1269. const Point3F& conePnt2 = sgConePnts[sgConeVerts[i][2]];
  1270. pnt.set(conePnt2[x], conePnt2[y], conePnt2[z]);
  1271. PrimBuild::vertex3fv(pnt * tipScale + sgAxisVectors[axisIdx] * mProjLen);
  1272. }
  1273. PrimBuild::end();
  1274. }
  1275. }
  1276. void Gizmo::_renderAxisBoxes()
  1277. {
  1278. if ( mProfile->hideDisabledAxes && !( mProfile->flags & GizmoProfile::CanScale ) )
  1279. return;
  1280. F32 tipScale = mProjLen * 0.1;
  1281. F32 pos = mProjLen - 0.5 * tipScale;
  1282. for( U32 axisIdx = 0; axisIdx < 3; ++axisIdx )
  1283. {
  1284. if ( mProfile->hideDisabledAxes && !( mProfile->flags & ( GizmoProfile::CanScaleX << axisIdx ) ) )
  1285. continue;
  1286. if ( mAxisEnabled[axisIdx] )
  1287. PrimBuild::color( mProfile->axisColors[axisIdx] );
  1288. else
  1289. PrimBuild::color( mProfile->inActiveColor );
  1290. for(U32 j = 0; j < 6; j++)
  1291. {
  1292. PrimBuild::begin( GFXTriangleStrip, 4 );
  1293. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][0]] * tipScale + sgAxisVectors[axisIdx] * pos );
  1294. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][1]] * tipScale + sgAxisVectors[axisIdx] * pos );
  1295. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][2]] * tipScale + sgAxisVectors[axisIdx] * pos );
  1296. PrimBuild::vertex3fv( sgCenterBoxPnts[sgBoxVerts[j][3]] * tipScale + sgAxisVectors[axisIdx] * pos );
  1297. PrimBuild::end();
  1298. }
  1299. }
  1300. }
  1301. void Gizmo::_renderAxisCircles()
  1302. {
  1303. if ( mProfile->hideDisabledAxes && !( mProfile->flags & GizmoProfile::CanRotate ) )
  1304. return;
  1305. // Setup the WorldMatrix for rendering in camera space.
  1306. // Honestly not sure exactly why this works but it does...
  1307. GFX->pushWorldMatrix();
  1308. MatrixF cameraXfm = GFX->getWorldMatrix();
  1309. cameraXfm.inverse();
  1310. const Point3F cameraPos = cameraXfm.getPosition();
  1311. cameraXfm.setPosition( mOrigin );
  1312. GFX->multWorld(cameraXfm);
  1313. // Render the ScreenSpace rotation circle...
  1314. if ( !( mProfile->hideDisabledAxes && !mScreenRotateHandleEnabled ) )
  1315. {
  1316. F32 radius = mProjLen * 0.7f;
  1317. U32 segments = 40;
  1318. F32 step = mDegToRad(360.0f)/ segments;
  1319. Point3F pnt;
  1320. PrimBuild::color( ( mHighlightAll || mSelectionIdx == Custom1 ) ? mProfile->activeColor : mProfile->inActiveColor );
  1321. PrimBuild::begin( GFXLineStrip, segments+1 );
  1322. for(U32 i = 0; i <= segments; i++)
  1323. {
  1324. F32 angle = i * step;
  1325. pnt.x = mCos(angle) * radius;
  1326. pnt.y = 0.0f;
  1327. pnt.z = mSin(angle) * radius;
  1328. PrimBuild::vertex3fv( pnt );
  1329. }
  1330. PrimBuild::end();
  1331. }
  1332. // Render the gizmo/sphere bounding circle...
  1333. {
  1334. F32 radius = mProjLen * 0.5f;
  1335. U32 segments = 40;
  1336. F32 step = mDegToRad(360.0f) / segments;
  1337. Point3F pnt;
  1338. // Render as solid (with transparency) when the sphere is selected
  1339. if ( mSelectionIdx == Custom2 )
  1340. {
  1341. ColorI color = mProfile->inActiveColor;
  1342. color.alpha = 100;
  1343. PrimBuild::color( color );
  1344. PrimBuild::begin( GFXTriangleStrip, segments+2 );
  1345. PrimBuild::vertex3fv( Point3F(0,0,0) );
  1346. for(U32 i = 0; i <= segments; i++)
  1347. {
  1348. F32 angle = i * step;
  1349. pnt.x = mCos(angle) * radius;
  1350. pnt.y = 0.0f;
  1351. pnt.z = mSin(angle) * radius;
  1352. PrimBuild::vertex3fv( pnt );
  1353. }
  1354. PrimBuild::end();
  1355. }
  1356. else
  1357. {
  1358. PrimBuild::color( mProfile->inActiveColor );
  1359. PrimBuild::begin( GFXLineStrip, segments+1 );
  1360. for(U32 i = 0; i <= segments; i++)
  1361. {
  1362. F32 angle = i * step;
  1363. pnt.x = mCos(angle) * radius;
  1364. pnt.y = 0.0f;
  1365. pnt.z = mSin(angle) * radius;
  1366. PrimBuild::vertex3fv( pnt );
  1367. }
  1368. PrimBuild::end();
  1369. }
  1370. }
  1371. // Done rendering in camera space.
  1372. GFX->popWorldMatrix();
  1373. // Setup WorldMatrix for Gizmo-Space rendering.
  1374. GFX->pushWorldMatrix();
  1375. GFX->multWorld(mTransform);
  1376. // Render the axis-manipulation ellipses...
  1377. {
  1378. F32 radius = mProjLen * 0.5f;
  1379. U32 segments = 40;
  1380. F32 step = mDegToRad(360.0f) / segments;
  1381. U32 x,y,z;
  1382. VectorF planeNormal;
  1383. planeNormal = mOrigin - cameraPos;
  1384. planeNormal.normalize();
  1385. PlaneF clipPlane( mOrigin, planeNormal );
  1386. MatrixF worldToGizmo = mTransform;
  1387. worldToGizmo.inverse();
  1388. mTransformPlane( worldToGizmo, Point3F(1,1,1), clipPlane, &clipPlane );
  1389. for ( U32 axis = 0; axis < 3; axis++ )
  1390. {
  1391. if ( mProfile->hideDisabledAxes && !( mProfile->flags & ( GizmoProfile::CanRotateX << axis ) ) )
  1392. continue;
  1393. if ( mAxisEnabled[axis] || mHighlightAll )
  1394. PrimBuild::color( (axis == mSelectionIdx) ? mProfile->activeColor : mProfile->axisColors[axis] );
  1395. else
  1396. PrimBuild::color( mProfile->inActiveColor );
  1397. x = sgAxisRemap[axis][0];
  1398. y = sgAxisRemap[axis][1];
  1399. z = sgAxisRemap[axis][2];
  1400. PrimBuild::begin( GFXLineList, (segments+1) * 2 );
  1401. for ( U32 i = 1; i <= segments; i++ )
  1402. {
  1403. F32 ang0 = (i-1) * step;
  1404. F32 ang1 = i * step;
  1405. Point3F temp;
  1406. temp.x = 0.0f;
  1407. temp.y = mCos(ang0) * radius;
  1408. temp.z = mSin(ang0) * radius;
  1409. Point3F pnt0( temp[x], temp[y], temp[z] );
  1410. temp.x = 0.0f;
  1411. temp.y = mCos(ang1) * radius;
  1412. temp.z = mSin(ang1) * radius;
  1413. Point3F pnt1( temp[x], temp[y], temp[z] );
  1414. bool valid0 = ( clipPlane.whichSide(pnt0) == PlaneF::Back );
  1415. bool valid1 = ( clipPlane.whichSide(pnt1) == PlaneF::Back );
  1416. //if ( !valid0 && !valid1 )
  1417. // continue;
  1418. if ( !valid0 || !valid1 )
  1419. continue;
  1420. PrimBuild::vertex3fv( pnt0 );
  1421. PrimBuild::vertex3fv( pnt1 );
  1422. }
  1423. PrimBuild::end();
  1424. }
  1425. }
  1426. // Done rendering in Gizmo-Space.
  1427. GFX->popWorldMatrix();
  1428. // Render hint-arrows...
  1429. /*
  1430. if ( mMouseDown && mSelectionIdx != -1 )
  1431. {
  1432. PrimBuild::begin( GFXLineList, 4 );
  1433. F32 hintArrowScreenLength = mProfile->screenLen * 0.5f;
  1434. F32 hintArrowTipScreenLength = mProfile->screenLen * 0.25;
  1435. F32 worldZDist = ( mMouseCollideLine.origin - mCameraPos ).len();
  1436. F32 hintArrowLen = ( hintArrowScreenLength * worldZDist ) / mLastWorldToScreenScale.y;
  1437. F32 hintArrowTipLen = ( hintArrowTipScreenLength * worldZDist ) / mLastWorldToScreenScale.y;
  1438. Point3F p0 = mMouseCollideLine.origin - mMouseCollideLine.direction * hintArrowLen;
  1439. Point3F p1 = mMouseCollideLine.origin;
  1440. Point3F p2 = mMouseCollideLine.origin + mMouseCollideLine.direction * hintArrowLen;
  1441. // For whatever reason, the sign is actually negative if we are on the
  1442. // positive size of the MouseCollideLine direction.
  1443. ColorI color0 = ( mSign > 0.0f ) ? mProfile->activeColor : mProfile->inActiveColor;
  1444. ColorI color1 = ( mSign < 0.0f ) ? mProfile->activeColor : mProfile->inActiveColor;
  1445. PrimBuild::color( color0 );
  1446. PrimBuild::vertex3fv( p1 );
  1447. PrimBuild::vertex3fv( p0 );
  1448. PrimBuild::color( color1 );
  1449. PrimBuild::vertex3fv( p1 );
  1450. PrimBuild::vertex3fv( p2 );
  1451. PrimBuild::end();
  1452. GFXStateBlockDesc desc;
  1453. desc.setBlend( true );
  1454. desc.setZReadWrite( false, false );
  1455. GFXDrawUtil *drawer = GFX->getDrawUtil();
  1456. drawer->drawCone( desc, p0, p0 - mMouseCollideLine.direction * hintArrowTipLen, hintArrowTipLen * 0.5f, color0 );
  1457. drawer->drawCone( desc, p2, p2 + mMouseCollideLine.direction * hintArrowTipLen, hintArrowTipLen * 0.5f, color1 );
  1458. }
  1459. */
  1460. }
  1461. void Gizmo::_renderPlane()
  1462. {
  1463. if( !mGridPlaneEnabled )
  1464. return;
  1465. Point2F size( mProfile->planeDim, mProfile->planeDim );
  1466. GFXStateBlockDesc desc;
  1467. desc.setBlend( true );
  1468. desc.setZReadWrite( true, false );
  1469. GFXTransformSaver saver;
  1470. GFX->multWorld( mTransform );
  1471. if ( mProfile->renderPlane )
  1472. GFX->getDrawUtil()->drawSolidPlane( desc, Point3F::Zero, size, mProfile->gridColor );
  1473. if ( mProfile->renderPlaneHashes )
  1474. {
  1475. // TODO: This wasn't specified before... so it was
  1476. // rendering lines that were invisible. Maybe we need
  1477. // a new field for grid line color?
  1478. ColorI gridColor( mProfile->gridColor );
  1479. gridColor.alpha *= 2;
  1480. GFX->getDrawUtil()->drawPlaneGrid( desc, Point3F::Zero, size, Point2F( mProfile->gridSize.x, mProfile->gridSize.y ), gridColor );
  1481. }
  1482. }
  1483. void Gizmo::_setStateBlock()
  1484. {
  1485. if ( !mStateBlock )
  1486. {
  1487. GFXStateBlockDesc sb;
  1488. sb.blendDefined = true;
  1489. sb.blendEnable = true;
  1490. sb.blendSrc = GFXBlendSrcAlpha;
  1491. sb.blendDest = GFXBlendInvSrcAlpha;
  1492. sb.zDefined = true;
  1493. sb.zEnable = false;
  1494. sb.cullDefined = true;
  1495. sb.cullMode = GFXCullNone;
  1496. mStateBlock = GFX->createStateBlock(sb);
  1497. sb.setZReadWrite( true, false );
  1498. mSolidStateBlock = GFX->createStateBlock(sb);
  1499. }
  1500. //if ( mProfile->renderSolid )
  1501. // GFX->setStateBlock( mSolidStateBlock );
  1502. //else
  1503. GFX->setStateBlock( mStateBlock );
  1504. }
  1505. Point3F Gizmo::_snapPoint( const Point3F &pnt ) const
  1506. {
  1507. if ( !mProfile->snapToGrid )
  1508. return pnt;
  1509. Point3F snap;
  1510. snap.x = _snapFloat( pnt.x, mProfile->gridSize.x );
  1511. snap.y = _snapFloat( pnt.y, mProfile->gridSize.y );
  1512. snap.z = _snapFloat( pnt.z, mProfile->gridSize.z );
  1513. return snap;
  1514. }
  1515. F32 Gizmo::_snapFloat( const F32 &val, const F32 &snap ) const
  1516. {
  1517. if ( snap == 0.0f )
  1518. return val;
  1519. F32 a = mFmod( val, snap );
  1520. F32 temp = val;
  1521. if ( mFabs(a) > (snap / 2) )
  1522. val < 0.0f ? temp -= snap : temp += snap;
  1523. return(temp - a);
  1524. }
  1525. GizmoAlignment Gizmo::_filteredAlignment()
  1526. {
  1527. GizmoAlignment align = mProfile->alignment;
  1528. // Special case in ScaleMode, always be in object.
  1529. if ( mProfile->mode == ScaleMode )
  1530. align = Object;
  1531. return align;
  1532. }
  1533. void Gizmo::_updateState( bool collideGizmo )
  1534. {
  1535. if ( !mProfile )
  1536. return;
  1537. // Update mCurrentMode
  1538. if ( mCurrentMode != mProfile->mode )
  1539. {
  1540. // Changing the mode invalidates the prior selection since the gizmo
  1541. // has changed shape.
  1542. mCurrentMode = mProfile->mode;
  1543. mSelectionIdx = -1;
  1544. // Determine the new selection unless we have been told not to.
  1545. if ( collideGizmo )
  1546. collideAxisGizmo( mLastMouseEvent );
  1547. // Also cancel any current dragging operation since it would only be
  1548. // valid if the mouse down event occurred first.
  1549. mMouseDown = false;
  1550. }
  1551. // Update mCurrentAlignment
  1552. // Changing the alignment during a drag could be really bad.
  1553. // Haven't actually tested this though.
  1554. if ( mMouseDown )
  1555. return;
  1556. GizmoAlignment desired = _filteredAlignment();
  1557. if ( desired == World &&
  1558. mCurrentAlignment == Object )
  1559. {
  1560. mObjectMat = mTransform;
  1561. mTransform.identity();
  1562. mTransform.setPosition( mObjectMat.getPosition() );
  1563. }
  1564. else if ( desired == Object &&
  1565. mCurrentAlignment == World )
  1566. {
  1567. Point3F pos = mTransform.getPosition();
  1568. mTransform = mObjectMat;
  1569. mTransform.setPosition( pos );
  1570. mObjectMat.identity();
  1571. mObjectMat.setPosition( pos );
  1572. }
  1573. mCurrentAlignment = desired;
  1574. mObjectMat.invertTo( &mObjectMatInv );
  1575. }
  1576. void Gizmo::_updateEnabledAxices()
  1577. {
  1578. if ( ( mProfile->mode == ScaleMode && mProfile->flags & GizmoProfile::CanScaleUniform ) ||
  1579. ( mProfile->mode == MoveMode && mProfile->flags & GizmoProfile::CanTranslateUniform ) ||
  1580. ( mProfile->mode == RotateMode && mProfile->flags & GizmoProfile::CanRotateUniform ) )
  1581. mUniformHandleEnabled = true;
  1582. else
  1583. mUniformHandleEnabled = false;
  1584. // Screen / camera relative rotation disabled until it functions properly
  1585. //
  1586. //if ( mProfile->mode == RotateMode && mProfile->flags & GizmoProfile::CanRotateScreen )
  1587. // mScreenRotateHandleEnabled = true;
  1588. //else
  1589. mScreenRotateHandleEnabled = false;
  1590. // Early out if we are in a mode that is disabled.
  1591. if ( mProfile->mode == RotateMode && !(mProfile->flags & GizmoProfile::CanRotate ) )
  1592. {
  1593. mAxisEnabled[0] = mAxisEnabled[1] = mAxisEnabled[2] = false;
  1594. return;
  1595. }
  1596. if ( mProfile->mode == MoveMode && !(mProfile->flags & GizmoProfile::CanTranslate ) )
  1597. {
  1598. mAxisEnabled[0] = mAxisEnabled[1] = mAxisEnabled[2] = false;
  1599. return;
  1600. }
  1601. if ( mProfile->mode == ScaleMode && !(mProfile->flags & GizmoProfile::CanScale ) )
  1602. {
  1603. mAxisEnabled[0] = mAxisEnabled[1] = mAxisEnabled[2] = false;
  1604. return;
  1605. }
  1606. for ( U32 i = 0; i < 3; i++ )
  1607. {
  1608. mAxisEnabled[i] = false;
  1609. // Some tricky enum math... x/y/z are sequential in the enum
  1610. if ( ( mProfile->mode == RotateMode ) &&
  1611. !( mProfile->flags & ( GizmoProfile::CanRotateX << i ) ) )
  1612. continue;
  1613. if ( ( mProfile->mode == MoveMode ) &&
  1614. !( mProfile->flags & ( GizmoProfile::CanTranslateX << i ) ) )
  1615. continue;
  1616. if ( ( mProfile->mode == ScaleMode ) &&
  1617. !( mProfile->flags & ( GizmoProfile::CanScaleX << i ) ) )
  1618. continue;
  1619. mAxisEnabled[i] = true;
  1620. }
  1621. }