ImGuizmo.cpp 112 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996
  1. // https://github.com/CedricGuillemet/ImGuizmo
  2. // v 1.89 WIP
  3. //
  4. // The MIT License(MIT)
  5. //
  6. // Copyright(c) 2021 Cedric Guillemet
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a copy
  9. // of this software and associated documentation files(the "Software"), to deal
  10. // in the Software without restriction, including without limitation the rights
  11. // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
  12. // copies of the Software, and to permit persons to whom the Software is
  13. // furnished to do so, subject to the following conditions :
  14. //
  15. // The above copyright notice and this permission notice shall be included in all
  16. // copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. // SOFTWARE.
  25. //
  26. #ifndef IMGUI_DEFINE_MATH_OPERATORS
  27. #define IMGUI_DEFINE_MATH_OPERATORS
  28. #endif
  29. #include "imgui.h"
  30. #include "imgui_internal.h"
  31. #include "ImGuizmo.h"
  32. #if defined(_MSC_VER) || defined(__MINGW32__)
  33. #include <malloc.h>
  34. #endif
  35. #if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
  36. #define _malloca(x) alloca(x)
  37. #define _freea(x)
  38. #endif
  39. // includes patches for multiview from
  40. // https://github.com/CedricGuillemet/ImGuizmo/issues/15
  41. namespace IMGUIZMO_NAMESPACE
  42. {
  43. static const float ZPI = 3.14159265358979323846f;
  44. static const float RAD2DEG = (180.f / ZPI);
  45. static const float DEG2RAD = (ZPI / 180.f);
  46. const float screenRotateSize = 0.06f;
  47. // scale a bit so translate axis do not touch when in universal
  48. const float rotationDisplayFactor = 1.2f;
  49. static OPERATION operator&(OPERATION lhs, OPERATION rhs)
  50. {
  51. return static_cast<OPERATION>(static_cast<int>(lhs) & static_cast<int>(rhs));
  52. }
  53. static bool operator!=(OPERATION lhs, int rhs)
  54. {
  55. return static_cast<int>(lhs) != rhs;
  56. }
  57. static bool Intersects(OPERATION lhs, OPERATION rhs)
  58. {
  59. return (lhs & rhs) != 0;
  60. }
  61. // True if lhs contains rhs
  62. static bool Contains(OPERATION lhs, OPERATION rhs)
  63. {
  64. return (lhs & rhs) == rhs;
  65. }
  66. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  67. // utility and math
  68. void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r)
  69. {
  70. r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
  71. r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
  72. r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
  73. r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
  74. r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
  75. r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
  76. r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
  77. r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
  78. r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
  79. r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
  80. r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
  81. r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
  82. r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
  83. r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
  84. r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
  85. r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
  86. }
  87. void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16)
  88. {
  89. float temp, temp2, temp3, temp4;
  90. temp = 2.0f * znear;
  91. temp2 = right - left;
  92. temp3 = top - bottom;
  93. temp4 = zfar - znear;
  94. m16[0] = temp / temp2;
  95. m16[1] = 0.0;
  96. m16[2] = 0.0;
  97. m16[3] = 0.0;
  98. m16[4] = 0.0;
  99. m16[5] = temp / temp3;
  100. m16[6] = 0.0;
  101. m16[7] = 0.0;
  102. m16[8] = (right + left) / temp2;
  103. m16[9] = (top + bottom) / temp3;
  104. m16[10] = (-zfar - znear) / temp4;
  105. m16[11] = -1.0f;
  106. m16[12] = 0.0;
  107. m16[13] = 0.0;
  108. m16[14] = (-temp * zfar) / temp4;
  109. m16[15] = 0.0;
  110. }
  111. void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16)
  112. {
  113. float ymax, xmax;
  114. ymax = znear * tanf(fovyInDegrees * DEG2RAD);
  115. xmax = ymax * aspectRatio;
  116. Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16);
  117. }
  118. void Cross(const float* a, const float* b, float* r)
  119. {
  120. r[0] = a[1] * b[2] - a[2] * b[1];
  121. r[1] = a[2] * b[0] - a[0] * b[2];
  122. r[2] = a[0] * b[1] - a[1] * b[0];
  123. }
  124. float Dot(const float* a, const float* b)
  125. {
  126. return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
  127. }
  128. void Normalize(const float* a, float* r)
  129. {
  130. float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON);
  131. r[0] = a[0] * il;
  132. r[1] = a[1] * il;
  133. r[2] = a[2] * il;
  134. }
  135. void LookAt(const float* eye, const float* at, const float* up, float* m16)
  136. {
  137. float X[3], Y[3], Z[3], tmp[3];
  138. tmp[0] = eye[0] - at[0];
  139. tmp[1] = eye[1] - at[1];
  140. tmp[2] = eye[2] - at[2];
  141. Normalize(tmp, Z);
  142. Normalize(up, Y);
  143. Cross(Y, Z, tmp);
  144. Normalize(tmp, X);
  145. Cross(Z, X, tmp);
  146. Normalize(tmp, Y);
  147. m16[0] = X[0];
  148. m16[1] = Y[0];
  149. m16[2] = Z[0];
  150. m16[3] = 0.0f;
  151. m16[4] = X[1];
  152. m16[5] = Y[1];
  153. m16[6] = Z[1];
  154. m16[7] = 0.0f;
  155. m16[8] = X[2];
  156. m16[9] = Y[2];
  157. m16[10] = Z[2];
  158. m16[11] = 0.0f;
  159. m16[12] = -Dot(X, eye);
  160. m16[13] = -Dot(Y, eye);
  161. m16[14] = -Dot(Z, eye);
  162. m16[15] = 1.0f;
  163. }
  164. template <typename T> T Clamp(T x, T y, T z) { return ((x < y) ? y : ((x > z) ? z : x)); }
  165. template <typename T> T max(T x, T y) { return (x > y) ? x : y; }
  166. template <typename T> T min(T x, T y) { return (x < y) ? x : y; }
  167. template <typename T> bool IsWithin(T x, T y, T z) { return (x >= y) && (x <= z); }
  168. struct matrix_t;
  169. struct vec_t
  170. {
  171. public:
  172. float x, y, z, w;
  173. void Lerp(const vec_t& v, float t)
  174. {
  175. x += (v.x - x) * t;
  176. y += (v.y - y) * t;
  177. z += (v.z - z) * t;
  178. w += (v.w - w) * t;
  179. }
  180. void Set(float v) { x = y = z = w = v; }
  181. void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; }
  182. vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }
  183. vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }
  184. vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; }
  185. vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
  186. vec_t operator * (float f) const;
  187. vec_t operator - () const;
  188. vec_t operator - (const vec_t& v) const;
  189. vec_t operator + (const vec_t& v) const;
  190. vec_t operator * (const vec_t& v) const;
  191. const vec_t& operator + () const { return (*this); }
  192. float Length() const { return sqrtf(x * x + y * y + z * z); };
  193. float LengthSq() const { return (x * x + y * y + z * z); };
  194. vec_t Normalize() { (*this) *= (1.f / ( Length() > FLT_EPSILON ? Length() : FLT_EPSILON ) ); return (*this); }
  195. vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
  196. vec_t Abs() const;
  197. void Cross(const vec_t& v)
  198. {
  199. vec_t res;
  200. res.x = y * v.z - z * v.y;
  201. res.y = z * v.x - x * v.z;
  202. res.z = x * v.y - y * v.x;
  203. x = res.x;
  204. y = res.y;
  205. z = res.z;
  206. w = 0.f;
  207. }
  208. void Cross(const vec_t& v1, const vec_t& v2)
  209. {
  210. x = v1.y * v2.z - v1.z * v2.y;
  211. y = v1.z * v2.x - v1.x * v2.z;
  212. z = v1.x * v2.y - v1.y * v2.x;
  213. w = 0.f;
  214. }
  215. float Dot(const vec_t& v) const
  216. {
  217. return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w);
  218. }
  219. float Dot3(const vec_t& v) const
  220. {
  221. return (x * v.x) + (y * v.y) + (z * v.z);
  222. }
  223. void Transform(const matrix_t& matrix);
  224. void Transform(const vec_t& s, const matrix_t& matrix);
  225. void TransformVector(const matrix_t& matrix);
  226. void TransformPoint(const matrix_t& matrix);
  227. void TransformVector(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformVector(matrix); }
  228. void TransformPoint(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformPoint(matrix); }
  229. float& operator [] (size_t index) { return ((float*)&x)[index]; }
  230. const float& operator [] (size_t index) const { return ((float*)&x)[index]; }
  231. bool operator!=(const vec_t& other) const { return memcmp(this, &other, sizeof(vec_t)) != 0; }
  232. };
  233. vec_t makeVect(float _x, float _y, float _z = 0.f, float _w = 0.f) { vec_t res; res.x = _x; res.y = _y; res.z = _z; res.w = _w; return res; }
  234. vec_t makeVect(ImVec2 v) { vec_t res; res.x = v.x; res.y = v.y; res.z = 0.f; res.w = 0.f; return res; }
  235. vec_t vec_t::operator * (float f) const { return makeVect(x * f, y * f, z * f, w * f); }
  236. vec_t vec_t::operator - () const { return makeVect(-x, -y, -z, -w); }
  237. vec_t vec_t::operator - (const vec_t& v) const { return makeVect(x - v.x, y - v.y, z - v.z, w - v.w); }
  238. vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }
  239. vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }
  240. vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); }
  241. vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; }
  242. vec_t Cross(const vec_t& v1, const vec_t& v2)
  243. {
  244. vec_t res;
  245. res.x = v1.y * v2.z - v1.z * v2.y;
  246. res.y = v1.z * v2.x - v1.x * v2.z;
  247. res.z = v1.x * v2.y - v1.y * v2.x;
  248. res.w = 0.f;
  249. return res;
  250. }
  251. float Dot(const vec_t& v1, const vec_t& v2)
  252. {
  253. return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
  254. }
  255. vec_t BuildPlan(const vec_t& p_point1, const vec_t& p_normal)
  256. {
  257. vec_t normal, res;
  258. normal.Normalize(p_normal);
  259. res.w = normal.Dot(p_point1);
  260. res.x = normal.x;
  261. res.y = normal.y;
  262. res.z = normal.z;
  263. return res;
  264. }
  265. struct matrix_t
  266. {
  267. public:
  268. union
  269. {
  270. float m[4][4];
  271. float m16[16];
  272. struct
  273. {
  274. vec_t right, up, dir, position;
  275. } v;
  276. vec_t component[4];
  277. };
  278. operator float* () { return m16; }
  279. operator const float* () const { return m16; }
  280. void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); }
  281. void Translation(const vec_t& vt)
  282. {
  283. v.right.Set(1.f, 0.f, 0.f, 0.f);
  284. v.up.Set(0.f, 1.f, 0.f, 0.f);
  285. v.dir.Set(0.f, 0.f, 1.f, 0.f);
  286. v.position.Set(vt.x, vt.y, vt.z, 1.f);
  287. }
  288. void Scale(float _x, float _y, float _z)
  289. {
  290. v.right.Set(_x, 0.f, 0.f, 0.f);
  291. v.up.Set(0.f, _y, 0.f, 0.f);
  292. v.dir.Set(0.f, 0.f, _z, 0.f);
  293. v.position.Set(0.f, 0.f, 0.f, 1.f);
  294. }
  295. void Scale(const vec_t& s) { Scale(s.x, s.y, s.z); }
  296. matrix_t& operator *= (const matrix_t& mat)
  297. {
  298. matrix_t tmpMat;
  299. tmpMat = *this;
  300. tmpMat.Multiply(mat);
  301. *this = tmpMat;
  302. return *this;
  303. }
  304. matrix_t operator * (const matrix_t& mat) const
  305. {
  306. matrix_t matT;
  307. matT.Multiply(*this, mat);
  308. return matT;
  309. }
  310. void Multiply(const matrix_t& matrix)
  311. {
  312. matrix_t tmp;
  313. tmp = *this;
  314. FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this);
  315. }
  316. void Multiply(const matrix_t& m1, const matrix_t& m2)
  317. {
  318. FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this);
  319. }
  320. float GetDeterminant() const
  321. {
  322. return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] -
  323. m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1];
  324. }
  325. float Inverse(const matrix_t& srcMatrix, bool affine = false);
  326. void SetToIdentity()
  327. {
  328. v.right.Set(1.f, 0.f, 0.f, 0.f);
  329. v.up.Set(0.f, 1.f, 0.f, 0.f);
  330. v.dir.Set(0.f, 0.f, 1.f, 0.f);
  331. v.position.Set(0.f, 0.f, 0.f, 1.f);
  332. }
  333. void Transpose()
  334. {
  335. matrix_t tmpm;
  336. for (int l = 0; l < 4; l++)
  337. {
  338. for (int c = 0; c < 4; c++)
  339. {
  340. tmpm.m[l][c] = m[c][l];
  341. }
  342. }
  343. (*this) = tmpm;
  344. }
  345. void RotationAxis(const vec_t& axis, float angle);
  346. void OrthoNormalize()
  347. {
  348. v.right.Normalize();
  349. v.up.Normalize();
  350. v.dir.Normalize();
  351. }
  352. };
  353. void vec_t::Transform(const matrix_t& matrix)
  354. {
  355. vec_t out;
  356. out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + w * matrix.m[3][0];
  357. out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + w * matrix.m[3][1];
  358. out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + w * matrix.m[3][2];
  359. out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + w * matrix.m[3][3];
  360. x = out.x;
  361. y = out.y;
  362. z = out.z;
  363. w = out.w;
  364. }
  365. void vec_t::Transform(const vec_t& s, const matrix_t& matrix)
  366. {
  367. *this = s;
  368. Transform(matrix);
  369. }
  370. void vec_t::TransformPoint(const matrix_t& matrix)
  371. {
  372. vec_t out;
  373. out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0];
  374. out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1];
  375. out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2];
  376. out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3];
  377. x = out.x;
  378. y = out.y;
  379. z = out.z;
  380. w = out.w;
  381. }
  382. void vec_t::TransformVector(const matrix_t& matrix)
  383. {
  384. vec_t out;
  385. out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0];
  386. out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1];
  387. out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2];
  388. out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3];
  389. x = out.x;
  390. y = out.y;
  391. z = out.z;
  392. w = out.w;
  393. }
  394. float matrix_t::Inverse(const matrix_t& srcMatrix, bool affine)
  395. {
  396. float det = 0;
  397. if (affine)
  398. {
  399. det = GetDeterminant();
  400. float s = 1 / det;
  401. m[0][0] = (srcMatrix.m[1][1] * srcMatrix.m[2][2] - srcMatrix.m[1][2] * srcMatrix.m[2][1]) * s;
  402. m[0][1] = (srcMatrix.m[2][1] * srcMatrix.m[0][2] - srcMatrix.m[2][2] * srcMatrix.m[0][1]) * s;
  403. m[0][2] = (srcMatrix.m[0][1] * srcMatrix.m[1][2] - srcMatrix.m[0][2] * srcMatrix.m[1][1]) * s;
  404. m[1][0] = (srcMatrix.m[1][2] * srcMatrix.m[2][0] - srcMatrix.m[1][0] * srcMatrix.m[2][2]) * s;
  405. m[1][1] = (srcMatrix.m[2][2] * srcMatrix.m[0][0] - srcMatrix.m[2][0] * srcMatrix.m[0][2]) * s;
  406. m[1][2] = (srcMatrix.m[0][2] * srcMatrix.m[1][0] - srcMatrix.m[0][0] * srcMatrix.m[1][2]) * s;
  407. m[2][0] = (srcMatrix.m[1][0] * srcMatrix.m[2][1] - srcMatrix.m[1][1] * srcMatrix.m[2][0]) * s;
  408. m[2][1] = (srcMatrix.m[2][0] * srcMatrix.m[0][1] - srcMatrix.m[2][1] * srcMatrix.m[0][0]) * s;
  409. m[2][2] = (srcMatrix.m[0][0] * srcMatrix.m[1][1] - srcMatrix.m[0][1] * srcMatrix.m[1][0]) * s;
  410. m[3][0] = -(m[0][0] * srcMatrix.m[3][0] + m[1][0] * srcMatrix.m[3][1] + m[2][0] * srcMatrix.m[3][2]);
  411. m[3][1] = -(m[0][1] * srcMatrix.m[3][0] + m[1][1] * srcMatrix.m[3][1] + m[2][1] * srcMatrix.m[3][2]);
  412. m[3][2] = -(m[0][2] * srcMatrix.m[3][0] + m[1][2] * srcMatrix.m[3][1] + m[2][2] * srcMatrix.m[3][2]);
  413. }
  414. else
  415. {
  416. // transpose matrix
  417. float src[16];
  418. for (int i = 0; i < 4; ++i)
  419. {
  420. src[i] = srcMatrix.m16[i * 4];
  421. src[i + 4] = srcMatrix.m16[i * 4 + 1];
  422. src[i + 8] = srcMatrix.m16[i * 4 + 2];
  423. src[i + 12] = srcMatrix.m16[i * 4 + 3];
  424. }
  425. // calculate pairs for first 8 elements (cofactors)
  426. float tmp[12]; // temp array for pairs
  427. tmp[0] = src[10] * src[15];
  428. tmp[1] = src[11] * src[14];
  429. tmp[2] = src[9] * src[15];
  430. tmp[3] = src[11] * src[13];
  431. tmp[4] = src[9] * src[14];
  432. tmp[5] = src[10] * src[13];
  433. tmp[6] = src[8] * src[15];
  434. tmp[7] = src[11] * src[12];
  435. tmp[8] = src[8] * src[14];
  436. tmp[9] = src[10] * src[12];
  437. tmp[10] = src[8] * src[13];
  438. tmp[11] = src[9] * src[12];
  439. // calculate first 8 elements (cofactors)
  440. m16[0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]);
  441. m16[1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]);
  442. m16[2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]);
  443. m16[3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]);
  444. m16[4] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]);
  445. m16[5] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]);
  446. m16[6] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]);
  447. m16[7] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]);
  448. // calculate pairs for second 8 elements (cofactors)
  449. tmp[0] = src[2] * src[7];
  450. tmp[1] = src[3] * src[6];
  451. tmp[2] = src[1] * src[7];
  452. tmp[3] = src[3] * src[5];
  453. tmp[4] = src[1] * src[6];
  454. tmp[5] = src[2] * src[5];
  455. tmp[6] = src[0] * src[7];
  456. tmp[7] = src[3] * src[4];
  457. tmp[8] = src[0] * src[6];
  458. tmp[9] = src[2] * src[4];
  459. tmp[10] = src[0] * src[5];
  460. tmp[11] = src[1] * src[4];
  461. // calculate second 8 elements (cofactors)
  462. m16[8] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]);
  463. m16[9] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]);
  464. m16[10] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]);
  465. m16[11] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]);
  466. m16[12] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]);
  467. m16[13] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]);
  468. m16[14] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]);
  469. m16[15] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]);
  470. // calculate determinant
  471. det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3];
  472. // calculate matrix inverse
  473. float invdet = 1 / det;
  474. for (int j = 0; j < 16; ++j)
  475. {
  476. m16[j] *= invdet;
  477. }
  478. }
  479. return det;
  480. }
  481. void matrix_t::RotationAxis(const vec_t& axis, float angle)
  482. {
  483. float length2 = axis.LengthSq();
  484. if (length2 < FLT_EPSILON)
  485. {
  486. SetToIdentity();
  487. return;
  488. }
  489. vec_t n = axis * (1.f / sqrtf(length2));
  490. float s = sinf(angle);
  491. float c = cosf(angle);
  492. float k = 1.f - c;
  493. float xx = n.x * n.x * k + c;
  494. float yy = n.y * n.y * k + c;
  495. float zz = n.z * n.z * k + c;
  496. float xy = n.x * n.y * k;
  497. float yz = n.y * n.z * k;
  498. float zx = n.z * n.x * k;
  499. float xs = n.x * s;
  500. float ys = n.y * s;
  501. float zs = n.z * s;
  502. m[0][0] = xx;
  503. m[0][1] = xy + zs;
  504. m[0][2] = zx - ys;
  505. m[0][3] = 0.f;
  506. m[1][0] = xy - zs;
  507. m[1][1] = yy;
  508. m[1][2] = yz + xs;
  509. m[1][3] = 0.f;
  510. m[2][0] = zx + ys;
  511. m[2][1] = yz - xs;
  512. m[2][2] = zz;
  513. m[2][3] = 0.f;
  514. m[3][0] = 0.f;
  515. m[3][1] = 0.f;
  516. m[3][2] = 0.f;
  517. m[3][3] = 1.f;
  518. }
  519. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  520. //
  521. enum MOVETYPE
  522. {
  523. MT_NONE,
  524. MT_MOVE_X,
  525. MT_MOVE_Y,
  526. MT_MOVE_Z,
  527. MT_MOVE_YZ,
  528. MT_MOVE_ZX,
  529. MT_MOVE_XY,
  530. MT_MOVE_SCREEN,
  531. MT_ROTATE_X,
  532. MT_ROTATE_Y,
  533. MT_ROTATE_Z,
  534. MT_ROTATE_SCREEN,
  535. MT_SCALE_X,
  536. MT_SCALE_Y,
  537. MT_SCALE_Z,
  538. MT_SCALE_XYZ
  539. };
  540. static bool IsTranslateType(int type)
  541. {
  542. return type >= MT_MOVE_X && type <= MT_MOVE_SCREEN;
  543. }
  544. static bool IsRotateType(int type)
  545. {
  546. return type >= MT_ROTATE_X && type <= MT_ROTATE_SCREEN;
  547. }
  548. static bool IsScaleType(int type)
  549. {
  550. return type >= MT_SCALE_X && type <= MT_SCALE_XYZ;
  551. }
  552. // Matches MT_MOVE_AB order
  553. static const OPERATION TRANSLATE_PLANS[3] = { TRANSLATE_Y | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Y };
  554. Style::Style()
  555. {
  556. // default values
  557. TranslationLineThickness = 3.0f;
  558. TranslationLineArrowSize = 6.0f;
  559. RotationLineThickness = 2.0f;
  560. RotationOuterLineThickness = 3.0f;
  561. ScaleLineThickness = 3.0f;
  562. ScaleLineCircleSize = 6.0f;
  563. HatchedAxisLineThickness = 6.0f;
  564. CenterCircleSize = 6.0f;
  565. // initialize default colors
  566. Colors[DIRECTION_X] = ImVec4(0.666f, 0.000f, 0.000f, 1.000f);
  567. Colors[DIRECTION_Y] = ImVec4(0.000f, 0.666f, 0.000f, 1.000f);
  568. Colors[DIRECTION_Z] = ImVec4(0.000f, 0.000f, 0.666f, 1.000f);
  569. Colors[PLANE_X] = ImVec4(0.666f, 0.000f, 0.000f, 0.380f);
  570. Colors[PLANE_Y] = ImVec4(0.000f, 0.666f, 0.000f, 0.380f);
  571. Colors[PLANE_Z] = ImVec4(0.000f, 0.000f, 0.666f, 0.380f);
  572. Colors[SELECTION] = ImVec4(1.000f, 0.500f, 0.062f, 0.541f);
  573. Colors[INACTIVE] = ImVec4(0.600f, 0.600f, 0.600f, 0.600f);
  574. Colors[TRANSLATION_LINE] = ImVec4(0.666f, 0.666f, 0.666f, 0.666f);
  575. Colors[SCALE_LINE] = ImVec4(0.250f, 0.250f, 0.250f, 1.000f);
  576. Colors[ROTATION_USING_BORDER] = ImVec4(1.000f, 0.500f, 0.062f, 1.000f);
  577. Colors[ROTATION_USING_FILL] = ImVec4(1.000f, 0.500f, 0.062f, 0.500f);
  578. Colors[HATCHED_AXIS_LINES] = ImVec4(0.000f, 0.000f, 0.000f, 0.500f);
  579. Colors[TEXT] = ImVec4(1.000f, 1.000f, 1.000f, 1.000f);
  580. Colors[TEXT_SHADOW] = ImVec4(0.000f, 0.000f, 0.000f, 1.000f);
  581. }
  582. struct Context
  583. {
  584. Context() : mbUsing(false), mbEnable(true), mbUsingBounds(false)
  585. {
  586. }
  587. ImDrawList* mDrawList;
  588. Style mStyle;
  589. MODE mMode;
  590. matrix_t mViewMat;
  591. matrix_t mProjectionMat;
  592. matrix_t mModel;
  593. matrix_t mModelLocal; // orthonormalized model
  594. matrix_t mModelInverse;
  595. matrix_t mModelSource;
  596. matrix_t mModelSourceInverse;
  597. matrix_t mMVP;
  598. matrix_t mMVPLocal; // MVP with full model matrix whereas mMVP's model matrix might only be translation in case of World space edition
  599. matrix_t mViewProjection;
  600. vec_t mModelScaleOrigin;
  601. vec_t mCameraEye;
  602. vec_t mCameraRight;
  603. vec_t mCameraDir;
  604. vec_t mCameraUp;
  605. vec_t mRayOrigin;
  606. vec_t mRayVector;
  607. float mRadiusSquareCenter;
  608. ImVec2 mScreenSquareCenter;
  609. ImVec2 mScreenSquareMin;
  610. ImVec2 mScreenSquareMax;
  611. float mScreenFactor;
  612. vec_t mRelativeOrigin;
  613. bool mbUsing;
  614. bool mbEnable;
  615. bool mbMouseOver;
  616. bool mReversed; // reversed projection matrix
  617. // translation
  618. vec_t mTranslationPlan;
  619. vec_t mTranslationPlanOrigin;
  620. vec_t mMatrixOrigin;
  621. vec_t mTranslationLastDelta;
  622. // rotation
  623. vec_t mRotationVectorSource;
  624. float mRotationAngle;
  625. float mRotationAngleOrigin;
  626. //vec_t mWorldToLocalAxis;
  627. // scale
  628. vec_t mScale;
  629. vec_t mScaleValueOrigin;
  630. vec_t mScaleLast;
  631. float mSaveMousePosx;
  632. // save axis factor when using gizmo
  633. bool mBelowAxisLimit[3];
  634. bool mBelowPlaneLimit[3];
  635. float mAxisFactor[3];
  636. float mAxisLimit=0.0025f;
  637. float mPlaneLimit=0.02f;
  638. // bounds stretching
  639. vec_t mBoundsPivot;
  640. vec_t mBoundsAnchor;
  641. vec_t mBoundsPlan;
  642. vec_t mBoundsLocalPivot;
  643. int mBoundsBestAxis;
  644. int mBoundsAxis[2];
  645. bool mbUsingBounds;
  646. matrix_t mBoundsMatrix;
  647. //
  648. int mCurrentOperation;
  649. float mX = 0.f;
  650. float mY = 0.f;
  651. float mWidth = 0.f;
  652. float mHeight = 0.f;
  653. float mXMax = 0.f;
  654. float mYMax = 0.f;
  655. float mDisplayRatio = 1.f;
  656. bool mIsOrthographic = false;
  657. int mActualID = -1;
  658. int mEditingID = -1;
  659. OPERATION mOperation = OPERATION(-1);
  660. bool mAllowAxisFlip = true;
  661. float mGizmoSizeClipSpace = 0.1f;
  662. };
  663. static Context gContext;
  664. static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) };
  665. static const char* translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f",
  666. "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f",
  667. "X : %5.3f Y : %5.3f Z : %5.3f" };
  668. static const char* scaleInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "XYZ : %5.2f" };
  669. static const char* rotationInfoMask[] = { "X : %5.2f deg %5.2f rad", "Y : %5.2f deg %5.2f rad", "Z : %5.2f deg %5.2f rad", "Screen : %5.2f deg %5.2f rad" };
  670. static const int translationInfoIndex[] = { 0,0,0, 1,0,0, 2,0,0, 1,2,0, 0,2,0, 0,1,0, 0,1,2 };
  671. static const float quadMin = 0.5f;
  672. static const float quadMax = 0.8f;
  673. static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin };
  674. static const int halfCircleSegmentCount = 64;
  675. static const float snapTension = 0.5f;
  676. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  677. //
  678. static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion);
  679. static int GetRotateType(OPERATION op);
  680. static int GetScaleType(OPERATION op);
  681. Style& GetStyle()
  682. {
  683. return gContext.mStyle;
  684. }
  685. static ImU32 GetColorU32(int idx)
  686. {
  687. IM_ASSERT(idx < COLOR::COUNT);
  688. return ImGui::ColorConvertFloat4ToU32(gContext.mStyle.Colors[idx]);
  689. }
  690. static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))
  691. {
  692. vec_t trans;
  693. trans.TransformPoint(worldPos, mat);
  694. trans *= 0.5f / trans.w;
  695. trans += makeVect(0.5f, 0.5f);
  696. trans.y = 1.f - trans.y;
  697. trans.x *= size.x;
  698. trans.y *= size.y;
  699. trans.x += position.x;
  700. trans.y += position.y;
  701. return ImVec2(trans.x, trans.y);
  702. }
  703. static void ComputeCameraRay(vec_t& rayOrigin, vec_t& rayDir, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))
  704. {
  705. ImGuiIO& io = ImGui::GetIO();
  706. matrix_t mViewProjInverse;
  707. mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat);
  708. const float mox = ((io.MousePos.x - position.x) / size.x) * 2.f - 1.f;
  709. const float moy = (1.f - ((io.MousePos.y - position.y) / size.y)) * 2.f - 1.f;
  710. const float zNear = gContext.mReversed ? (1.f - FLT_EPSILON) : 0.f;
  711. const float zFar = gContext.mReversed ? 0.f : (1.f - FLT_EPSILON);
  712. rayOrigin.Transform(makeVect(mox, moy, zNear, 1.f), mViewProjInverse);
  713. rayOrigin *= 1.f / rayOrigin.w;
  714. vec_t rayEnd;
  715. rayEnd.Transform(makeVect(mox, moy, zFar, 1.f), mViewProjInverse);
  716. rayEnd *= 1.f / rayEnd.w;
  717. rayDir = Normalized(rayEnd - rayOrigin);
  718. }
  719. static float GetSegmentLengthClipSpace(const vec_t& start, const vec_t& end, const bool localCoordinates = false)
  720. {
  721. vec_t startOfSegment = start;
  722. const matrix_t& mvp = localCoordinates ? gContext.mMVPLocal : gContext.mMVP;
  723. startOfSegment.TransformPoint(mvp);
  724. if (fabsf(startOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction
  725. {
  726. startOfSegment *= 1.f / startOfSegment.w;
  727. }
  728. vec_t endOfSegment = end;
  729. endOfSegment.TransformPoint(mvp);
  730. if (fabsf(endOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction
  731. {
  732. endOfSegment *= 1.f / endOfSegment.w;
  733. }
  734. vec_t clipSpaceAxis = endOfSegment - startOfSegment;
  735. if (gContext.mDisplayRatio < 1.0)
  736. clipSpaceAxis.x *= gContext.mDisplayRatio;
  737. else
  738. clipSpaceAxis.y /= gContext.mDisplayRatio;
  739. float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x * clipSpaceAxis.x + clipSpaceAxis.y * clipSpaceAxis.y);
  740. return segmentLengthInClipSpace;
  741. }
  742. static float GetParallelogram(const vec_t& ptO, const vec_t& ptA, const vec_t& ptB)
  743. {
  744. vec_t pts[] = { ptO, ptA, ptB };
  745. for (unsigned int i = 0; i < 3; i++)
  746. {
  747. pts[i].TransformPoint(gContext.mMVP);
  748. if (fabsf(pts[i].w) > FLT_EPSILON) // check for axis aligned with camera direction
  749. {
  750. pts[i] *= 1.f / pts[i].w;
  751. }
  752. }
  753. vec_t segA = pts[1] - pts[0];
  754. vec_t segB = pts[2] - pts[0];
  755. segA.y /= gContext.mDisplayRatio;
  756. segB.y /= gContext.mDisplayRatio;
  757. vec_t segAOrtho = makeVect(-segA.y, segA.x);
  758. segAOrtho.Normalize();
  759. float dt = segAOrtho.Dot3(segB);
  760. float surface = sqrtf(segA.x * segA.x + segA.y * segA.y) * fabsf(dt);
  761. return surface;
  762. }
  763. inline vec_t PointOnSegment(const vec_t& point, const vec_t& vertPos1, const vec_t& vertPos2)
  764. {
  765. vec_t c = point - vertPos1;
  766. vec_t V;
  767. V.Normalize(vertPos2 - vertPos1);
  768. float d = (vertPos2 - vertPos1).Length();
  769. float t = V.Dot3(c);
  770. if (t < 0.f)
  771. {
  772. return vertPos1;
  773. }
  774. if (t > d)
  775. {
  776. return vertPos2;
  777. }
  778. return vertPos1 + V * t;
  779. }
  780. static float IntersectRayPlane(const vec_t& rOrigin, const vec_t& rVector, const vec_t& plan)
  781. {
  782. const float numer = plan.Dot3(rOrigin) - plan.w;
  783. const float denom = plan.Dot3(rVector);
  784. if (fabsf(denom) < FLT_EPSILON) // normal is orthogonal to vector, cant intersect
  785. {
  786. return -1.0f;
  787. }
  788. return -(numer / denom);
  789. }
  790. static float DistanceToPlane(const vec_t& point, const vec_t& plan)
  791. {
  792. return plan.Dot3(point) + plan.w;
  793. }
  794. static bool IsInContextRect(ImVec2 p)
  795. {
  796. return IsWithin(p.x, gContext.mX, gContext.mXMax) && IsWithin(p.y, gContext.mY, gContext.mYMax);
  797. }
  798. static bool IsHoveringWindow()
  799. {
  800. ImGuiContext& g = *ImGui::GetCurrentContext();
  801. ImGuiWindow* window = ImGui::FindWindowByName(gContext.mDrawList->_OwnerName);
  802. if (g.HoveredWindow == window) // Mouse hovering drawlist window
  803. return true;
  804. if (g.HoveredWindow != NULL) // Any other window is hovered
  805. return false;
  806. if (ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max, false)) // Hovering drawlist window rect, while no other window is hovered (for _NoInputs windows)
  807. return true;
  808. return false;
  809. }
  810. void SetRect(float x, float y, float width, float height)
  811. {
  812. gContext.mX = x;
  813. gContext.mY = y;
  814. gContext.mWidth = width;
  815. gContext.mHeight = height;
  816. gContext.mXMax = gContext.mX + gContext.mWidth;
  817. gContext.mYMax = gContext.mY + gContext.mXMax;
  818. gContext.mDisplayRatio = width / height;
  819. }
  820. void SetOrthographic(bool isOrthographic)
  821. {
  822. gContext.mIsOrthographic = isOrthographic;
  823. }
  824. void SetDrawlist(ImDrawList* drawlist)
  825. {
  826. gContext.mDrawList = drawlist ? drawlist : ImGui::GetWindowDrawList();
  827. }
  828. void SetImGuiContext(ImGuiContext* ctx)
  829. {
  830. ImGui::SetCurrentContext(ctx);
  831. }
  832. void BeginFrame()
  833. {
  834. const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus;
  835. #ifdef IMGUI_HAS_VIEWPORT
  836. ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size);
  837. ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos);
  838. #else
  839. ImGuiIO& io = ImGui::GetIO();
  840. ImGui::SetNextWindowSize(io.DisplaySize);
  841. ImGui::SetNextWindowPos(ImVec2(0, 0));
  842. #endif
  843. ImGui::PushStyleColor(ImGuiCol_WindowBg, 0);
  844. ImGui::PushStyleColor(ImGuiCol_Border, 0);
  845. ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
  846. ImGui::Begin("gizmo", NULL, flags);
  847. gContext.mDrawList = ImGui::GetWindowDrawList();
  848. ImGui::End();
  849. ImGui::PopStyleVar();
  850. ImGui::PopStyleColor(2);
  851. }
  852. bool IsUsing()
  853. {
  854. return (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) || gContext.mbUsingBounds;
  855. }
  856. bool IsUsingAny()
  857. {
  858. return gContext.mbUsing || gContext.mbUsingBounds;
  859. }
  860. bool IsOver()
  861. {
  862. return (Intersects(gContext.mOperation, TRANSLATE) && GetMoveType(gContext.mOperation, NULL) != MT_NONE) ||
  863. (Intersects(gContext.mOperation, ROTATE) && GetRotateType(gContext.mOperation) != MT_NONE) ||
  864. (Intersects(gContext.mOperation, SCALE) && GetScaleType(gContext.mOperation) != MT_NONE) || IsUsing();
  865. }
  866. bool IsOver(OPERATION op)
  867. {
  868. if(IsUsing())
  869. {
  870. return true;
  871. }
  872. if(Intersects(op, SCALE) && GetScaleType(op) != MT_NONE)
  873. {
  874. return true;
  875. }
  876. if(Intersects(op, ROTATE) && GetRotateType(op) != MT_NONE)
  877. {
  878. return true;
  879. }
  880. if(Intersects(op, TRANSLATE) && GetMoveType(op, NULL) != MT_NONE)
  881. {
  882. return true;
  883. }
  884. return false;
  885. }
  886. void Enable(bool enable)
  887. {
  888. gContext.mbEnable = enable;
  889. if (!enable)
  890. {
  891. gContext.mbUsing = false;
  892. gContext.mbUsingBounds = false;
  893. }
  894. }
  895. static void ComputeContext(const float* view, const float* projection, float* matrix, MODE mode)
  896. {
  897. gContext.mMode = mode;
  898. gContext.mViewMat = *(matrix_t*)view;
  899. gContext.mProjectionMat = *(matrix_t*)projection;
  900. gContext.mbMouseOver = IsHoveringWindow();
  901. gContext.mModelLocal = *(matrix_t*)matrix;
  902. gContext.mModelLocal.OrthoNormalize();
  903. if (mode == LOCAL)
  904. {
  905. gContext.mModel = gContext.mModelLocal;
  906. }
  907. else
  908. {
  909. gContext.mModel.Translation(((matrix_t*)matrix)->v.position);
  910. }
  911. gContext.mModelSource = *(matrix_t*)matrix;
  912. gContext.mModelScaleOrigin.Set(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
  913. gContext.mModelInverse.Inverse(gContext.mModel);
  914. gContext.mModelSourceInverse.Inverse(gContext.mModelSource);
  915. gContext.mViewProjection = gContext.mViewMat * gContext.mProjectionMat;
  916. gContext.mMVP = gContext.mModel * gContext.mViewProjection;
  917. gContext.mMVPLocal = gContext.mModelLocal * gContext.mViewProjection;
  918. matrix_t viewInverse;
  919. viewInverse.Inverse(gContext.mViewMat);
  920. gContext.mCameraDir = viewInverse.v.dir;
  921. gContext.mCameraEye = viewInverse.v.position;
  922. gContext.mCameraRight = viewInverse.v.right;
  923. gContext.mCameraUp = viewInverse.v.up;
  924. // projection reverse
  925. vec_t nearPos, farPos;
  926. nearPos.Transform(makeVect(0, 0, 1.f, 1.f), gContext.mProjectionMat);
  927. farPos.Transform(makeVect(0, 0, 2.f, 1.f), gContext.mProjectionMat);
  928. gContext.mReversed = (nearPos.z/nearPos.w) > (farPos.z / farPos.w);
  929. // compute scale from the size of camera right vector projected on screen at the matrix position
  930. vec_t pointRight = viewInverse.v.right;
  931. pointRight.TransformPoint(gContext.mViewProjection);
  932. gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / (pointRight.x / pointRight.w - gContext.mMVP.v.position.x / gContext.mMVP.v.position.w);
  933. vec_t rightViewInverse = viewInverse.v.right;
  934. rightViewInverse.TransformVector(gContext.mModelInverse);
  935. float rightLength = GetSegmentLengthClipSpace(makeVect(0.f, 0.f), rightViewInverse);
  936. gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / rightLength;
  937. ImVec2 centerSSpace = worldToPos(makeVect(0.f, 0.f), gContext.mMVP);
  938. gContext.mScreenSquareCenter = centerSSpace;
  939. gContext.mScreenSquareMin = ImVec2(centerSSpace.x - 10.f, centerSSpace.y - 10.f);
  940. gContext.mScreenSquareMax = ImVec2(centerSSpace.x + 10.f, centerSSpace.y + 10.f);
  941. ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector);
  942. }
  943. static void ComputeColors(ImU32* colors, int type, OPERATION operation)
  944. {
  945. if (gContext.mbEnable)
  946. {
  947. ImU32 selectionColor = GetColorU32(SELECTION);
  948. switch (operation)
  949. {
  950. case TRANSLATE:
  951. colors[0] = (type == MT_MOVE_SCREEN) ? selectionColor : IM_COL32_WHITE;
  952. for (int i = 0; i < 3; i++)
  953. {
  954. colors[i + 1] = (type == (int)(MT_MOVE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
  955. colors[i + 4] = (type == (int)(MT_MOVE_YZ + i)) ? selectionColor : GetColorU32(PLANE_X + i);
  956. colors[i + 4] = (type == MT_MOVE_SCREEN) ? selectionColor : colors[i + 4];
  957. }
  958. break;
  959. case ROTATE:
  960. colors[0] = (type == MT_ROTATE_SCREEN) ? selectionColor : IM_COL32_WHITE;
  961. for (int i = 0; i < 3; i++)
  962. {
  963. colors[i + 1] = (type == (int)(MT_ROTATE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
  964. }
  965. break;
  966. case SCALEU:
  967. case SCALE:
  968. colors[0] = (type == MT_SCALE_XYZ) ? selectionColor : IM_COL32_WHITE;
  969. for (int i = 0; i < 3; i++)
  970. {
  971. colors[i + 1] = (type == (int)(MT_SCALE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
  972. }
  973. break;
  974. // note: this internal function is only called with three possible values for operation
  975. default:
  976. break;
  977. }
  978. }
  979. else
  980. {
  981. ImU32 inactiveColor = GetColorU32(INACTIVE);
  982. for (int i = 0; i < 7; i++)
  983. {
  984. colors[i] = inactiveColor;
  985. }
  986. }
  987. }
  988. static void ComputeTripodAxisAndVisibility(const int axisIndex, vec_t& dirAxis, vec_t& dirPlaneX, vec_t& dirPlaneY, bool& belowAxisLimit, bool& belowPlaneLimit, const bool localCoordinates = false)
  989. {
  990. dirAxis = directionUnary[axisIndex];
  991. dirPlaneX = directionUnary[(axisIndex + 1) % 3];
  992. dirPlaneY = directionUnary[(axisIndex + 2) % 3];
  993. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
  994. {
  995. // when using, use stored factors so the gizmo doesn't flip when we translate
  996. belowAxisLimit = gContext.mBelowAxisLimit[axisIndex];
  997. belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex];
  998. dirAxis *= gContext.mAxisFactor[axisIndex];
  999. dirPlaneX *= gContext.mAxisFactor[(axisIndex + 1) % 3];
  1000. dirPlaneY *= gContext.mAxisFactor[(axisIndex + 2) % 3];
  1001. }
  1002. else
  1003. {
  1004. // new method
  1005. float lenDir = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis, localCoordinates);
  1006. float lenDirMinus = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirAxis, localCoordinates);
  1007. float lenDirPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneX, localCoordinates);
  1008. float lenDirMinusPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneX, localCoordinates);
  1009. float lenDirPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneY, localCoordinates);
  1010. float lenDirMinusPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneY, localCoordinates);
  1011. // For readability
  1012. bool & allowFlip = gContext.mAllowAxisFlip;
  1013. float mulAxis = (allowFlip && lenDir < lenDirMinus&& fabsf(lenDir - lenDirMinus) > FLT_EPSILON) ? -1.f : 1.f;
  1014. float mulAxisX = (allowFlip && lenDirPlaneX < lenDirMinusPlaneX&& fabsf(lenDirPlaneX - lenDirMinusPlaneX) > FLT_EPSILON) ? -1.f : 1.f;
  1015. float mulAxisY = (allowFlip && lenDirPlaneY < lenDirMinusPlaneY&& fabsf(lenDirPlaneY - lenDirMinusPlaneY) > FLT_EPSILON) ? -1.f : 1.f;
  1016. dirAxis *= mulAxis;
  1017. dirPlaneX *= mulAxisX;
  1018. dirPlaneY *= mulAxisY;
  1019. // for axis
  1020. float axisLengthInClipSpace = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis * gContext.mScreenFactor, localCoordinates);
  1021. float paraSurf = GetParallelogram(makeVect(0.f, 0.f, 0.f), dirPlaneX * gContext.mScreenFactor, dirPlaneY * gContext.mScreenFactor);
  1022. belowPlaneLimit = (paraSurf > gContext.mAxisLimit);
  1023. belowAxisLimit = (axisLengthInClipSpace > gContext.mPlaneLimit);
  1024. // and store values
  1025. gContext.mAxisFactor[axisIndex] = mulAxis;
  1026. gContext.mAxisFactor[(axisIndex + 1) % 3] = mulAxisX;
  1027. gContext.mAxisFactor[(axisIndex + 2) % 3] = mulAxisY;
  1028. gContext.mBelowAxisLimit[axisIndex] = belowAxisLimit;
  1029. gContext.mBelowPlaneLimit[axisIndex] = belowPlaneLimit;
  1030. }
  1031. }
  1032. static void ComputeSnap(float* value, float snap)
  1033. {
  1034. if (snap <= FLT_EPSILON)
  1035. {
  1036. return;
  1037. }
  1038. float modulo = fmodf(*value, snap);
  1039. float moduloRatio = fabsf(modulo) / snap;
  1040. if (moduloRatio < snapTension)
  1041. {
  1042. *value -= modulo;
  1043. }
  1044. else if (moduloRatio > (1.f - snapTension))
  1045. {
  1046. *value = *value - modulo + snap * ((*value < 0.f) ? -1.f : 1.f);
  1047. }
  1048. }
  1049. static void ComputeSnap(vec_t& value, const float* snap)
  1050. {
  1051. for (int i = 0; i < 3; i++)
  1052. {
  1053. ComputeSnap(&value[i], snap[i]);
  1054. }
  1055. }
  1056. static float ComputeAngleOnPlan()
  1057. {
  1058. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
  1059. vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
  1060. vec_t perpendicularVector;
  1061. perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
  1062. perpendicularVector.Normalize();
  1063. float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -1.f, 1.f);
  1064. float angle = acosf(acosAngle);
  1065. angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
  1066. return angle;
  1067. }
  1068. static void DrawRotationGizmo(OPERATION op, int type)
  1069. {
  1070. if(!Intersects(op, ROTATE))
  1071. {
  1072. return;
  1073. }
  1074. ImDrawList* drawList = gContext.mDrawList;
  1075. // colors
  1076. ImU32 colors[7];
  1077. ComputeColors(colors, type, ROTATE);
  1078. vec_t cameraToModelNormalized;
  1079. if (gContext.mIsOrthographic)
  1080. {
  1081. matrix_t viewInverse;
  1082. viewInverse.Inverse(*(matrix_t*)&gContext.mViewMat);
  1083. cameraToModelNormalized = -viewInverse.v.dir;
  1084. }
  1085. else
  1086. {
  1087. cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
  1088. }
  1089. cameraToModelNormalized.TransformVector(gContext.mModelInverse);
  1090. gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight;
  1091. bool hasRSC = Intersects(op, ROTATE_SCREEN);
  1092. for (int axis = 0; axis < 3; axis++)
  1093. {
  1094. if(!Intersects(op, static_cast<OPERATION>(ROTATE_Z >> axis)))
  1095. {
  1096. continue;
  1097. }
  1098. const bool usingAxis = (gContext.mbUsing && type == MT_ROTATE_Z - axis);
  1099. const int circleMul = (hasRSC && !usingAxis ) ? 1 : 2;
  1100. ImVec2* circlePos = (ImVec2*)alloca(sizeof(ImVec2) * (circleMul * halfCircleSegmentCount + 1));
  1101. float angleStart = atan2f(cameraToModelNormalized[(4 - axis) % 3], cameraToModelNormalized[(3 - axis) % 3]) + ZPI * 0.5f;
  1102. for (int i = 0; i < circleMul * halfCircleSegmentCount + 1; i++)
  1103. {
  1104. float ng = angleStart + (float)circleMul * ZPI * ((float)i / (float)(circleMul * halfCircleSegmentCount));
  1105. vec_t axisPos = makeVect(cosf(ng), sinf(ng), 0.f);
  1106. vec_t pos = makeVect(axisPos[axis], axisPos[(axis + 1) % 3], axisPos[(axis + 2) % 3]) * gContext.mScreenFactor * rotationDisplayFactor;
  1107. circlePos[i] = worldToPos(pos, gContext.mMVP);
  1108. }
  1109. if (!gContext.mbUsing || usingAxis)
  1110. {
  1111. drawList->AddPolyline(circlePos, circleMul* halfCircleSegmentCount + 1, colors[3 - axis], false, gContext.mStyle.RotationLineThickness);
  1112. }
  1113. float radiusAxis = sqrtf((ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0])));
  1114. if (radiusAxis > gContext.mRadiusSquareCenter)
  1115. {
  1116. gContext.mRadiusSquareCenter = radiusAxis;
  1117. }
  1118. }
  1119. if(hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN))
  1120. {
  1121. drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, gContext.mStyle.RotationOuterLineThickness);
  1122. }
  1123. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(type))
  1124. {
  1125. ImVec2 circlePos[halfCircleSegmentCount + 1];
  1126. circlePos[0] = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
  1127. for (unsigned int i = 1; i < halfCircleSegmentCount + 1; i++)
  1128. {
  1129. float ng = gContext.mRotationAngle * ((float)(i - 1) / (float)(halfCircleSegmentCount - 1));
  1130. matrix_t rotateVectorMatrix;
  1131. rotateVectorMatrix.RotationAxis(gContext.mTranslationPlan, ng);
  1132. vec_t pos;
  1133. pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix);
  1134. pos *= gContext.mScreenFactor * rotationDisplayFactor;
  1135. circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);
  1136. }
  1137. drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount + 1, GetColorU32(ROTATION_USING_FILL));
  1138. drawList->AddPolyline(circlePos, halfCircleSegmentCount + 1, GetColorU32(ROTATION_USING_BORDER), true, gContext.mStyle.RotationLineThickness);
  1139. ImVec2 destinationPosOnScreen = circlePos[1];
  1140. char tmps[512];
  1141. ImFormatString(tmps, sizeof(tmps), rotationInfoMask[type - MT_ROTATE_X], (gContext.mRotationAngle / ZPI) * 180.f, gContext.mRotationAngle);
  1142. drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
  1143. drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
  1144. }
  1145. }
  1146. static void DrawHatchedAxis(const vec_t& axis)
  1147. {
  1148. if (gContext.mStyle.HatchedAxisLineThickness <= 0.0f)
  1149. {
  1150. return;
  1151. }
  1152. for (int j = 1; j < 10; j++)
  1153. {
  1154. ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, gContext.mMVP);
  1155. ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, gContext.mMVP);
  1156. gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, GetColorU32(HATCHED_AXIS_LINES), gContext.mStyle.HatchedAxisLineThickness);
  1157. }
  1158. }
  1159. static void DrawScaleGizmo(OPERATION op, int type)
  1160. {
  1161. ImDrawList* drawList = gContext.mDrawList;
  1162. if(!Intersects(op, SCALE))
  1163. {
  1164. return;
  1165. }
  1166. // colors
  1167. ImU32 colors[7];
  1168. ComputeColors(colors, type, SCALE);
  1169. // draw
  1170. vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
  1171. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
  1172. {
  1173. scaleDisplay = gContext.mScale;
  1174. }
  1175. for (int i = 0; i < 3; i++)
  1176. {
  1177. if(!Intersects(op, static_cast<OPERATION>(SCALE_X << i)))
  1178. {
  1179. continue;
  1180. }
  1181. const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);
  1182. if (!gContext.mbUsing || usingAxis)
  1183. {
  1184. vec_t dirPlaneX, dirPlaneY, dirAxis;
  1185. bool belowAxisLimit, belowPlaneLimit;
  1186. ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
  1187. // draw axis
  1188. if (belowAxisLimit)
  1189. {
  1190. bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));
  1191. float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
  1192. ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);
  1193. ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
  1194. ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVP);
  1195. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
  1196. {
  1197. ImU32 scaleLineColor = GetColorU32(SCALE_LINE);
  1198. drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, scaleLineColor, gContext.mStyle.ScaleLineThickness);
  1199. drawList->AddCircleFilled(worldDirSSpaceNoScale, gContext.mStyle.ScaleLineCircleSize, scaleLineColor);
  1200. }
  1201. if (!hasTranslateOnAxis || gContext.mbUsing)
  1202. {
  1203. drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.ScaleLineThickness);
  1204. }
  1205. drawList->AddCircleFilled(worldDirSSpace, gContext.mStyle.ScaleLineCircleSize, colors[i + 1]);
  1206. if (gContext.mAxisFactor[i] < 0.f)
  1207. {
  1208. DrawHatchedAxis(dirAxis * scaleDisplay[i]);
  1209. }
  1210. }
  1211. }
  1212. }
  1213. // draw screen cirle
  1214. drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32);
  1215. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type))
  1216. {
  1217. //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
  1218. ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
  1219. /*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
  1220. dif.Normalize();
  1221. dif *= 5.f;
  1222. drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
  1223. drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
  1224. drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
  1225. */
  1226. char tmps[512];
  1227. //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
  1228. int componentInfoIndex = (type - MT_SCALE_X) * 3;
  1229. ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]);
  1230. drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
  1231. drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
  1232. }
  1233. }
  1234. static void DrawScaleUniveralGizmo(OPERATION op, int type)
  1235. {
  1236. ImDrawList* drawList = gContext.mDrawList;
  1237. if (!Intersects(op, SCALEU))
  1238. {
  1239. return;
  1240. }
  1241. // colors
  1242. ImU32 colors[7];
  1243. ComputeColors(colors, type, SCALEU);
  1244. // draw
  1245. vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
  1246. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
  1247. {
  1248. scaleDisplay = gContext.mScale;
  1249. }
  1250. for (int i = 0; i < 3; i++)
  1251. {
  1252. if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i)))
  1253. {
  1254. continue;
  1255. }
  1256. const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);
  1257. if (!gContext.mbUsing || usingAxis)
  1258. {
  1259. vec_t dirPlaneX, dirPlaneY, dirAxis;
  1260. bool belowAxisLimit, belowPlaneLimit;
  1261. ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
  1262. // draw axis
  1263. if (belowAxisLimit)
  1264. {
  1265. bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));
  1266. float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
  1267. //ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
  1268. //ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
  1269. ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVPLocal);
  1270. #if 0
  1271. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
  1272. {
  1273. drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, IM_COL32(0x40, 0x40, 0x40, 0xFF), 3.f);
  1274. drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, IM_COL32(0x40, 0x40, 0x40, 0xFF));
  1275. }
  1276. /*
  1277. if (!hasTranslateOnAxis || gContext.mbUsing)
  1278. {
  1279. drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
  1280. }
  1281. */
  1282. #endif
  1283. drawList->AddCircleFilled(worldDirSSpace, 12.f, colors[i + 1]);
  1284. }
  1285. }
  1286. }
  1287. // draw screen cirle
  1288. drawList->AddCircle(gContext.mScreenSquareCenter, 20.f, colors[0], 32, gContext.mStyle.CenterCircleSize);
  1289. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type))
  1290. {
  1291. //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
  1292. ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
  1293. /*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
  1294. dif.Normalize();
  1295. dif *= 5.f;
  1296. drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
  1297. drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
  1298. drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
  1299. */
  1300. char tmps[512];
  1301. //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
  1302. int componentInfoIndex = (type - MT_SCALE_X) * 3;
  1303. ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]);
  1304. drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
  1305. drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
  1306. }
  1307. }
  1308. static void DrawTranslationGizmo(OPERATION op, int type)
  1309. {
  1310. ImDrawList* drawList = gContext.mDrawList;
  1311. if (!drawList)
  1312. {
  1313. return;
  1314. }
  1315. if(!Intersects(op, TRANSLATE))
  1316. {
  1317. return;
  1318. }
  1319. // colors
  1320. ImU32 colors[7];
  1321. ComputeColors(colors, type, TRANSLATE);
  1322. const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
  1323. // draw
  1324. bool belowAxisLimit = false;
  1325. bool belowPlaneLimit = false;
  1326. for (int i = 0; i < 3; ++i)
  1327. {
  1328. vec_t dirPlaneX, dirPlaneY, dirAxis;
  1329. ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
  1330. if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_X + i))
  1331. {
  1332. // draw axis
  1333. if (belowAxisLimit && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i)))
  1334. {
  1335. ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);
  1336. ImVec2 worldDirSSpace = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP);
  1337. drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.TranslationLineThickness);
  1338. // Arrow head begin
  1339. ImVec2 dir(origin - worldDirSSpace);
  1340. float d = sqrtf(ImLengthSqr(dir));
  1341. dir /= d; // Normalize
  1342. dir *= gContext.mStyle.TranslationLineArrowSize;
  1343. ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector
  1344. ImVec2 a(worldDirSSpace + dir);
  1345. drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]);
  1346. // Arrow head end
  1347. if (gContext.mAxisFactor[i] < 0.f)
  1348. {
  1349. DrawHatchedAxis(dirAxis);
  1350. }
  1351. }
  1352. }
  1353. // draw plane
  1354. if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_YZ + i))
  1355. {
  1356. if (belowPlaneLimit && Contains(op, TRANSLATE_PLANS[i]))
  1357. {
  1358. ImVec2 screenQuadPts[4];
  1359. for (int j = 0; j < 4; ++j)
  1360. {
  1361. vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor;
  1362. screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);
  1363. }
  1364. drawList->AddPolyline(screenQuadPts, 4, GetColorU32(DIRECTION_X + i), true, 1.0f);
  1365. drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]);
  1366. }
  1367. }
  1368. }
  1369. drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32);
  1370. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(type))
  1371. {
  1372. ImU32 translationLineColor = GetColorU32(TRANSLATION_LINE);
  1373. ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
  1374. ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
  1375. vec_t dif = { destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y, 0.f, 0.f };
  1376. dif.Normalize();
  1377. dif *= 5.f;
  1378. drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
  1379. drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
  1380. drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
  1381. char tmps[512];
  1382. vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
  1383. int componentInfoIndex = (type - MT_MOVE_X) * 3;
  1384. ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MT_MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]);
  1385. drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
  1386. drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
  1387. }
  1388. }
  1389. static bool CanActivate()
  1390. {
  1391. if (ImGui::IsMouseClicked(0) /*&& !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive()*/)
  1392. {
  1393. return true;
  1394. }
  1395. return false;
  1396. }
  1397. static void HandleAndDrawLocalBounds(const float* bounds, matrix_t* matrix, const float* snapValues, OPERATION operation)
  1398. {
  1399. ImGuiIO& io = ImGui::GetIO();
  1400. ImDrawList* drawList = gContext.mDrawList;
  1401. // compute best projection axis
  1402. vec_t axesWorldDirections[3];
  1403. vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f };
  1404. int axes[3];
  1405. unsigned int numAxes = 1;
  1406. axes[0] = gContext.mBoundsBestAxis;
  1407. int bestAxis = axes[0];
  1408. if (!gContext.mbUsingBounds)
  1409. {
  1410. numAxes = 0;
  1411. float bestDot = 0.f;
  1412. for (int i = 0; i < 3; i++)
  1413. {
  1414. vec_t dirPlaneNormalWorld;
  1415. dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
  1416. dirPlaneNormalWorld.Normalize();
  1417. float dt = fabsf(Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld));
  1418. if (dt >= bestDot)
  1419. {
  1420. bestDot = dt;
  1421. bestAxis = i;
  1422. bestAxisWorldDirection = dirPlaneNormalWorld;
  1423. }
  1424. if (dt >= 0.1f)
  1425. {
  1426. axes[numAxes] = i;
  1427. axesWorldDirections[numAxes] = dirPlaneNormalWorld;
  1428. ++numAxes;
  1429. }
  1430. }
  1431. }
  1432. if (numAxes == 0)
  1433. {
  1434. axes[0] = bestAxis;
  1435. axesWorldDirections[0] = bestAxisWorldDirection;
  1436. numAxes = 1;
  1437. }
  1438. else if (bestAxis != axes[0])
  1439. {
  1440. unsigned int bestIndex = 0;
  1441. for (unsigned int i = 0; i < numAxes; i++)
  1442. {
  1443. if (axes[i] == bestAxis)
  1444. {
  1445. bestIndex = i;
  1446. break;
  1447. }
  1448. }
  1449. int tempAxis = axes[0];
  1450. axes[0] = axes[bestIndex];
  1451. axes[bestIndex] = tempAxis;
  1452. vec_t tempDirection = axesWorldDirections[0];
  1453. axesWorldDirections[0] = axesWorldDirections[bestIndex];
  1454. axesWorldDirections[bestIndex] = tempDirection;
  1455. }
  1456. for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex)
  1457. {
  1458. bestAxis = axes[axisIndex];
  1459. bestAxisWorldDirection = axesWorldDirections[axisIndex];
  1460. // corners
  1461. vec_t aabb[4];
  1462. int secondAxis = (bestAxis + 1) % 3;
  1463. int thirdAxis = (bestAxis + 2) % 3;
  1464. for (int i = 0; i < 4; i++)
  1465. {
  1466. aabb[i][3] = aabb[i][bestAxis] = 0.f;
  1467. aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
  1468. aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
  1469. }
  1470. // draw bounds
  1471. unsigned int anchorAlpha = gContext.mbEnable ? IM_COL32_BLACK : IM_COL32(0, 0, 0, 0x80);
  1472. matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
  1473. for (int i = 0; i < 4; i++)
  1474. {
  1475. ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
  1476. ImVec2 worldBound2 = worldToPos(aabb[(i + 1) % 4], boundsMVP);
  1477. if (!IsInContextRect(worldBound1) || !IsInContextRect(worldBound2))
  1478. {
  1479. continue;
  1480. }
  1481. float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
  1482. int stepCount = (int)(boundDistance / 10.f);
  1483. stepCount = min(stepCount, 1000);
  1484. for (int j = 0; j < stepCount; j++)
  1485. {
  1486. float stepLength = 1.f / (float)stepCount;
  1487. float t1 = (float)j * stepLength;
  1488. float t2 = (float)j * stepLength + stepLength * 0.5f;
  1489. ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
  1490. ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
  1491. //drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0, 0, 0, 0) + anchorAlpha, 3.f);
  1492. drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha, 2.f);
  1493. }
  1494. vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4]) * 0.5f;
  1495. ImVec2 midBound = worldToPos(midPoint, boundsMVP);
  1496. static const float AnchorBigRadius = 8.f;
  1497. static const float AnchorSmallRadius = 6.f;
  1498. bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius);
  1499. bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius);
  1500. int type = MT_NONE;
  1501. vec_t gizmoHitProportion;
  1502. if(Intersects(operation, TRANSLATE))
  1503. {
  1504. type = GetMoveType(operation, &gizmoHitProportion);
  1505. }
  1506. if(Intersects(operation, ROTATE) && type == MT_NONE)
  1507. {
  1508. type = GetRotateType(operation);
  1509. }
  1510. if(Intersects(operation, SCALE) && type == MT_NONE)
  1511. {
  1512. type = GetScaleType(operation);
  1513. }
  1514. if (type != MT_NONE)
  1515. {
  1516. overBigAnchor = false;
  1517. overSmallAnchor = false;
  1518. }
  1519. ImU32 selectionColor = GetColorU32(SELECTION);
  1520. unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha);
  1521. unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha);
  1522. drawList->AddCircleFilled(worldBound1, AnchorBigRadius, IM_COL32_BLACK);
  1523. drawList->AddCircleFilled(worldBound1, AnchorBigRadius - 1.2f, bigAnchorColor);
  1524. drawList->AddCircleFilled(midBound, AnchorSmallRadius, IM_COL32_BLACK);
  1525. drawList->AddCircleFilled(midBound, AnchorSmallRadius - 1.2f, smallAnchorColor);
  1526. int oppositeIndex = (i + 2) % 4;
  1527. // big anchor on corners
  1528. if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate())
  1529. {
  1530. gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
  1531. gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
  1532. gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
  1533. gContext.mBoundsBestAxis = bestAxis;
  1534. gContext.mBoundsAxis[0] = secondAxis;
  1535. gContext.mBoundsAxis[1] = thirdAxis;
  1536. gContext.mBoundsLocalPivot.Set(0.f);
  1537. gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
  1538. gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
  1539. gContext.mbUsingBounds = true;
  1540. gContext.mEditingID = gContext.mActualID;
  1541. gContext.mBoundsMatrix = gContext.mModelSource;
  1542. }
  1543. // small anchor on middle of segment
  1544. if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate())
  1545. {
  1546. vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
  1547. gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
  1548. gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
  1549. gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
  1550. gContext.mBoundsBestAxis = bestAxis;
  1551. int indices[] = { secondAxis , thirdAxis };
  1552. gContext.mBoundsAxis[0] = indices[i % 2];
  1553. gContext.mBoundsAxis[1] = -1;
  1554. gContext.mBoundsLocalPivot.Set(0.f);
  1555. gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
  1556. gContext.mbUsingBounds = true;
  1557. gContext.mEditingID = gContext.mActualID;
  1558. gContext.mBoundsMatrix = gContext.mModelSource;
  1559. }
  1560. }
  1561. if (gContext.mbUsingBounds && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
  1562. {
  1563. matrix_t scale;
  1564. scale.SetToIdentity();
  1565. // compute projected mouse position on plan
  1566. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
  1567. vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
  1568. // compute a reference and delta vectors base on mouse move
  1569. vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
  1570. vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
  1571. // for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
  1572. for (int i = 0; i < 2; i++)
  1573. {
  1574. int axisIndex1 = gContext.mBoundsAxis[i];
  1575. if (axisIndex1 == -1)
  1576. {
  1577. continue;
  1578. }
  1579. float ratioAxis = 1.f;
  1580. vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs();
  1581. float dtAxis = axisDir.Dot(referenceVector);
  1582. float boundSize = bounds[axisIndex1 + 3] - bounds[axisIndex1];
  1583. if (dtAxis > FLT_EPSILON)
  1584. {
  1585. ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
  1586. }
  1587. if (snapValues)
  1588. {
  1589. float length = boundSize * ratioAxis;
  1590. ComputeSnap(&length, snapValues[axisIndex1]);
  1591. if (boundSize > FLT_EPSILON)
  1592. {
  1593. ratioAxis = length / boundSize;
  1594. }
  1595. }
  1596. scale.component[axisIndex1] *= ratioAxis;
  1597. }
  1598. // transform matrix
  1599. matrix_t preScale, postScale;
  1600. preScale.Translation(-gContext.mBoundsLocalPivot);
  1601. postScale.Translation(gContext.mBoundsLocalPivot);
  1602. matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
  1603. *matrix = res;
  1604. // info text
  1605. char tmps[512];
  1606. ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
  1607. ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z: %.2f"
  1608. , (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
  1609. , (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
  1610. , (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
  1611. );
  1612. drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
  1613. drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
  1614. }
  1615. if (!io.MouseDown[0]) {
  1616. gContext.mbUsingBounds = false;
  1617. gContext.mEditingID = -1;
  1618. }
  1619. if (gContext.mbUsingBounds)
  1620. {
  1621. break;
  1622. }
  1623. }
  1624. }
  1625. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1626. //
  1627. static int GetScaleType(OPERATION op)
  1628. {
  1629. if (gContext.mbUsing)
  1630. {
  1631. return MT_NONE;
  1632. }
  1633. ImGuiIO& io = ImGui::GetIO();
  1634. int type = MT_NONE;
  1635. // screen
  1636. if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
  1637. io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&
  1638. Contains(op, SCALE))
  1639. {
  1640. type = MT_SCALE_XYZ;
  1641. }
  1642. // compute
  1643. for (int i = 0; i < 3 && type == MT_NONE; i++)
  1644. {
  1645. if(!Intersects(op, static_cast<OPERATION>(SCALE_X << i)))
  1646. {
  1647. continue;
  1648. }
  1649. vec_t dirPlaneX, dirPlaneY, dirAxis;
  1650. bool belowAxisLimit, belowPlaneLimit;
  1651. ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
  1652. dirAxis.TransformVector(gContext.mModelLocal);
  1653. dirPlaneX.TransformVector(gContext.mModelLocal);
  1654. dirPlaneY.TransformVector(gContext.mModelLocal);
  1655. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModelLocal.v.position, dirAxis));
  1656. vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
  1657. const float startOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.0f : 0.1f;
  1658. const float endOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.4f : 1.0f;
  1659. const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection);
  1660. const ImVec2 axisStartOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * startOffset, gContext.mViewProjection);
  1661. const ImVec2 axisEndOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * endOffset, gContext.mViewProjection);
  1662. vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));
  1663. if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size
  1664. {
  1665. type = MT_SCALE_X + i;
  1666. }
  1667. }
  1668. // universal
  1669. vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
  1670. float dist = deltaScreen.Length();
  1671. if (Contains(op, SCALEU) && dist >= 17.0f && dist < 23.0f)
  1672. {
  1673. type = MT_SCALE_XYZ;
  1674. }
  1675. for (int i = 0; i < 3 && type == MT_NONE; i++)
  1676. {
  1677. if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i)))
  1678. {
  1679. continue;
  1680. }
  1681. vec_t dirPlaneX, dirPlaneY, dirAxis;
  1682. bool belowAxisLimit, belowPlaneLimit;
  1683. ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
  1684. // draw axis
  1685. if (belowAxisLimit)
  1686. {
  1687. bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));
  1688. float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
  1689. //ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
  1690. //ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
  1691. ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale) * gContext.mScreenFactor, gContext.mMVPLocal);
  1692. float distance = sqrtf(ImLengthSqr(worldDirSSpace - io.MousePos));
  1693. if (distance < 12.f)
  1694. {
  1695. type = MT_SCALE_X + i;
  1696. }
  1697. }
  1698. }
  1699. return type;
  1700. }
  1701. static int GetRotateType(OPERATION op)
  1702. {
  1703. if (gContext.mbUsing)
  1704. {
  1705. return MT_NONE;
  1706. }
  1707. ImGuiIO& io = ImGui::GetIO();
  1708. int type = MT_NONE;
  1709. vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
  1710. float dist = deltaScreen.Length();
  1711. if (Intersects(op, ROTATE_SCREEN) && dist >= (gContext.mRadiusSquareCenter - 4.0f) && dist < (gContext.mRadiusSquareCenter + 4.0f))
  1712. {
  1713. type = MT_ROTATE_SCREEN;
  1714. }
  1715. const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir };
  1716. vec_t modelViewPos;
  1717. modelViewPos.TransformPoint(gContext.mModel.v.position, gContext.mViewMat);
  1718. for (int i = 0; i < 3 && type == MT_NONE; i++)
  1719. {
  1720. if(!Intersects(op, static_cast<OPERATION>(ROTATE_X << i)))
  1721. {
  1722. continue;
  1723. }
  1724. // pickup plan
  1725. vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]);
  1726. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan);
  1727. const vec_t intersectWorldPos = gContext.mRayOrigin + gContext.mRayVector * len;
  1728. vec_t intersectViewPos;
  1729. intersectViewPos.TransformPoint(intersectWorldPos, gContext.mViewMat);
  1730. if (ImAbs(modelViewPos.z) - ImAbs(intersectViewPos.z) < -FLT_EPSILON)
  1731. {
  1732. continue;
  1733. }
  1734. const vec_t localPos = intersectWorldPos - gContext.mModel.v.position;
  1735. vec_t idealPosOnCircle = Normalized(localPos);
  1736. idealPosOnCircle.TransformVector(gContext.mModelInverse);
  1737. const ImVec2 idealPosOnCircleScreen = worldToPos(idealPosOnCircle * rotationDisplayFactor * gContext.mScreenFactor, gContext.mMVP);
  1738. //gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, IM_COL32_WHITE);
  1739. const ImVec2 distanceOnScreen = idealPosOnCircleScreen - io.MousePos;
  1740. const float distance = makeVect(distanceOnScreen).Length();
  1741. if (distance < 8.f) // pixel size
  1742. {
  1743. type = MT_ROTATE_X + i;
  1744. }
  1745. }
  1746. return type;
  1747. }
  1748. static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion)
  1749. {
  1750. if(!Intersects(op, TRANSLATE) || gContext.mbUsing || !gContext.mbMouseOver)
  1751. {
  1752. return MT_NONE;
  1753. }
  1754. ImGuiIO& io = ImGui::GetIO();
  1755. int type = MT_NONE;
  1756. // screen
  1757. if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
  1758. io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&
  1759. Contains(op, TRANSLATE))
  1760. {
  1761. type = MT_MOVE_SCREEN;
  1762. }
  1763. const vec_t screenCoord = makeVect(io.MousePos - ImVec2(gContext.mX, gContext.mY));
  1764. // compute
  1765. for (int i = 0; i < 3 && type == MT_NONE; i++)
  1766. {
  1767. vec_t dirPlaneX, dirPlaneY, dirAxis;
  1768. bool belowAxisLimit, belowPlaneLimit;
  1769. ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
  1770. dirAxis.TransformVector(gContext.mModel);
  1771. dirPlaneX.TransformVector(gContext.mModel);
  1772. dirPlaneY.TransformVector(gContext.mModel);
  1773. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, dirAxis));
  1774. vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
  1775. const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor * 0.1f, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);
  1776. const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);
  1777. vec_t closestPointOnAxis = PointOnSegment(screenCoord, makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));
  1778. if ((closestPointOnAxis - screenCoord).Length() < 12.f && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i))) // pixel size
  1779. {
  1780. type = MT_MOVE_X + i;
  1781. }
  1782. const float dx = dirPlaneX.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
  1783. const float dy = dirPlaneY.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
  1784. if (belowPlaneLimit && dx >= quadUV[0] && dx <= quadUV[4] && dy >= quadUV[1] && dy <= quadUV[3] && Contains(op, TRANSLATE_PLANS[i]))
  1785. {
  1786. type = MT_MOVE_YZ + i;
  1787. }
  1788. if (gizmoHitProportion)
  1789. {
  1790. *gizmoHitProportion = makeVect(dx, dy, 0.f);
  1791. }
  1792. }
  1793. return type;
  1794. }
  1795. static bool HandleTranslation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
  1796. {
  1797. if(!Intersects(op, TRANSLATE) || type != MT_NONE)
  1798. {
  1799. return false;
  1800. }
  1801. const ImGuiIO& io = ImGui::GetIO();
  1802. const bool applyRotationLocaly = gContext.mMode == LOCAL || type == MT_MOVE_SCREEN;
  1803. bool modified = false;
  1804. // move
  1805. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(gContext.mCurrentOperation))
  1806. {
  1807. #if IMGUI_VERSION_NUM >= 18723
  1808. ImGui::SetNextFrameWantCaptureMouse(true);
  1809. #else
  1810. ImGui::CaptureMouseFromApp();
  1811. #endif
  1812. const float signedLength = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
  1813. const float len = fabsf(signedLength); // near plan
  1814. const vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
  1815. // compute delta
  1816. const vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
  1817. vec_t delta = newOrigin - gContext.mModel.v.position;
  1818. // 1 axis constraint
  1819. if (gContext.mCurrentOperation >= MT_MOVE_X && gContext.mCurrentOperation <= MT_MOVE_Z)
  1820. {
  1821. const int axisIndex = gContext.mCurrentOperation - MT_MOVE_X;
  1822. const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex];
  1823. const float lengthOnAxis = Dot(axisValue, delta);
  1824. delta = axisValue * lengthOnAxis;
  1825. }
  1826. // snap
  1827. if (snap)
  1828. {
  1829. vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin;
  1830. if (applyRotationLocaly)
  1831. {
  1832. matrix_t modelSourceNormalized = gContext.mModelSource;
  1833. modelSourceNormalized.OrthoNormalize();
  1834. matrix_t modelSourceNormalizedInverse;
  1835. modelSourceNormalizedInverse.Inverse(modelSourceNormalized);
  1836. cumulativeDelta.TransformVector(modelSourceNormalizedInverse);
  1837. ComputeSnap(cumulativeDelta, snap);
  1838. cumulativeDelta.TransformVector(modelSourceNormalized);
  1839. }
  1840. else
  1841. {
  1842. ComputeSnap(cumulativeDelta, snap);
  1843. }
  1844. delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position;
  1845. }
  1846. if (delta != gContext.mTranslationLastDelta)
  1847. {
  1848. modified = true;
  1849. }
  1850. gContext.mTranslationLastDelta = delta;
  1851. // compute matrix & delta
  1852. matrix_t deltaMatrixTranslation;
  1853. deltaMatrixTranslation.Translation(delta);
  1854. if (deltaMatrix)
  1855. {
  1856. memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16);
  1857. }
  1858. const matrix_t res = gContext.mModelSource * deltaMatrixTranslation;
  1859. *(matrix_t*)matrix = res;
  1860. if (!io.MouseDown[0])
  1861. {
  1862. gContext.mbUsing = false;
  1863. }
  1864. type = gContext.mCurrentOperation;
  1865. }
  1866. else
  1867. {
  1868. // find new possible way to move
  1869. vec_t gizmoHitProportion;
  1870. type = GetMoveType(op, &gizmoHitProportion);
  1871. if (type != MT_NONE)
  1872. {
  1873. #if IMGUI_VERSION_NUM >= 18723
  1874. ImGui::SetNextFrameWantCaptureMouse(true);
  1875. #else
  1876. ImGui::CaptureMouseFromApp();
  1877. #endif
  1878. }
  1879. if (CanActivate() && type != MT_NONE)
  1880. {
  1881. gContext.mbUsing = true;
  1882. gContext.mEditingID = gContext.mActualID;
  1883. gContext.mCurrentOperation = type;
  1884. vec_t movePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,
  1885. gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,
  1886. -gContext.mCameraDir };
  1887. vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
  1888. for (unsigned int i = 0; i < 3; i++)
  1889. {
  1890. vec_t orthoVector = Cross(movePlanNormal[i], cameraToModelNormalized);
  1891. movePlanNormal[i].Cross(orthoVector);
  1892. movePlanNormal[i].Normalize();
  1893. }
  1894. // pickup plan
  1895. gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_MOVE_X]);
  1896. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
  1897. gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
  1898. gContext.mMatrixOrigin = gContext.mModel.v.position;
  1899. gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
  1900. }
  1901. }
  1902. return modified;
  1903. }
  1904. static bool HandleScale(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
  1905. {
  1906. if((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE || !gContext.mbMouseOver)
  1907. {
  1908. return false;
  1909. }
  1910. ImGuiIO& io = ImGui::GetIO();
  1911. bool modified = false;
  1912. if (!gContext.mbUsing)
  1913. {
  1914. // find new possible way to scale
  1915. type = GetScaleType(op);
  1916. if (type != MT_NONE)
  1917. {
  1918. #if IMGUI_VERSION_NUM >= 18723
  1919. ImGui::SetNextFrameWantCaptureMouse(true);
  1920. #else
  1921. ImGui::CaptureMouseFromApp();
  1922. #endif
  1923. }
  1924. if (CanActivate() && type != MT_NONE)
  1925. {
  1926. gContext.mbUsing = true;
  1927. gContext.mEditingID = gContext.mActualID;
  1928. gContext.mCurrentOperation = type;
  1929. const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.up, gContext.mModel.v.right, -gContext.mCameraDir };
  1930. // pickup plan
  1931. gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_SCALE_X]);
  1932. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
  1933. gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
  1934. gContext.mMatrixOrigin = gContext.mModel.v.position;
  1935. gContext.mScale.Set(1.f, 1.f, 1.f);
  1936. gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
  1937. gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
  1938. gContext.mSaveMousePosx = io.MousePos.x;
  1939. }
  1940. }
  1941. // scale
  1942. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(gContext.mCurrentOperation))
  1943. {
  1944. #if IMGUI_VERSION_NUM >= 18723
  1945. ImGui::SetNextFrameWantCaptureMouse(true);
  1946. #else
  1947. ImGui::CaptureMouseFromApp();
  1948. #endif
  1949. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
  1950. vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
  1951. vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
  1952. vec_t delta = newOrigin - gContext.mModelLocal.v.position;
  1953. // 1 axis constraint
  1954. if (gContext.mCurrentOperation >= MT_SCALE_X && gContext.mCurrentOperation <= MT_SCALE_Z)
  1955. {
  1956. int axisIndex = gContext.mCurrentOperation - MT_SCALE_X;
  1957. const vec_t& axisValue = *(vec_t*)&gContext.mModelLocal.m[axisIndex];
  1958. float lengthOnAxis = Dot(axisValue, delta);
  1959. delta = axisValue * lengthOnAxis;
  1960. vec_t baseVector = gContext.mTranslationPlanOrigin - gContext.mModelLocal.v.position;
  1961. float ratio = Dot(axisValue, baseVector + delta) / Dot(axisValue, baseVector);
  1962. gContext.mScale[axisIndex] = max(ratio, 0.001f);
  1963. }
  1964. else
  1965. {
  1966. float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;
  1967. gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
  1968. }
  1969. // snap
  1970. if (snap)
  1971. {
  1972. float scaleSnap[] = { snap[0], snap[0], snap[0] };
  1973. ComputeSnap(gContext.mScale, scaleSnap);
  1974. }
  1975. // no 0 allowed
  1976. for (int i = 0; i < 3; i++)
  1977. gContext.mScale[i] = max(gContext.mScale[i], 0.001f);
  1978. if (gContext.mScaleLast != gContext.mScale)
  1979. {
  1980. modified = true;
  1981. }
  1982. gContext.mScaleLast = gContext.mScale;
  1983. // compute matrix & delta
  1984. matrix_t deltaMatrixScale;
  1985. deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin);
  1986. matrix_t res = deltaMatrixScale * gContext.mModelLocal;
  1987. *(matrix_t*)matrix = res;
  1988. if (deltaMatrix)
  1989. {
  1990. vec_t deltaScale = gContext.mScale * gContext.mScaleValueOrigin;
  1991. vec_t originalScaleDivider;
  1992. originalScaleDivider.x = 1 / gContext.mModelScaleOrigin.x;
  1993. originalScaleDivider.y = 1 / gContext.mModelScaleOrigin.y;
  1994. originalScaleDivider.z = 1 / gContext.mModelScaleOrigin.z;
  1995. deltaScale = deltaScale * originalScaleDivider;
  1996. deltaMatrixScale.Scale(deltaScale);
  1997. memcpy(deltaMatrix, deltaMatrixScale.m16, sizeof(float) * 16);
  1998. }
  1999. if (!io.MouseDown[0])
  2000. {
  2001. gContext.mbUsing = false;
  2002. gContext.mScale.Set(1.f, 1.f, 1.f);
  2003. }
  2004. type = gContext.mCurrentOperation;
  2005. }
  2006. return modified;
  2007. }
  2008. static bool HandleRotation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
  2009. {
  2010. if(!Intersects(op, ROTATE) || type != MT_NONE || !gContext.mbMouseOver)
  2011. {
  2012. return false;
  2013. }
  2014. ImGuiIO& io = ImGui::GetIO();
  2015. bool applyRotationLocaly = gContext.mMode == LOCAL;
  2016. bool modified = false;
  2017. if (!gContext.mbUsing)
  2018. {
  2019. type = GetRotateType(op);
  2020. if (type != MT_NONE)
  2021. {
  2022. #if IMGUI_VERSION_NUM >= 18723
  2023. ImGui::SetNextFrameWantCaptureMouse(true);
  2024. #else
  2025. ImGui::CaptureMouseFromApp();
  2026. #endif
  2027. }
  2028. if (type == MT_ROTATE_SCREEN)
  2029. {
  2030. applyRotationLocaly = true;
  2031. }
  2032. if (CanActivate() && type != MT_NONE)
  2033. {
  2034. gContext.mbUsing = true;
  2035. gContext.mEditingID = gContext.mActualID;
  2036. gContext.mCurrentOperation = type;
  2037. const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir };
  2038. // pickup plan
  2039. if (applyRotationLocaly)
  2040. {
  2041. gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, rotatePlanNormal[type - MT_ROTATE_X]);
  2042. }
  2043. else
  2044. {
  2045. gContext.mTranslationPlan = BuildPlan(gContext.mModelSource.v.position, directionUnary[type - MT_ROTATE_X]);
  2046. }
  2047. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
  2048. vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position;
  2049. gContext.mRotationVectorSource = Normalized(localPos);
  2050. gContext.mRotationAngleOrigin = ComputeAngleOnPlan();
  2051. }
  2052. }
  2053. // rotation
  2054. if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(gContext.mCurrentOperation))
  2055. {
  2056. #if IMGUI_VERSION_NUM >= 18723
  2057. ImGui::SetNextFrameWantCaptureMouse(true);
  2058. #else
  2059. ImGui::CaptureMouseFromApp();
  2060. #endif
  2061. gContext.mRotationAngle = ComputeAngleOnPlan();
  2062. if (snap)
  2063. {
  2064. float snapInRadian = snap[0] * DEG2RAD;
  2065. ComputeSnap(&gContext.mRotationAngle, snapInRadian);
  2066. }
  2067. vec_t rotationAxisLocalSpace;
  2068. rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
  2069. rotationAxisLocalSpace.Normalize();
  2070. matrix_t deltaRotation;
  2071. deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - gContext.mRotationAngleOrigin);
  2072. if (gContext.mRotationAngle != gContext.mRotationAngleOrigin)
  2073. {
  2074. modified = true;
  2075. }
  2076. gContext.mRotationAngleOrigin = gContext.mRotationAngle;
  2077. matrix_t scaleOrigin;
  2078. scaleOrigin.Scale(gContext.mModelScaleOrigin);
  2079. if (applyRotationLocaly)
  2080. {
  2081. *(matrix_t*)matrix = scaleOrigin * deltaRotation * gContext.mModelLocal;
  2082. }
  2083. else
  2084. {
  2085. matrix_t res = gContext.mModelSource;
  2086. res.v.position.Set(0.f);
  2087. *(matrix_t*)matrix = res * deltaRotation;
  2088. ((matrix_t*)matrix)->v.position = gContext.mModelSource.v.position;
  2089. }
  2090. if (deltaMatrix)
  2091. {
  2092. *(matrix_t*)deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel;
  2093. }
  2094. if (!io.MouseDown[0])
  2095. {
  2096. gContext.mbUsing = false;
  2097. gContext.mEditingID = -1;
  2098. }
  2099. type = gContext.mCurrentOperation;
  2100. }
  2101. return modified;
  2102. }
  2103. void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale)
  2104. {
  2105. matrix_t mat = *(matrix_t*)matrix;
  2106. scale[0] = mat.v.right.Length();
  2107. scale[1] = mat.v.up.Length();
  2108. scale[2] = mat.v.dir.Length();
  2109. mat.OrthoNormalize();
  2110. rotation[0] = RAD2DEG * atan2f(mat.m[1][2], mat.m[2][2]);
  2111. rotation[1] = RAD2DEG * atan2f(-mat.m[0][2], sqrtf(mat.m[1][2] * mat.m[1][2] + mat.m[2][2] * mat.m[2][2]));
  2112. rotation[2] = RAD2DEG * atan2f(mat.m[0][1], mat.m[0][0]);
  2113. translation[0] = mat.v.position.x;
  2114. translation[1] = mat.v.position.y;
  2115. translation[2] = mat.v.position.z;
  2116. }
  2117. void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix)
  2118. {
  2119. matrix_t& mat = *(matrix_t*)matrix;
  2120. matrix_t rot[3];
  2121. for (int i = 0; i < 3; i++)
  2122. {
  2123. rot[i].RotationAxis(directionUnary[i], rotation[i] * DEG2RAD);
  2124. }
  2125. mat = rot[0] * rot[1] * rot[2];
  2126. float validScale[3];
  2127. for (int i = 0; i < 3; i++)
  2128. {
  2129. if (fabsf(scale[i]) < FLT_EPSILON)
  2130. {
  2131. validScale[i] = 0.001f;
  2132. }
  2133. else
  2134. {
  2135. validScale[i] = scale[i];
  2136. }
  2137. }
  2138. mat.v.right *= validScale[0];
  2139. mat.v.up *= validScale[1];
  2140. mat.v.dir *= validScale[2];
  2141. mat.v.position.Set(translation[0], translation[1], translation[2], 1.f);
  2142. }
  2143. void SetID(int id)
  2144. {
  2145. gContext.mActualID = id;
  2146. }
  2147. void AllowAxisFlip(bool value)
  2148. {
  2149. gContext.mAllowAxisFlip = value;
  2150. }
  2151. void SetAxisLimit(float value)
  2152. {
  2153. gContext.mAxisLimit=value;
  2154. }
  2155. void SetPlaneLimit(float value)
  2156. {
  2157. gContext.mPlaneLimit = value;
  2158. }
  2159. bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix, const float* snap, const float* localBounds, const float* boundsSnap)
  2160. {
  2161. // Scale is always local or matrix will be skewed when applying world scale or oriented matrix
  2162. ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode);
  2163. // set delta to identity
  2164. if (deltaMatrix)
  2165. {
  2166. ((matrix_t*)deltaMatrix)->SetToIdentity();
  2167. }
  2168. // behind camera
  2169. vec_t camSpacePosition;
  2170. camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP);
  2171. if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f && !gContext.mbUsing)
  2172. {
  2173. return false;
  2174. }
  2175. // --
  2176. int type = MT_NONE;
  2177. bool manipulated = false;
  2178. if (gContext.mbEnable)
  2179. {
  2180. if (!gContext.mbUsingBounds)
  2181. {
  2182. manipulated = HandleTranslation(matrix, deltaMatrix, operation, type, snap) ||
  2183. HandleScale(matrix, deltaMatrix, operation, type, snap) ||
  2184. HandleRotation(matrix, deltaMatrix, operation, type, snap);
  2185. }
  2186. }
  2187. if (localBounds && !gContext.mbUsing)
  2188. {
  2189. HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap, operation);
  2190. }
  2191. gContext.mOperation = operation;
  2192. if (!gContext.mbUsingBounds)
  2193. {
  2194. DrawRotationGizmo(operation, type);
  2195. DrawTranslationGizmo(operation, type);
  2196. DrawScaleGizmo(operation, type);
  2197. DrawScaleUniveralGizmo(operation, type);
  2198. }
  2199. return manipulated;
  2200. }
  2201. void SetGizmoSizeClipSpace(float value)
  2202. {
  2203. gContext.mGizmoSizeClipSpace = value;
  2204. }
  2205. ///////////////////////////////////////////////////////////////////////////////////////////////////
  2206. void ComputeFrustumPlanes(vec_t* frustum, const float* clip)
  2207. {
  2208. frustum[0].x = clip[3] - clip[0];
  2209. frustum[0].y = clip[7] - clip[4];
  2210. frustum[0].z = clip[11] - clip[8];
  2211. frustum[0].w = clip[15] - clip[12];
  2212. frustum[1].x = clip[3] + clip[0];
  2213. frustum[1].y = clip[7] + clip[4];
  2214. frustum[1].z = clip[11] + clip[8];
  2215. frustum[1].w = clip[15] + clip[12];
  2216. frustum[2].x = clip[3] + clip[1];
  2217. frustum[2].y = clip[7] + clip[5];
  2218. frustum[2].z = clip[11] + clip[9];
  2219. frustum[2].w = clip[15] + clip[13];
  2220. frustum[3].x = clip[3] - clip[1];
  2221. frustum[3].y = clip[7] - clip[5];
  2222. frustum[3].z = clip[11] - clip[9];
  2223. frustum[3].w = clip[15] - clip[13];
  2224. frustum[4].x = clip[3] - clip[2];
  2225. frustum[4].y = clip[7] - clip[6];
  2226. frustum[4].z = clip[11] - clip[10];
  2227. frustum[4].w = clip[15] - clip[14];
  2228. frustum[5].x = clip[3] + clip[2];
  2229. frustum[5].y = clip[7] + clip[6];
  2230. frustum[5].z = clip[11] + clip[10];
  2231. frustum[5].w = clip[15] + clip[14];
  2232. for (int i = 0; i < 6; i++)
  2233. {
  2234. frustum[i].Normalize();
  2235. }
  2236. }
  2237. void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount)
  2238. {
  2239. matrix_t viewInverse;
  2240. viewInverse.Inverse(*(matrix_t*)view);
  2241. struct CubeFace
  2242. {
  2243. float z;
  2244. ImVec2 faceCoordsScreen[4];
  2245. ImU32 color;
  2246. };
  2247. CubeFace* faces = (CubeFace*)_malloca(sizeof(CubeFace) * matrixCount * 6);
  2248. if (!faces)
  2249. {
  2250. return;
  2251. }
  2252. vec_t frustum[6];
  2253. matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection;
  2254. ComputeFrustumPlanes(frustum, viewProjection.m16);
  2255. int cubeFaceCount = 0;
  2256. for (int cube = 0; cube < matrixCount; cube++)
  2257. {
  2258. const float* matrix = &matrices[cube * 16];
  2259. matrix_t res = *(matrix_t*)matrix * *(matrix_t*)view * *(matrix_t*)projection;
  2260. for (int iFace = 0; iFace < 6; iFace++)
  2261. {
  2262. const int normalIndex = (iFace % 3);
  2263. const int perpXIndex = (normalIndex + 1) % 3;
  2264. const int perpYIndex = (normalIndex + 2) % 3;
  2265. const float invert = (iFace > 2) ? -1.f : 1.f;
  2266. const vec_t faceCoords[4] = { directionUnary[normalIndex] + directionUnary[perpXIndex] + directionUnary[perpYIndex],
  2267. directionUnary[normalIndex] + directionUnary[perpXIndex] - directionUnary[perpYIndex],
  2268. directionUnary[normalIndex] - directionUnary[perpXIndex] - directionUnary[perpYIndex],
  2269. directionUnary[normalIndex] - directionUnary[perpXIndex] + directionUnary[perpYIndex],
  2270. };
  2271. // clipping
  2272. /*
  2273. bool skipFace = false;
  2274. for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
  2275. {
  2276. vec_t camSpacePosition;
  2277. camSpacePosition.TransformPoint(faceCoords[iCoord] * 0.5f * invert, res);
  2278. if (camSpacePosition.z < 0.001f)
  2279. {
  2280. skipFace = true;
  2281. break;
  2282. }
  2283. }
  2284. if (skipFace)
  2285. {
  2286. continue;
  2287. }
  2288. */
  2289. vec_t centerPosition, centerPositionVP;
  2290. centerPosition.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, *(matrix_t*)matrix);
  2291. centerPositionVP.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, res);
  2292. bool inFrustum = true;
  2293. for (int iFrustum = 0; iFrustum < 6; iFrustum++)
  2294. {
  2295. float dist = DistanceToPlane(centerPosition, frustum[iFrustum]);
  2296. if (dist < 0.f)
  2297. {
  2298. inFrustum = false;
  2299. break;
  2300. }
  2301. }
  2302. if (!inFrustum)
  2303. {
  2304. continue;
  2305. }
  2306. CubeFace& cubeFace = faces[cubeFaceCount];
  2307. // 3D->2D
  2308. //ImVec2 faceCoordsScreen[4];
  2309. for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
  2310. {
  2311. cubeFace.faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res);
  2312. }
  2313. ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex);
  2314. cubeFace.color = directionColor | IM_COL32(0x80, 0x80, 0x80, 0);
  2315. cubeFace.z = centerPositionVP.z / centerPositionVP.w;
  2316. cubeFaceCount++;
  2317. }
  2318. }
  2319. qsort(faces, cubeFaceCount, sizeof(CubeFace), [](void const* _a, void const* _b) {
  2320. CubeFace* a = (CubeFace*)_a;
  2321. CubeFace* b = (CubeFace*)_b;
  2322. if (a->z < b->z)
  2323. {
  2324. return 1;
  2325. }
  2326. return -1;
  2327. });
  2328. // draw face with lighter color
  2329. for (int iFace = 0; iFace < cubeFaceCount; iFace++)
  2330. {
  2331. const CubeFace& cubeFace = faces[iFace];
  2332. gContext.mDrawList->AddConvexPolyFilled(cubeFace.faceCoordsScreen, 4, cubeFace.color);
  2333. }
  2334. _freea(faces);
  2335. }
  2336. void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize)
  2337. {
  2338. matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection;
  2339. vec_t frustum[6];
  2340. ComputeFrustumPlanes(frustum, viewProjection.m16);
  2341. matrix_t res = *(matrix_t*)matrix * viewProjection;
  2342. for (float f = -gridSize; f <= gridSize; f += 1.f)
  2343. {
  2344. for (int dir = 0; dir < 2; dir++)
  2345. {
  2346. vec_t ptA = makeVect(dir ? -gridSize : f, 0.f, dir ? f : -gridSize);
  2347. vec_t ptB = makeVect(dir ? gridSize : f, 0.f, dir ? f : gridSize);
  2348. bool visible = true;
  2349. for (int i = 0; i < 6; i++)
  2350. {
  2351. float dA = DistanceToPlane(ptA, frustum[i]);
  2352. float dB = DistanceToPlane(ptB, frustum[i]);
  2353. if (dA < 0.f && dB < 0.f)
  2354. {
  2355. visible = false;
  2356. break;
  2357. }
  2358. if (dA > 0.f && dB > 0.f)
  2359. {
  2360. continue;
  2361. }
  2362. if (dA < 0.f)
  2363. {
  2364. float len = fabsf(dA - dB);
  2365. float t = fabsf(dA) / len;
  2366. ptA.Lerp(ptB, t);
  2367. }
  2368. if (dB < 0.f)
  2369. {
  2370. float len = fabsf(dB - dA);
  2371. float t = fabsf(dB) / len;
  2372. ptB.Lerp(ptA, t);
  2373. }
  2374. }
  2375. if (visible)
  2376. {
  2377. ImU32 col = IM_COL32(0x80, 0x80, 0x80, 0xFF);
  2378. col = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? IM_COL32(0x90, 0x90, 0x90, 0xFF) : col;
  2379. col = (fabsf(f) < FLT_EPSILON) ? IM_COL32(0x40, 0x40, 0x40, 0xFF): col;
  2380. float thickness = 1.f;
  2381. thickness = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? 1.5f : thickness;
  2382. thickness = (fabsf(f) < FLT_EPSILON) ? 2.3f : thickness;
  2383. gContext.mDrawList->AddLine(worldToPos(ptA, res), worldToPos(ptB, res), col, thickness);
  2384. }
  2385. }
  2386. }
  2387. }
  2388. void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor)
  2389. {
  2390. // Scale is always local or matrix will be skewed when applying world scale or oriented matrix
  2391. ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode);
  2392. ViewManipulate(view, length, position, size, backgroundColor);
  2393. }
  2394. void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor)
  2395. {
  2396. static bool isDraging = false;
  2397. static bool isClicking = false;
  2398. static bool isInside = false;
  2399. static vec_t interpolationUp;
  2400. static vec_t interpolationDir;
  2401. static int interpolationFrames = 0;
  2402. const vec_t referenceUp = makeVect(0.f, 1.f, 0.f);
  2403. matrix_t svgView, svgProjection;
  2404. svgView = gContext.mViewMat;
  2405. svgProjection = gContext.mProjectionMat;
  2406. ImGuiIO& io = ImGui::GetIO();
  2407. gContext.mDrawList->AddRectFilled(position, position + size, backgroundColor);
  2408. matrix_t viewInverse;
  2409. viewInverse.Inverse(*(matrix_t*)view);
  2410. const vec_t camTarget = viewInverse.v.position - viewInverse.v.dir * length;
  2411. // view/projection matrices
  2412. const float distance = 3.f;
  2413. matrix_t cubeProjection, cubeView;
  2414. float fov = acosf(distance / (sqrtf(distance * distance + 3.f))) * RAD2DEG;
  2415. Perspective(fov / sqrtf(2.f), size.x / size.y, 0.01f, 1000.f, cubeProjection.m16);
  2416. vec_t dir = makeVect(viewInverse.m[2][0], viewInverse.m[2][1], viewInverse.m[2][2]);
  2417. vec_t up = makeVect(viewInverse.m[1][0], viewInverse.m[1][1], viewInverse.m[1][2]);
  2418. vec_t eye = dir * distance;
  2419. vec_t zero = makeVect(0.f, 0.f);
  2420. LookAt(&eye.x, &zero.x, &up.x, cubeView.m16);
  2421. // set context
  2422. gContext.mViewMat = cubeView;
  2423. gContext.mProjectionMat = cubeProjection;
  2424. ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector, position, size);
  2425. const matrix_t res = cubeView * cubeProjection;
  2426. // panels
  2427. static const ImVec2 panelPosition[9] = { ImVec2(0.75f,0.75f), ImVec2(0.25f, 0.75f), ImVec2(0.f, 0.75f),
  2428. ImVec2(0.75f, 0.25f), ImVec2(0.25f, 0.25f), ImVec2(0.f, 0.25f),
  2429. ImVec2(0.75f, 0.f), ImVec2(0.25f, 0.f), ImVec2(0.f, 0.f) };
  2430. static const ImVec2 panelSize[9] = { ImVec2(0.25f,0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f),
  2431. ImVec2(0.25f, 0.5f), ImVec2(0.5f, 0.5f), ImVec2(0.25f, 0.5f),
  2432. ImVec2(0.25f, 0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f) };
  2433. // tag faces
  2434. bool boxes[27]{};
  2435. static int overBox = -1;
  2436. for (int iPass = 0; iPass < 2; iPass++)
  2437. {
  2438. for (int iFace = 0; iFace < 6; iFace++)
  2439. {
  2440. const int normalIndex = (iFace % 3);
  2441. const int perpXIndex = (normalIndex + 1) % 3;
  2442. const int perpYIndex = (normalIndex + 2) % 3;
  2443. const float invert = (iFace > 2) ? -1.f : 1.f;
  2444. const vec_t indexVectorX = directionUnary[perpXIndex] * invert;
  2445. const vec_t indexVectorY = directionUnary[perpYIndex] * invert;
  2446. const vec_t boxOrigin = directionUnary[normalIndex] * -invert - indexVectorX - indexVectorY;
  2447. // plan local space
  2448. const vec_t n = directionUnary[normalIndex] * invert;
  2449. vec_t viewSpaceNormal = n;
  2450. vec_t viewSpacePoint = n * 0.5f;
  2451. viewSpaceNormal.TransformVector(cubeView);
  2452. viewSpaceNormal.Normalize();
  2453. viewSpacePoint.TransformPoint(cubeView);
  2454. const vec_t viewSpaceFacePlan = BuildPlan(viewSpacePoint, viewSpaceNormal);
  2455. // back face culling
  2456. if (viewSpaceFacePlan.w > 0.f)
  2457. {
  2458. continue;
  2459. }
  2460. const vec_t facePlan = BuildPlan(n * 0.5f, n);
  2461. const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, facePlan);
  2462. vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len - (n * 0.5f);
  2463. float localx = Dot(directionUnary[perpXIndex], posOnPlan) * invert + 0.5f;
  2464. float localy = Dot(directionUnary[perpYIndex], posOnPlan) * invert + 0.5f;
  2465. // panels
  2466. const vec_t dx = directionUnary[perpXIndex];
  2467. const vec_t dy = directionUnary[perpYIndex];
  2468. const vec_t origin = directionUnary[normalIndex] - dx - dy;
  2469. for (int iPanel = 0; iPanel < 9; iPanel++)
  2470. {
  2471. vec_t boxCoord = boxOrigin + indexVectorX * float(iPanel % 3) + indexVectorY * float(iPanel / 3) + makeVect(1.f, 1.f, 1.f);
  2472. const ImVec2 p = panelPosition[iPanel] * 2.f;
  2473. const ImVec2 s = panelSize[iPanel] * 2.f;
  2474. ImVec2 faceCoordsScreen[4];
  2475. vec_t panelPos[4] = { dx * p.x + dy * p.y,
  2476. dx * p.x + dy * (p.y + s.y),
  2477. dx * (p.x + s.x) + dy * (p.y + s.y),
  2478. dx * (p.x + s.x) + dy * p.y };
  2479. for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
  2480. {
  2481. faceCoordsScreen[iCoord] = worldToPos((panelPos[iCoord] + origin) * 0.5f * invert, res, position, size);
  2482. }
  2483. const ImVec2 panelCorners[2] = { panelPosition[iPanel], panelPosition[iPanel] + panelSize[iPanel] };
  2484. bool insidePanel = localx > panelCorners[0].x && localx < panelCorners[1].x && localy > panelCorners[0].y && localy < panelCorners[1].y;
  2485. int boxCoordInt = int(boxCoord.x * 9.f + boxCoord.y * 3.f + boxCoord.z);
  2486. IM_ASSERT(boxCoordInt < 27);
  2487. boxes[boxCoordInt] |= insidePanel && (!isDraging) && gContext.mbMouseOver;
  2488. // draw face with lighter color
  2489. if (iPass)
  2490. {
  2491. ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex);
  2492. gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, (directionColor | IM_COL32(0x80, 0x80, 0x80, 0x80)) | (isInside ? IM_COL32(0x08, 0x08, 0x08, 0) : 0));
  2493. if (boxes[boxCoordInt])
  2494. {
  2495. gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, IM_COL32(0xF0, 0xA0, 0x60, 0x80));
  2496. if (io.MouseDown[0] && !isClicking && !isDraging && GImGui->ActiveId == 0) {
  2497. overBox = boxCoordInt;
  2498. isClicking = true;
  2499. isDraging = true;
  2500. }
  2501. }
  2502. }
  2503. }
  2504. }
  2505. }
  2506. if (interpolationFrames)
  2507. {
  2508. interpolationFrames--;
  2509. vec_t newDir = viewInverse.v.dir;
  2510. newDir.Lerp(interpolationDir, 0.2f);
  2511. newDir.Normalize();
  2512. vec_t newUp = viewInverse.v.up;
  2513. newUp.Lerp(interpolationUp, 0.3f);
  2514. newUp.Normalize();
  2515. newUp = interpolationUp;
  2516. vec_t newEye = camTarget + newDir * length;
  2517. LookAt(&newEye.x, &camTarget.x, &newUp.x, view);
  2518. }
  2519. isInside = gContext.mbMouseOver && ImRect(position, position + size).Contains(io.MousePos);
  2520. if (io.MouseDown[0] && (fabsf(io.MouseDelta[0]) || fabsf(io.MouseDelta[1])) && isClicking)
  2521. {
  2522. isClicking = false;
  2523. }
  2524. if (!io.MouseDown[0])
  2525. {
  2526. if (isClicking)
  2527. {
  2528. // apply new view direction
  2529. int cx = overBox / 9;
  2530. int cy = (overBox - cx * 9) / 3;
  2531. int cz = overBox % 3;
  2532. interpolationDir = makeVect(1.f - (float)cx, 1.f - (float)cy, 1.f - (float)cz);
  2533. interpolationDir.Normalize();
  2534. if (fabsf(Dot(interpolationDir, referenceUp)) > 1.0f - 0.01f)
  2535. {
  2536. vec_t right = viewInverse.v.right;
  2537. if (fabsf(right.x) > fabsf(right.z))
  2538. {
  2539. right.z = 0.f;
  2540. }
  2541. else
  2542. {
  2543. right.x = 0.f;
  2544. }
  2545. right.Normalize();
  2546. interpolationUp = Cross(interpolationDir, right);
  2547. interpolationUp.Normalize();
  2548. }
  2549. else
  2550. {
  2551. interpolationUp = referenceUp;
  2552. }
  2553. interpolationFrames = 40;
  2554. }
  2555. isClicking = false;
  2556. isDraging = false;
  2557. }
  2558. if (isDraging)
  2559. {
  2560. matrix_t rx, ry, roll;
  2561. rx.RotationAxis(referenceUp, -io.MouseDelta.x * 0.01f);
  2562. ry.RotationAxis(viewInverse.v.right, -io.MouseDelta.y * 0.01f);
  2563. roll = rx * ry;
  2564. vec_t newDir = viewInverse.v.dir;
  2565. newDir.TransformVector(roll);
  2566. newDir.Normalize();
  2567. // clamp
  2568. vec_t planDir = Cross(viewInverse.v.right, referenceUp);
  2569. planDir.y = 0.f;
  2570. planDir.Normalize();
  2571. float dt = Dot(planDir, newDir);
  2572. if (dt < 0.0f)
  2573. {
  2574. newDir += planDir * dt;
  2575. newDir.Normalize();
  2576. }
  2577. vec_t newEye = camTarget + newDir * length;
  2578. LookAt(&newEye.x, &camTarget.x, &referenceUp.x, view);
  2579. }
  2580. // restore view/projection because it was used to compute ray
  2581. ComputeContext(svgView.m16, svgProjection.m16, gContext.mModelSource.m16, gContext.mMode);
  2582. }
  2583. };