| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996 |
- // https://github.com/CedricGuillemet/ImGuizmo
- // v 1.89 WIP
- //
- // The MIT License(MIT)
- //
- // Copyright(c) 2021 Cedric Guillemet
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files(the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions :
- //
- // The above copyright notice and this permission notice shall be included in all
- // copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- // SOFTWARE.
- //
- #ifndef IMGUI_DEFINE_MATH_OPERATORS
- #define IMGUI_DEFINE_MATH_OPERATORS
- #endif
- #include "imgui.h"
- #include "imgui_internal.h"
- #include "ImGuizmo.h"
- #if defined(_MSC_VER) || defined(__MINGW32__)
- #include <malloc.h>
- #endif
- #if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
- #define _malloca(x) alloca(x)
- #define _freea(x)
- #endif
- // includes patches for multiview from
- // https://github.com/CedricGuillemet/ImGuizmo/issues/15
- namespace IMGUIZMO_NAMESPACE
- {
- static const float ZPI = 3.14159265358979323846f;
- static const float RAD2DEG = (180.f / ZPI);
- static const float DEG2RAD = (ZPI / 180.f);
- const float screenRotateSize = 0.06f;
- // scale a bit so translate axis do not touch when in universal
- const float rotationDisplayFactor = 1.2f;
- static OPERATION operator&(OPERATION lhs, OPERATION rhs)
- {
- return static_cast<OPERATION>(static_cast<int>(lhs) & static_cast<int>(rhs));
- }
- static bool operator!=(OPERATION lhs, int rhs)
- {
- return static_cast<int>(lhs) != rhs;
- }
- static bool Intersects(OPERATION lhs, OPERATION rhs)
- {
- return (lhs & rhs) != 0;
- }
- // True if lhs contains rhs
- static bool Contains(OPERATION lhs, OPERATION rhs)
- {
- return (lhs & rhs) == rhs;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // utility and math
- void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r)
- {
- r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
- r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
- r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
- r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
- r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
- r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
- r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
- r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
- r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
- r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
- r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
- r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
- r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
- r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
- r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
- r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
- }
- void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16)
- {
- float temp, temp2, temp3, temp4;
- temp = 2.0f * znear;
- temp2 = right - left;
- temp3 = top - bottom;
- temp4 = zfar - znear;
- m16[0] = temp / temp2;
- m16[1] = 0.0;
- m16[2] = 0.0;
- m16[3] = 0.0;
- m16[4] = 0.0;
- m16[5] = temp / temp3;
- m16[6] = 0.0;
- m16[7] = 0.0;
- m16[8] = (right + left) / temp2;
- m16[9] = (top + bottom) / temp3;
- m16[10] = (-zfar - znear) / temp4;
- m16[11] = -1.0f;
- m16[12] = 0.0;
- m16[13] = 0.0;
- m16[14] = (-temp * zfar) / temp4;
- m16[15] = 0.0;
- }
- void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16)
- {
- float ymax, xmax;
- ymax = znear * tanf(fovyInDegrees * DEG2RAD);
- xmax = ymax * aspectRatio;
- Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16);
- }
- void Cross(const float* a, const float* b, float* r)
- {
- r[0] = a[1] * b[2] - a[2] * b[1];
- r[1] = a[2] * b[0] - a[0] * b[2];
- r[2] = a[0] * b[1] - a[1] * b[0];
- }
- float Dot(const float* a, const float* b)
- {
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
- }
- void Normalize(const float* a, float* r)
- {
- float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON);
- r[0] = a[0] * il;
- r[1] = a[1] * il;
- r[2] = a[2] * il;
- }
- void LookAt(const float* eye, const float* at, const float* up, float* m16)
- {
- float X[3], Y[3], Z[3], tmp[3];
- tmp[0] = eye[0] - at[0];
- tmp[1] = eye[1] - at[1];
- tmp[2] = eye[2] - at[2];
- Normalize(tmp, Z);
- Normalize(up, Y);
- Cross(Y, Z, tmp);
- Normalize(tmp, X);
- Cross(Z, X, tmp);
- Normalize(tmp, Y);
- m16[0] = X[0];
- m16[1] = Y[0];
- m16[2] = Z[0];
- m16[3] = 0.0f;
- m16[4] = X[1];
- m16[5] = Y[1];
- m16[6] = Z[1];
- m16[7] = 0.0f;
- m16[8] = X[2];
- m16[9] = Y[2];
- m16[10] = Z[2];
- m16[11] = 0.0f;
- m16[12] = -Dot(X, eye);
- m16[13] = -Dot(Y, eye);
- m16[14] = -Dot(Z, eye);
- m16[15] = 1.0f;
- }
- template <typename T> T Clamp(T x, T y, T z) { return ((x < y) ? y : ((x > z) ? z : x)); }
- template <typename T> T max(T x, T y) { return (x > y) ? x : y; }
- template <typename T> T min(T x, T y) { return (x < y) ? x : y; }
- template <typename T> bool IsWithin(T x, T y, T z) { return (x >= y) && (x <= z); }
- struct matrix_t;
- struct vec_t
- {
- public:
- float x, y, z, w;
- void Lerp(const vec_t& v, float t)
- {
- x += (v.x - x) * t;
- y += (v.y - y) * t;
- z += (v.z - z) * t;
- w += (v.w - w) * t;
- }
- void Set(float v) { x = y = z = w = v; }
- void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; }
- vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }
- vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }
- vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; }
- vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
- vec_t operator * (float f) const;
- vec_t operator - () const;
- vec_t operator - (const vec_t& v) const;
- vec_t operator + (const vec_t& v) const;
- vec_t operator * (const vec_t& v) const;
- const vec_t& operator + () const { return (*this); }
- float Length() const { return sqrtf(x * x + y * y + z * z); };
- float LengthSq() const { return (x * x + y * y + z * z); };
- vec_t Normalize() { (*this) *= (1.f / ( Length() > FLT_EPSILON ? Length() : FLT_EPSILON ) ); return (*this); }
- vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
- vec_t Abs() const;
- void Cross(const vec_t& v)
- {
- vec_t res;
- res.x = y * v.z - z * v.y;
- res.y = z * v.x - x * v.z;
- res.z = x * v.y - y * v.x;
- x = res.x;
- y = res.y;
- z = res.z;
- w = 0.f;
- }
- void Cross(const vec_t& v1, const vec_t& v2)
- {
- x = v1.y * v2.z - v1.z * v2.y;
- y = v1.z * v2.x - v1.x * v2.z;
- z = v1.x * v2.y - v1.y * v2.x;
- w = 0.f;
- }
- float Dot(const vec_t& v) const
- {
- return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w);
- }
- float Dot3(const vec_t& v) const
- {
- return (x * v.x) + (y * v.y) + (z * v.z);
- }
- void Transform(const matrix_t& matrix);
- void Transform(const vec_t& s, const matrix_t& matrix);
- void TransformVector(const matrix_t& matrix);
- void TransformPoint(const matrix_t& matrix);
- void TransformVector(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformVector(matrix); }
- void TransformPoint(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformPoint(matrix); }
- float& operator [] (size_t index) { return ((float*)&x)[index]; }
- const float& operator [] (size_t index) const { return ((float*)&x)[index]; }
- bool operator!=(const vec_t& other) const { return memcmp(this, &other, sizeof(vec_t)) != 0; }
- };
- 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; }
- 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; }
- vec_t vec_t::operator * (float f) const { return makeVect(x * f, y * f, z * f, w * f); }
- vec_t vec_t::operator - () const { return makeVect(-x, -y, -z, -w); }
- vec_t vec_t::operator - (const vec_t& v) const { return makeVect(x - v.x, y - v.y, z - v.z, w - v.w); }
- vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }
- vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }
- vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); }
- vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; }
- vec_t Cross(const vec_t& v1, const vec_t& v2)
- {
- vec_t res;
- res.x = v1.y * v2.z - v1.z * v2.y;
- res.y = v1.z * v2.x - v1.x * v2.z;
- res.z = v1.x * v2.y - v1.y * v2.x;
- res.w = 0.f;
- return res;
- }
- float Dot(const vec_t& v1, const vec_t& v2)
- {
- return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
- }
- vec_t BuildPlan(const vec_t& p_point1, const vec_t& p_normal)
- {
- vec_t normal, res;
- normal.Normalize(p_normal);
- res.w = normal.Dot(p_point1);
- res.x = normal.x;
- res.y = normal.y;
- res.z = normal.z;
- return res;
- }
- struct matrix_t
- {
- public:
- union
- {
- float m[4][4];
- float m16[16];
- struct
- {
- vec_t right, up, dir, position;
- } v;
- vec_t component[4];
- };
- operator float* () { return m16; }
- operator const float* () const { return m16; }
- void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); }
- void Translation(const vec_t& vt)
- {
- v.right.Set(1.f, 0.f, 0.f, 0.f);
- v.up.Set(0.f, 1.f, 0.f, 0.f);
- v.dir.Set(0.f, 0.f, 1.f, 0.f);
- v.position.Set(vt.x, vt.y, vt.z, 1.f);
- }
- void Scale(float _x, float _y, float _z)
- {
- v.right.Set(_x, 0.f, 0.f, 0.f);
- v.up.Set(0.f, _y, 0.f, 0.f);
- v.dir.Set(0.f, 0.f, _z, 0.f);
- v.position.Set(0.f, 0.f, 0.f, 1.f);
- }
- void Scale(const vec_t& s) { Scale(s.x, s.y, s.z); }
- matrix_t& operator *= (const matrix_t& mat)
- {
- matrix_t tmpMat;
- tmpMat = *this;
- tmpMat.Multiply(mat);
- *this = tmpMat;
- return *this;
- }
- matrix_t operator * (const matrix_t& mat) const
- {
- matrix_t matT;
- matT.Multiply(*this, mat);
- return matT;
- }
- void Multiply(const matrix_t& matrix)
- {
- matrix_t tmp;
- tmp = *this;
- FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this);
- }
- void Multiply(const matrix_t& m1, const matrix_t& m2)
- {
- FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this);
- }
- float GetDeterminant() const
- {
- 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] -
- 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];
- }
- float Inverse(const matrix_t& srcMatrix, bool affine = false);
- void SetToIdentity()
- {
- v.right.Set(1.f, 0.f, 0.f, 0.f);
- v.up.Set(0.f, 1.f, 0.f, 0.f);
- v.dir.Set(0.f, 0.f, 1.f, 0.f);
- v.position.Set(0.f, 0.f, 0.f, 1.f);
- }
- void Transpose()
- {
- matrix_t tmpm;
- for (int l = 0; l < 4; l++)
- {
- for (int c = 0; c < 4; c++)
- {
- tmpm.m[l][c] = m[c][l];
- }
- }
- (*this) = tmpm;
- }
- void RotationAxis(const vec_t& axis, float angle);
- void OrthoNormalize()
- {
- v.right.Normalize();
- v.up.Normalize();
- v.dir.Normalize();
- }
- };
- void vec_t::Transform(const matrix_t& matrix)
- {
- vec_t out;
- out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + w * matrix.m[3][0];
- out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + w * matrix.m[3][1];
- out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + w * matrix.m[3][2];
- out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + w * matrix.m[3][3];
- x = out.x;
- y = out.y;
- z = out.z;
- w = out.w;
- }
- void vec_t::Transform(const vec_t& s, const matrix_t& matrix)
- {
- *this = s;
- Transform(matrix);
- }
- void vec_t::TransformPoint(const matrix_t& matrix)
- {
- vec_t out;
- out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0];
- out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1];
- out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2];
- out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3];
- x = out.x;
- y = out.y;
- z = out.z;
- w = out.w;
- }
- void vec_t::TransformVector(const matrix_t& matrix)
- {
- vec_t out;
- out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0];
- out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1];
- out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2];
- out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3];
- x = out.x;
- y = out.y;
- z = out.z;
- w = out.w;
- }
- float matrix_t::Inverse(const matrix_t& srcMatrix, bool affine)
- {
- float det = 0;
- if (affine)
- {
- det = GetDeterminant();
- float s = 1 / det;
- m[0][0] = (srcMatrix.m[1][1] * srcMatrix.m[2][2] - srcMatrix.m[1][2] * srcMatrix.m[2][1]) * s;
- m[0][1] = (srcMatrix.m[2][1] * srcMatrix.m[0][2] - srcMatrix.m[2][2] * srcMatrix.m[0][1]) * s;
- m[0][2] = (srcMatrix.m[0][1] * srcMatrix.m[1][2] - srcMatrix.m[0][2] * srcMatrix.m[1][1]) * s;
- m[1][0] = (srcMatrix.m[1][2] * srcMatrix.m[2][0] - srcMatrix.m[1][0] * srcMatrix.m[2][2]) * s;
- m[1][1] = (srcMatrix.m[2][2] * srcMatrix.m[0][0] - srcMatrix.m[2][0] * srcMatrix.m[0][2]) * s;
- m[1][2] = (srcMatrix.m[0][2] * srcMatrix.m[1][0] - srcMatrix.m[0][0] * srcMatrix.m[1][2]) * s;
- m[2][0] = (srcMatrix.m[1][0] * srcMatrix.m[2][1] - srcMatrix.m[1][1] * srcMatrix.m[2][0]) * s;
- m[2][1] = (srcMatrix.m[2][0] * srcMatrix.m[0][1] - srcMatrix.m[2][1] * srcMatrix.m[0][0]) * s;
- m[2][2] = (srcMatrix.m[0][0] * srcMatrix.m[1][1] - srcMatrix.m[0][1] * srcMatrix.m[1][0]) * s;
- m[3][0] = -(m[0][0] * srcMatrix.m[3][0] + m[1][0] * srcMatrix.m[3][1] + m[2][0] * srcMatrix.m[3][2]);
- m[3][1] = -(m[0][1] * srcMatrix.m[3][0] + m[1][1] * srcMatrix.m[3][1] + m[2][1] * srcMatrix.m[3][2]);
- m[3][2] = -(m[0][2] * srcMatrix.m[3][0] + m[1][2] * srcMatrix.m[3][1] + m[2][2] * srcMatrix.m[3][2]);
- }
- else
- {
- // transpose matrix
- float src[16];
- for (int i = 0; i < 4; ++i)
- {
- src[i] = srcMatrix.m16[i * 4];
- src[i + 4] = srcMatrix.m16[i * 4 + 1];
- src[i + 8] = srcMatrix.m16[i * 4 + 2];
- src[i + 12] = srcMatrix.m16[i * 4 + 3];
- }
- // calculate pairs for first 8 elements (cofactors)
- float tmp[12]; // temp array for pairs
- tmp[0] = src[10] * src[15];
- tmp[1] = src[11] * src[14];
- tmp[2] = src[9] * src[15];
- tmp[3] = src[11] * src[13];
- tmp[4] = src[9] * src[14];
- tmp[5] = src[10] * src[13];
- tmp[6] = src[8] * src[15];
- tmp[7] = src[11] * src[12];
- tmp[8] = src[8] * src[14];
- tmp[9] = src[10] * src[12];
- tmp[10] = src[8] * src[13];
- tmp[11] = src[9] * src[12];
- // calculate first 8 elements (cofactors)
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- // calculate pairs for second 8 elements (cofactors)
- tmp[0] = src[2] * src[7];
- tmp[1] = src[3] * src[6];
- tmp[2] = src[1] * src[7];
- tmp[3] = src[3] * src[5];
- tmp[4] = src[1] * src[6];
- tmp[5] = src[2] * src[5];
- tmp[6] = src[0] * src[7];
- tmp[7] = src[3] * src[4];
- tmp[8] = src[0] * src[6];
- tmp[9] = src[2] * src[4];
- tmp[10] = src[0] * src[5];
- tmp[11] = src[1] * src[4];
- // calculate second 8 elements (cofactors)
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- 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]);
- // calculate determinant
- det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3];
- // calculate matrix inverse
- float invdet = 1 / det;
- for (int j = 0; j < 16; ++j)
- {
- m16[j] *= invdet;
- }
- }
- return det;
- }
- void matrix_t::RotationAxis(const vec_t& axis, float angle)
- {
- float length2 = axis.LengthSq();
- if (length2 < FLT_EPSILON)
- {
- SetToIdentity();
- return;
- }
- vec_t n = axis * (1.f / sqrtf(length2));
- float s = sinf(angle);
- float c = cosf(angle);
- float k = 1.f - c;
- float xx = n.x * n.x * k + c;
- float yy = n.y * n.y * k + c;
- float zz = n.z * n.z * k + c;
- float xy = n.x * n.y * k;
- float yz = n.y * n.z * k;
- float zx = n.z * n.x * k;
- float xs = n.x * s;
- float ys = n.y * s;
- float zs = n.z * s;
- m[0][0] = xx;
- m[0][1] = xy + zs;
- m[0][2] = zx - ys;
- m[0][3] = 0.f;
- m[1][0] = xy - zs;
- m[1][1] = yy;
- m[1][2] = yz + xs;
- m[1][3] = 0.f;
- m[2][0] = zx + ys;
- m[2][1] = yz - xs;
- m[2][2] = zz;
- m[2][3] = 0.f;
- m[3][0] = 0.f;
- m[3][1] = 0.f;
- m[3][2] = 0.f;
- m[3][3] = 1.f;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- enum MOVETYPE
- {
- MT_NONE,
- MT_MOVE_X,
- MT_MOVE_Y,
- MT_MOVE_Z,
- MT_MOVE_YZ,
- MT_MOVE_ZX,
- MT_MOVE_XY,
- MT_MOVE_SCREEN,
- MT_ROTATE_X,
- MT_ROTATE_Y,
- MT_ROTATE_Z,
- MT_ROTATE_SCREEN,
- MT_SCALE_X,
- MT_SCALE_Y,
- MT_SCALE_Z,
- MT_SCALE_XYZ
- };
- static bool IsTranslateType(int type)
- {
- return type >= MT_MOVE_X && type <= MT_MOVE_SCREEN;
- }
- static bool IsRotateType(int type)
- {
- return type >= MT_ROTATE_X && type <= MT_ROTATE_SCREEN;
- }
- static bool IsScaleType(int type)
- {
- return type >= MT_SCALE_X && type <= MT_SCALE_XYZ;
- }
- // Matches MT_MOVE_AB order
- static const OPERATION TRANSLATE_PLANS[3] = { TRANSLATE_Y | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Y };
- Style::Style()
- {
- // default values
- TranslationLineThickness = 3.0f;
- TranslationLineArrowSize = 6.0f;
- RotationLineThickness = 2.0f;
- RotationOuterLineThickness = 3.0f;
- ScaleLineThickness = 3.0f;
- ScaleLineCircleSize = 6.0f;
- HatchedAxisLineThickness = 6.0f;
- CenterCircleSize = 6.0f;
- // initialize default colors
- Colors[DIRECTION_X] = ImVec4(0.666f, 0.000f, 0.000f, 1.000f);
- Colors[DIRECTION_Y] = ImVec4(0.000f, 0.666f, 0.000f, 1.000f);
- Colors[DIRECTION_Z] = ImVec4(0.000f, 0.000f, 0.666f, 1.000f);
- Colors[PLANE_X] = ImVec4(0.666f, 0.000f, 0.000f, 0.380f);
- Colors[PLANE_Y] = ImVec4(0.000f, 0.666f, 0.000f, 0.380f);
- Colors[PLANE_Z] = ImVec4(0.000f, 0.000f, 0.666f, 0.380f);
- Colors[SELECTION] = ImVec4(1.000f, 0.500f, 0.062f, 0.541f);
- Colors[INACTIVE] = ImVec4(0.600f, 0.600f, 0.600f, 0.600f);
- Colors[TRANSLATION_LINE] = ImVec4(0.666f, 0.666f, 0.666f, 0.666f);
- Colors[SCALE_LINE] = ImVec4(0.250f, 0.250f, 0.250f, 1.000f);
- Colors[ROTATION_USING_BORDER] = ImVec4(1.000f, 0.500f, 0.062f, 1.000f);
- Colors[ROTATION_USING_FILL] = ImVec4(1.000f, 0.500f, 0.062f, 0.500f);
- Colors[HATCHED_AXIS_LINES] = ImVec4(0.000f, 0.000f, 0.000f, 0.500f);
- Colors[TEXT] = ImVec4(1.000f, 1.000f, 1.000f, 1.000f);
- Colors[TEXT_SHADOW] = ImVec4(0.000f, 0.000f, 0.000f, 1.000f);
- }
- struct Context
- {
- Context() : mbUsing(false), mbEnable(true), mbUsingBounds(false)
- {
- }
- ImDrawList* mDrawList;
- Style mStyle;
- MODE mMode;
- matrix_t mViewMat;
- matrix_t mProjectionMat;
- matrix_t mModel;
- matrix_t mModelLocal; // orthonormalized model
- matrix_t mModelInverse;
- matrix_t mModelSource;
- matrix_t mModelSourceInverse;
- matrix_t mMVP;
- matrix_t mMVPLocal; // MVP with full model matrix whereas mMVP's model matrix might only be translation in case of World space edition
- matrix_t mViewProjection;
- vec_t mModelScaleOrigin;
- vec_t mCameraEye;
- vec_t mCameraRight;
- vec_t mCameraDir;
- vec_t mCameraUp;
- vec_t mRayOrigin;
- vec_t mRayVector;
- float mRadiusSquareCenter;
- ImVec2 mScreenSquareCenter;
- ImVec2 mScreenSquareMin;
- ImVec2 mScreenSquareMax;
- float mScreenFactor;
- vec_t mRelativeOrigin;
- bool mbUsing;
- bool mbEnable;
- bool mbMouseOver;
- bool mReversed; // reversed projection matrix
- // translation
- vec_t mTranslationPlan;
- vec_t mTranslationPlanOrigin;
- vec_t mMatrixOrigin;
- vec_t mTranslationLastDelta;
- // rotation
- vec_t mRotationVectorSource;
- float mRotationAngle;
- float mRotationAngleOrigin;
- //vec_t mWorldToLocalAxis;
- // scale
- vec_t mScale;
- vec_t mScaleValueOrigin;
- vec_t mScaleLast;
- float mSaveMousePosx;
- // save axis factor when using gizmo
- bool mBelowAxisLimit[3];
- bool mBelowPlaneLimit[3];
- float mAxisFactor[3];
- float mAxisLimit=0.0025f;
- float mPlaneLimit=0.02f;
- // bounds stretching
- vec_t mBoundsPivot;
- vec_t mBoundsAnchor;
- vec_t mBoundsPlan;
- vec_t mBoundsLocalPivot;
- int mBoundsBestAxis;
- int mBoundsAxis[2];
- bool mbUsingBounds;
- matrix_t mBoundsMatrix;
- //
- int mCurrentOperation;
- float mX = 0.f;
- float mY = 0.f;
- float mWidth = 0.f;
- float mHeight = 0.f;
- float mXMax = 0.f;
- float mYMax = 0.f;
- float mDisplayRatio = 1.f;
- bool mIsOrthographic = false;
- int mActualID = -1;
- int mEditingID = -1;
- OPERATION mOperation = OPERATION(-1);
- bool mAllowAxisFlip = true;
- float mGizmoSizeClipSpace = 0.1f;
- };
- static Context gContext;
- 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) };
- static const char* translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f",
- "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f",
- "X : %5.3f Y : %5.3f Z : %5.3f" };
- static const char* scaleInfoMask[] = { "X : %5.2f", "Y : %5.2f", "Z : %5.2f", "XYZ : %5.2f" };
- 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" };
- 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 };
- static const float quadMin = 0.5f;
- static const float quadMax = 0.8f;
- static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin };
- static const int halfCircleSegmentCount = 64;
- static const float snapTension = 0.5f;
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion);
- static int GetRotateType(OPERATION op);
- static int GetScaleType(OPERATION op);
- Style& GetStyle()
- {
- return gContext.mStyle;
- }
- static ImU32 GetColorU32(int idx)
- {
- IM_ASSERT(idx < COLOR::COUNT);
- return ImGui::ColorConvertFloat4ToU32(gContext.mStyle.Colors[idx]);
- }
- 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))
- {
- vec_t trans;
- trans.TransformPoint(worldPos, mat);
- trans *= 0.5f / trans.w;
- trans += makeVect(0.5f, 0.5f);
- trans.y = 1.f - trans.y;
- trans.x *= size.x;
- trans.y *= size.y;
- trans.x += position.x;
- trans.y += position.y;
- return ImVec2(trans.x, trans.y);
- }
- static void ComputeCameraRay(vec_t& rayOrigin, vec_t& rayDir, ImVec2 position = ImVec2(gContext.mX, gContext.mY), ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))
- {
- ImGuiIO& io = ImGui::GetIO();
- matrix_t mViewProjInverse;
- mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat);
- const float mox = ((io.MousePos.x - position.x) / size.x) * 2.f - 1.f;
- const float moy = (1.f - ((io.MousePos.y - position.y) / size.y)) * 2.f - 1.f;
- const float zNear = gContext.mReversed ? (1.f - FLT_EPSILON) : 0.f;
- const float zFar = gContext.mReversed ? 0.f : (1.f - FLT_EPSILON);
- rayOrigin.Transform(makeVect(mox, moy, zNear, 1.f), mViewProjInverse);
- rayOrigin *= 1.f / rayOrigin.w;
- vec_t rayEnd;
- rayEnd.Transform(makeVect(mox, moy, zFar, 1.f), mViewProjInverse);
- rayEnd *= 1.f / rayEnd.w;
- rayDir = Normalized(rayEnd - rayOrigin);
- }
- static float GetSegmentLengthClipSpace(const vec_t& start, const vec_t& end, const bool localCoordinates = false)
- {
- vec_t startOfSegment = start;
- const matrix_t& mvp = localCoordinates ? gContext.mMVPLocal : gContext.mMVP;
- startOfSegment.TransformPoint(mvp);
- if (fabsf(startOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction
- {
- startOfSegment *= 1.f / startOfSegment.w;
- }
- vec_t endOfSegment = end;
- endOfSegment.TransformPoint(mvp);
- if (fabsf(endOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction
- {
- endOfSegment *= 1.f / endOfSegment.w;
- }
- vec_t clipSpaceAxis = endOfSegment - startOfSegment;
- if (gContext.mDisplayRatio < 1.0)
- clipSpaceAxis.x *= gContext.mDisplayRatio;
- else
- clipSpaceAxis.y /= gContext.mDisplayRatio;
- float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x * clipSpaceAxis.x + clipSpaceAxis.y * clipSpaceAxis.y);
- return segmentLengthInClipSpace;
- }
- static float GetParallelogram(const vec_t& ptO, const vec_t& ptA, const vec_t& ptB)
- {
- vec_t pts[] = { ptO, ptA, ptB };
- for (unsigned int i = 0; i < 3; i++)
- {
- pts[i].TransformPoint(gContext.mMVP);
- if (fabsf(pts[i].w) > FLT_EPSILON) // check for axis aligned with camera direction
- {
- pts[i] *= 1.f / pts[i].w;
- }
- }
- vec_t segA = pts[1] - pts[0];
- vec_t segB = pts[2] - pts[0];
- segA.y /= gContext.mDisplayRatio;
- segB.y /= gContext.mDisplayRatio;
- vec_t segAOrtho = makeVect(-segA.y, segA.x);
- segAOrtho.Normalize();
- float dt = segAOrtho.Dot3(segB);
- float surface = sqrtf(segA.x * segA.x + segA.y * segA.y) * fabsf(dt);
- return surface;
- }
- inline vec_t PointOnSegment(const vec_t& point, const vec_t& vertPos1, const vec_t& vertPos2)
- {
- vec_t c = point - vertPos1;
- vec_t V;
- V.Normalize(vertPos2 - vertPos1);
- float d = (vertPos2 - vertPos1).Length();
- float t = V.Dot3(c);
- if (t < 0.f)
- {
- return vertPos1;
- }
- if (t > d)
- {
- return vertPos2;
- }
- return vertPos1 + V * t;
- }
- static float IntersectRayPlane(const vec_t& rOrigin, const vec_t& rVector, const vec_t& plan)
- {
- const float numer = plan.Dot3(rOrigin) - plan.w;
- const float denom = plan.Dot3(rVector);
- if (fabsf(denom) < FLT_EPSILON) // normal is orthogonal to vector, cant intersect
- {
- return -1.0f;
- }
- return -(numer / denom);
- }
- static float DistanceToPlane(const vec_t& point, const vec_t& plan)
- {
- return plan.Dot3(point) + plan.w;
- }
- static bool IsInContextRect(ImVec2 p)
- {
- return IsWithin(p.x, gContext.mX, gContext.mXMax) && IsWithin(p.y, gContext.mY, gContext.mYMax);
- }
- static bool IsHoveringWindow()
- {
- ImGuiContext& g = *ImGui::GetCurrentContext();
- ImGuiWindow* window = ImGui::FindWindowByName(gContext.mDrawList->_OwnerName);
- if (g.HoveredWindow == window) // Mouse hovering drawlist window
- return true;
- if (g.HoveredWindow != NULL) // Any other window is hovered
- return false;
- if (ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max, false)) // Hovering drawlist window rect, while no other window is hovered (for _NoInputs windows)
- return true;
- return false;
- }
- void SetRect(float x, float y, float width, float height)
- {
- gContext.mX = x;
- gContext.mY = y;
- gContext.mWidth = width;
- gContext.mHeight = height;
- gContext.mXMax = gContext.mX + gContext.mWidth;
- gContext.mYMax = gContext.mY + gContext.mXMax;
- gContext.mDisplayRatio = width / height;
- }
- void SetOrthographic(bool isOrthographic)
- {
- gContext.mIsOrthographic = isOrthographic;
- }
- void SetDrawlist(ImDrawList* drawlist)
- {
- gContext.mDrawList = drawlist ? drawlist : ImGui::GetWindowDrawList();
- }
- void SetImGuiContext(ImGuiContext* ctx)
- {
- ImGui::SetCurrentContext(ctx);
- }
- void BeginFrame()
- {
- const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus;
- #ifdef IMGUI_HAS_VIEWPORT
- ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size);
- ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos);
- #else
- ImGuiIO& io = ImGui::GetIO();
- ImGui::SetNextWindowSize(io.DisplaySize);
- ImGui::SetNextWindowPos(ImVec2(0, 0));
- #endif
- ImGui::PushStyleColor(ImGuiCol_WindowBg, 0);
- ImGui::PushStyleColor(ImGuiCol_Border, 0);
- ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
- ImGui::Begin("gizmo", NULL, flags);
- gContext.mDrawList = ImGui::GetWindowDrawList();
- ImGui::End();
- ImGui::PopStyleVar();
- ImGui::PopStyleColor(2);
- }
- bool IsUsing()
- {
- return (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID)) || gContext.mbUsingBounds;
- }
- bool IsUsingAny()
- {
- return gContext.mbUsing || gContext.mbUsingBounds;
- }
- bool IsOver()
- {
- return (Intersects(gContext.mOperation, TRANSLATE) && GetMoveType(gContext.mOperation, NULL) != MT_NONE) ||
- (Intersects(gContext.mOperation, ROTATE) && GetRotateType(gContext.mOperation) != MT_NONE) ||
- (Intersects(gContext.mOperation, SCALE) && GetScaleType(gContext.mOperation) != MT_NONE) || IsUsing();
- }
- bool IsOver(OPERATION op)
- {
- if(IsUsing())
- {
- return true;
- }
- if(Intersects(op, SCALE) && GetScaleType(op) != MT_NONE)
- {
- return true;
- }
- if(Intersects(op, ROTATE) && GetRotateType(op) != MT_NONE)
- {
- return true;
- }
- if(Intersects(op, TRANSLATE) && GetMoveType(op, NULL) != MT_NONE)
- {
- return true;
- }
- return false;
- }
- void Enable(bool enable)
- {
- gContext.mbEnable = enable;
- if (!enable)
- {
- gContext.mbUsing = false;
- gContext.mbUsingBounds = false;
- }
- }
- static void ComputeContext(const float* view, const float* projection, float* matrix, MODE mode)
- {
- gContext.mMode = mode;
- gContext.mViewMat = *(matrix_t*)view;
- gContext.mProjectionMat = *(matrix_t*)projection;
- gContext.mbMouseOver = IsHoveringWindow();
- gContext.mModelLocal = *(matrix_t*)matrix;
- gContext.mModelLocal.OrthoNormalize();
- if (mode == LOCAL)
- {
- gContext.mModel = gContext.mModelLocal;
- }
- else
- {
- gContext.mModel.Translation(((matrix_t*)matrix)->v.position);
- }
- gContext.mModelSource = *(matrix_t*)matrix;
- gContext.mModelScaleOrigin.Set(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
- gContext.mModelInverse.Inverse(gContext.mModel);
- gContext.mModelSourceInverse.Inverse(gContext.mModelSource);
- gContext.mViewProjection = gContext.mViewMat * gContext.mProjectionMat;
- gContext.mMVP = gContext.mModel * gContext.mViewProjection;
- gContext.mMVPLocal = gContext.mModelLocal * gContext.mViewProjection;
- matrix_t viewInverse;
- viewInverse.Inverse(gContext.mViewMat);
- gContext.mCameraDir = viewInverse.v.dir;
- gContext.mCameraEye = viewInverse.v.position;
- gContext.mCameraRight = viewInverse.v.right;
- gContext.mCameraUp = viewInverse.v.up;
- // projection reverse
- vec_t nearPos, farPos;
- nearPos.Transform(makeVect(0, 0, 1.f, 1.f), gContext.mProjectionMat);
- farPos.Transform(makeVect(0, 0, 2.f, 1.f), gContext.mProjectionMat);
- gContext.mReversed = (nearPos.z/nearPos.w) > (farPos.z / farPos.w);
- // compute scale from the size of camera right vector projected on screen at the matrix position
- vec_t pointRight = viewInverse.v.right;
- pointRight.TransformPoint(gContext.mViewProjection);
- gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / (pointRight.x / pointRight.w - gContext.mMVP.v.position.x / gContext.mMVP.v.position.w);
- vec_t rightViewInverse = viewInverse.v.right;
- rightViewInverse.TransformVector(gContext.mModelInverse);
- float rightLength = GetSegmentLengthClipSpace(makeVect(0.f, 0.f), rightViewInverse);
- gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / rightLength;
- ImVec2 centerSSpace = worldToPos(makeVect(0.f, 0.f), gContext.mMVP);
- gContext.mScreenSquareCenter = centerSSpace;
- gContext.mScreenSquareMin = ImVec2(centerSSpace.x - 10.f, centerSSpace.y - 10.f);
- gContext.mScreenSquareMax = ImVec2(centerSSpace.x + 10.f, centerSSpace.y + 10.f);
- ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector);
- }
- static void ComputeColors(ImU32* colors, int type, OPERATION operation)
- {
- if (gContext.mbEnable)
- {
- ImU32 selectionColor = GetColorU32(SELECTION);
- switch (operation)
- {
- case TRANSLATE:
- colors[0] = (type == MT_MOVE_SCREEN) ? selectionColor : IM_COL32_WHITE;
- for (int i = 0; i < 3; i++)
- {
- colors[i + 1] = (type == (int)(MT_MOVE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
- colors[i + 4] = (type == (int)(MT_MOVE_YZ + i)) ? selectionColor : GetColorU32(PLANE_X + i);
- colors[i + 4] = (type == MT_MOVE_SCREEN) ? selectionColor : colors[i + 4];
- }
- break;
- case ROTATE:
- colors[0] = (type == MT_ROTATE_SCREEN) ? selectionColor : IM_COL32_WHITE;
- for (int i = 0; i < 3; i++)
- {
- colors[i + 1] = (type == (int)(MT_ROTATE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
- }
- break;
- case SCALEU:
- case SCALE:
- colors[0] = (type == MT_SCALE_XYZ) ? selectionColor : IM_COL32_WHITE;
- for (int i = 0; i < 3; i++)
- {
- colors[i + 1] = (type == (int)(MT_SCALE_X + i)) ? selectionColor : GetColorU32(DIRECTION_X + i);
- }
- break;
- // note: this internal function is only called with three possible values for operation
- default:
- break;
- }
- }
- else
- {
- ImU32 inactiveColor = GetColorU32(INACTIVE);
- for (int i = 0; i < 7; i++)
- {
- colors[i] = inactiveColor;
- }
- }
- }
- static void ComputeTripodAxisAndVisibility(const int axisIndex, vec_t& dirAxis, vec_t& dirPlaneX, vec_t& dirPlaneY, bool& belowAxisLimit, bool& belowPlaneLimit, const bool localCoordinates = false)
- {
- dirAxis = directionUnary[axisIndex];
- dirPlaneX = directionUnary[(axisIndex + 1) % 3];
- dirPlaneY = directionUnary[(axisIndex + 2) % 3];
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
- {
- // when using, use stored factors so the gizmo doesn't flip when we translate
- belowAxisLimit = gContext.mBelowAxisLimit[axisIndex];
- belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex];
- dirAxis *= gContext.mAxisFactor[axisIndex];
- dirPlaneX *= gContext.mAxisFactor[(axisIndex + 1) % 3];
- dirPlaneY *= gContext.mAxisFactor[(axisIndex + 2) % 3];
- }
- else
- {
- // new method
- float lenDir = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis, localCoordinates);
- float lenDirMinus = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirAxis, localCoordinates);
- float lenDirPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneX, localCoordinates);
- float lenDirMinusPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneX, localCoordinates);
- float lenDirPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneY, localCoordinates);
- float lenDirMinusPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirPlaneY, localCoordinates);
- // For readability
- bool & allowFlip = gContext.mAllowAxisFlip;
- float mulAxis = (allowFlip && lenDir < lenDirMinus&& fabsf(lenDir - lenDirMinus) > FLT_EPSILON) ? -1.f : 1.f;
- float mulAxisX = (allowFlip && lenDirPlaneX < lenDirMinusPlaneX&& fabsf(lenDirPlaneX - lenDirMinusPlaneX) > FLT_EPSILON) ? -1.f : 1.f;
- float mulAxisY = (allowFlip && lenDirPlaneY < lenDirMinusPlaneY&& fabsf(lenDirPlaneY - lenDirMinusPlaneY) > FLT_EPSILON) ? -1.f : 1.f;
- dirAxis *= mulAxis;
- dirPlaneX *= mulAxisX;
- dirPlaneY *= mulAxisY;
- // for axis
- float axisLengthInClipSpace = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis * gContext.mScreenFactor, localCoordinates);
- float paraSurf = GetParallelogram(makeVect(0.f, 0.f, 0.f), dirPlaneX * gContext.mScreenFactor, dirPlaneY * gContext.mScreenFactor);
- belowPlaneLimit = (paraSurf > gContext.mAxisLimit);
- belowAxisLimit = (axisLengthInClipSpace > gContext.mPlaneLimit);
- // and store values
- gContext.mAxisFactor[axisIndex] = mulAxis;
- gContext.mAxisFactor[(axisIndex + 1) % 3] = mulAxisX;
- gContext.mAxisFactor[(axisIndex + 2) % 3] = mulAxisY;
- gContext.mBelowAxisLimit[axisIndex] = belowAxisLimit;
- gContext.mBelowPlaneLimit[axisIndex] = belowPlaneLimit;
- }
- }
- static void ComputeSnap(float* value, float snap)
- {
- if (snap <= FLT_EPSILON)
- {
- return;
- }
- float modulo = fmodf(*value, snap);
- float moduloRatio = fabsf(modulo) / snap;
- if (moduloRatio < snapTension)
- {
- *value -= modulo;
- }
- else if (moduloRatio > (1.f - snapTension))
- {
- *value = *value - modulo + snap * ((*value < 0.f) ? -1.f : 1.f);
- }
- }
- static void ComputeSnap(vec_t& value, const float* snap)
- {
- for (int i = 0; i < 3; i++)
- {
- ComputeSnap(&value[i], snap[i]);
- }
- }
- static float ComputeAngleOnPlan()
- {
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
- vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position);
- vec_t perpendicularVector;
- perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);
- perpendicularVector.Normalize();
- float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -1.f, 1.f);
- float angle = acosf(acosAngle);
- angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;
- return angle;
- }
- static void DrawRotationGizmo(OPERATION op, int type)
- {
- if(!Intersects(op, ROTATE))
- {
- return;
- }
- ImDrawList* drawList = gContext.mDrawList;
- // colors
- ImU32 colors[7];
- ComputeColors(colors, type, ROTATE);
- vec_t cameraToModelNormalized;
- if (gContext.mIsOrthographic)
- {
- matrix_t viewInverse;
- viewInverse.Inverse(*(matrix_t*)&gContext.mViewMat);
- cameraToModelNormalized = -viewInverse.v.dir;
- }
- else
- {
- cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
- }
- cameraToModelNormalized.TransformVector(gContext.mModelInverse);
- gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight;
- bool hasRSC = Intersects(op, ROTATE_SCREEN);
- for (int axis = 0; axis < 3; axis++)
- {
- if(!Intersects(op, static_cast<OPERATION>(ROTATE_Z >> axis)))
- {
- continue;
- }
- const bool usingAxis = (gContext.mbUsing && type == MT_ROTATE_Z - axis);
- const int circleMul = (hasRSC && !usingAxis ) ? 1 : 2;
- ImVec2* circlePos = (ImVec2*)alloca(sizeof(ImVec2) * (circleMul * halfCircleSegmentCount + 1));
- float angleStart = atan2f(cameraToModelNormalized[(4 - axis) % 3], cameraToModelNormalized[(3 - axis) % 3]) + ZPI * 0.5f;
- for (int i = 0; i < circleMul * halfCircleSegmentCount + 1; i++)
- {
- float ng = angleStart + (float)circleMul * ZPI * ((float)i / (float)(circleMul * halfCircleSegmentCount));
- vec_t axisPos = makeVect(cosf(ng), sinf(ng), 0.f);
- vec_t pos = makeVect(axisPos[axis], axisPos[(axis + 1) % 3], axisPos[(axis + 2) % 3]) * gContext.mScreenFactor * rotationDisplayFactor;
- circlePos[i] = worldToPos(pos, gContext.mMVP);
- }
- if (!gContext.mbUsing || usingAxis)
- {
- drawList->AddPolyline(circlePos, circleMul* halfCircleSegmentCount + 1, colors[3 - axis], false, gContext.mStyle.RotationLineThickness);
- }
- float radiusAxis = sqrtf((ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0])));
- if (radiusAxis > gContext.mRadiusSquareCenter)
- {
- gContext.mRadiusSquareCenter = radiusAxis;
- }
- }
- if(hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN))
- {
- drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, gContext.mStyle.RotationOuterLineThickness);
- }
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(type))
- {
- ImVec2 circlePos[halfCircleSegmentCount + 1];
- circlePos[0] = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
- for (unsigned int i = 1; i < halfCircleSegmentCount + 1; i++)
- {
- float ng = gContext.mRotationAngle * ((float)(i - 1) / (float)(halfCircleSegmentCount - 1));
- matrix_t rotateVectorMatrix;
- rotateVectorMatrix.RotationAxis(gContext.mTranslationPlan, ng);
- vec_t pos;
- pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix);
- pos *= gContext.mScreenFactor * rotationDisplayFactor;
- circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);
- }
- drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount + 1, GetColorU32(ROTATION_USING_FILL));
- drawList->AddPolyline(circlePos, halfCircleSegmentCount + 1, GetColorU32(ROTATION_USING_BORDER), true, gContext.mStyle.RotationLineThickness);
- ImVec2 destinationPosOnScreen = circlePos[1];
- char tmps[512];
- ImFormatString(tmps, sizeof(tmps), rotationInfoMask[type - MT_ROTATE_X], (gContext.mRotationAngle / ZPI) * 180.f, gContext.mRotationAngle);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
- }
- }
- static void DrawHatchedAxis(const vec_t& axis)
- {
- if (gContext.mStyle.HatchedAxisLineThickness <= 0.0f)
- {
- return;
- }
- for (int j = 1; j < 10; j++)
- {
- ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, gContext.mMVP);
- ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, gContext.mMVP);
- gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, GetColorU32(HATCHED_AXIS_LINES), gContext.mStyle.HatchedAxisLineThickness);
- }
- }
- static void DrawScaleGizmo(OPERATION op, int type)
- {
- ImDrawList* drawList = gContext.mDrawList;
- if(!Intersects(op, SCALE))
- {
- return;
- }
- // colors
- ImU32 colors[7];
- ComputeColors(colors, type, SCALE);
- // draw
- vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
- {
- scaleDisplay = gContext.mScale;
- }
- for (int i = 0; i < 3; i++)
- {
- if(!Intersects(op, static_cast<OPERATION>(SCALE_X << i)))
- {
- continue;
- }
- const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);
- if (!gContext.mbUsing || usingAxis)
- {
- vec_t dirPlaneX, dirPlaneY, dirAxis;
- bool belowAxisLimit, belowPlaneLimit;
- ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
- // draw axis
- if (belowAxisLimit)
- {
- bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));
- float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
- ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);
- ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
- ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVP);
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
- {
- ImU32 scaleLineColor = GetColorU32(SCALE_LINE);
- drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, scaleLineColor, gContext.mStyle.ScaleLineThickness);
- drawList->AddCircleFilled(worldDirSSpaceNoScale, gContext.mStyle.ScaleLineCircleSize, scaleLineColor);
- }
- if (!hasTranslateOnAxis || gContext.mbUsing)
- {
- drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.ScaleLineThickness);
- }
- drawList->AddCircleFilled(worldDirSSpace, gContext.mStyle.ScaleLineCircleSize, colors[i + 1]);
- if (gContext.mAxisFactor[i] < 0.f)
- {
- DrawHatchedAxis(dirAxis * scaleDisplay[i]);
- }
- }
- }
- }
- // draw screen cirle
- drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32);
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type))
- {
- //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
- ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
- /*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
- dif.Normalize();
- dif *= 5.f;
- drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
- drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
- drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
- */
- char tmps[512];
- //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
- int componentInfoIndex = (type - MT_SCALE_X) * 3;
- ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
- }
- }
- static void DrawScaleUniveralGizmo(OPERATION op, int type)
- {
- ImDrawList* drawList = gContext.mDrawList;
- if (!Intersects(op, SCALEU))
- {
- return;
- }
- // colors
- ImU32 colors[7];
- ComputeColors(colors, type, SCALEU);
- // draw
- vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
- {
- scaleDisplay = gContext.mScale;
- }
- for (int i = 0; i < 3; i++)
- {
- if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i)))
- {
- continue;
- }
- const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);
- if (!gContext.mbUsing || usingAxis)
- {
- vec_t dirPlaneX, dirPlaneY, dirAxis;
- bool belowAxisLimit, belowPlaneLimit;
- ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
- // draw axis
- if (belowAxisLimit)
- {
- bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));
- float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
- //ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
- //ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
- ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, gContext.mMVPLocal);
- #if 0
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
- {
- drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, IM_COL32(0x40, 0x40, 0x40, 0xFF), 3.f);
- drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, IM_COL32(0x40, 0x40, 0x40, 0xFF));
- }
- /*
- if (!hasTranslateOnAxis || gContext.mbUsing)
- {
- drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
- }
- */
- #endif
- drawList->AddCircleFilled(worldDirSSpace, 12.f, colors[i + 1]);
- }
- }
- }
- // draw screen cirle
- drawList->AddCircle(gContext.mScreenSquareCenter, 20.f, colors[0], 32, gContext.mStyle.CenterCircleSize);
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(type))
- {
- //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
- ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
- /*vec_t dif(destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y);
- dif.Normalize();
- dif *= 5.f;
- drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
- drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
- drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
- */
- char tmps[512];
- //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
- int componentInfoIndex = (type - MT_SCALE_X) * 3;
- ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], scaleDisplay[translationInfoIndex[componentInfoIndex]]);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
- }
- }
- static void DrawTranslationGizmo(OPERATION op, int type)
- {
- ImDrawList* drawList = gContext.mDrawList;
- if (!drawList)
- {
- return;
- }
- if(!Intersects(op, TRANSLATE))
- {
- return;
- }
- // colors
- ImU32 colors[7];
- ComputeColors(colors, type, TRANSLATE);
- const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
- // draw
- bool belowAxisLimit = false;
- bool belowPlaneLimit = false;
- for (int i = 0; i < 3; ++i)
- {
- vec_t dirPlaneX, dirPlaneY, dirAxis;
- ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
- if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_X + i))
- {
- // draw axis
- if (belowAxisLimit && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i)))
- {
- ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);
- ImVec2 worldDirSSpace = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP);
- drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], gContext.mStyle.TranslationLineThickness);
- // Arrow head begin
- ImVec2 dir(origin - worldDirSSpace);
- float d = sqrtf(ImLengthSqr(dir));
- dir /= d; // Normalize
- dir *= gContext.mStyle.TranslationLineArrowSize;
- ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector
- ImVec2 a(worldDirSSpace + dir);
- drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]);
- // Arrow head end
- if (gContext.mAxisFactor[i] < 0.f)
- {
- DrawHatchedAxis(dirAxis);
- }
- }
- }
- // draw plane
- if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_YZ + i))
- {
- if (belowPlaneLimit && Contains(op, TRANSLATE_PLANS[i]))
- {
- ImVec2 screenQuadPts[4];
- for (int j = 0; j < 4; ++j)
- {
- vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor;
- screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);
- }
- drawList->AddPolyline(screenQuadPts, 4, GetColorU32(DIRECTION_X + i), true, 1.0f);
- drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]);
- }
- }
- }
- drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, colors[0], 32);
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(type))
- {
- ImU32 translationLineColor = GetColorU32(TRANSLATION_LINE);
- ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
- ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
- vec_t dif = { destinationPosOnScreen.x - sourcePosOnScreen.x, destinationPosOnScreen.y - sourcePosOnScreen.y, 0.f, 0.f };
- dif.Normalize();
- dif *= 5.f;
- drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);
- drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);
- drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), translationLineColor, 2.f);
- char tmps[512];
- vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;
- int componentInfoIndex = (type - MT_MOVE_X) * 3;
- ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MT_MOVE_X], deltaInfo[translationInfoIndex[componentInfoIndex]], deltaInfo[translationInfoIndex[componentInfoIndex + 1]], deltaInfo[translationInfoIndex[componentInfoIndex + 2]]);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
- }
- }
- static bool CanActivate()
- {
- if (ImGui::IsMouseClicked(0) /*&& !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive()*/)
- {
- return true;
- }
- return false;
- }
- static void HandleAndDrawLocalBounds(const float* bounds, matrix_t* matrix, const float* snapValues, OPERATION operation)
- {
- ImGuiIO& io = ImGui::GetIO();
- ImDrawList* drawList = gContext.mDrawList;
- // compute best projection axis
- vec_t axesWorldDirections[3];
- vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f };
- int axes[3];
- unsigned int numAxes = 1;
- axes[0] = gContext.mBoundsBestAxis;
- int bestAxis = axes[0];
- if (!gContext.mbUsingBounds)
- {
- numAxes = 0;
- float bestDot = 0.f;
- for (int i = 0; i < 3; i++)
- {
- vec_t dirPlaneNormalWorld;
- dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
- dirPlaneNormalWorld.Normalize();
- float dt = fabsf(Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld));
- if (dt >= bestDot)
- {
- bestDot = dt;
- bestAxis = i;
- bestAxisWorldDirection = dirPlaneNormalWorld;
- }
- if (dt >= 0.1f)
- {
- axes[numAxes] = i;
- axesWorldDirections[numAxes] = dirPlaneNormalWorld;
- ++numAxes;
- }
- }
- }
- if (numAxes == 0)
- {
- axes[0] = bestAxis;
- axesWorldDirections[0] = bestAxisWorldDirection;
- numAxes = 1;
- }
- else if (bestAxis != axes[0])
- {
- unsigned int bestIndex = 0;
- for (unsigned int i = 0; i < numAxes; i++)
- {
- if (axes[i] == bestAxis)
- {
- bestIndex = i;
- break;
- }
- }
- int tempAxis = axes[0];
- axes[0] = axes[bestIndex];
- axes[bestIndex] = tempAxis;
- vec_t tempDirection = axesWorldDirections[0];
- axesWorldDirections[0] = axesWorldDirections[bestIndex];
- axesWorldDirections[bestIndex] = tempDirection;
- }
- for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex)
- {
- bestAxis = axes[axisIndex];
- bestAxisWorldDirection = axesWorldDirections[axisIndex];
- // corners
- vec_t aabb[4];
- int secondAxis = (bestAxis + 1) % 3;
- int thirdAxis = (bestAxis + 2) % 3;
- for (int i = 0; i < 4; i++)
- {
- aabb[i][3] = aabb[i][bestAxis] = 0.f;
- aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
- aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
- }
- // draw bounds
- unsigned int anchorAlpha = gContext.mbEnable ? IM_COL32_BLACK : IM_COL32(0, 0, 0, 0x80);
- matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
- for (int i = 0; i < 4; i++)
- {
- ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
- ImVec2 worldBound2 = worldToPos(aabb[(i + 1) % 4], boundsMVP);
- if (!IsInContextRect(worldBound1) || !IsInContextRect(worldBound2))
- {
- continue;
- }
- float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
- int stepCount = (int)(boundDistance / 10.f);
- stepCount = min(stepCount, 1000);
- for (int j = 0; j < stepCount; j++)
- {
- float stepLength = 1.f / (float)stepCount;
- float t1 = (float)j * stepLength;
- float t2 = (float)j * stepLength + stepLength * 0.5f;
- ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
- ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
- //drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0, 0, 0, 0) + anchorAlpha, 3.f);
- drawList->AddLine(worldBoundSS1, worldBoundSS2, IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha, 2.f);
- }
- vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4]) * 0.5f;
- ImVec2 midBound = worldToPos(midPoint, boundsMVP);
- static const float AnchorBigRadius = 8.f;
- static const float AnchorSmallRadius = 6.f;
- bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius);
- bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius * AnchorBigRadius);
- int type = MT_NONE;
- vec_t gizmoHitProportion;
- if(Intersects(operation, TRANSLATE))
- {
- type = GetMoveType(operation, &gizmoHitProportion);
- }
- if(Intersects(operation, ROTATE) && type == MT_NONE)
- {
- type = GetRotateType(operation);
- }
- if(Intersects(operation, SCALE) && type == MT_NONE)
- {
- type = GetScaleType(operation);
- }
- if (type != MT_NONE)
- {
- overBigAnchor = false;
- overSmallAnchor = false;
- }
- ImU32 selectionColor = GetColorU32(SELECTION);
- unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha);
- unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (IM_COL32(0xAA, 0xAA, 0xAA, 0) + anchorAlpha);
- drawList->AddCircleFilled(worldBound1, AnchorBigRadius, IM_COL32_BLACK);
- drawList->AddCircleFilled(worldBound1, AnchorBigRadius - 1.2f, bigAnchorColor);
- drawList->AddCircleFilled(midBound, AnchorSmallRadius, IM_COL32_BLACK);
- drawList->AddCircleFilled(midBound, AnchorSmallRadius - 1.2f, smallAnchorColor);
- int oppositeIndex = (i + 2) % 4;
- // big anchor on corners
- if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate())
- {
- gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
- gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
- gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
- gContext.mBoundsBestAxis = bestAxis;
- gContext.mBoundsAxis[0] = secondAxis;
- gContext.mBoundsAxis[1] = thirdAxis;
- gContext.mBoundsLocalPivot.Set(0.f);
- gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
- gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
- gContext.mbUsingBounds = true;
- gContext.mEditingID = gContext.mActualID;
- gContext.mBoundsMatrix = gContext.mModelSource;
- }
- // small anchor on middle of segment
- if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate())
- {
- vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
- gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
- gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
- gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
- gContext.mBoundsBestAxis = bestAxis;
- int indices[] = { secondAxis , thirdAxis };
- gContext.mBoundsAxis[0] = indices[i % 2];
- gContext.mBoundsAxis[1] = -1;
- gContext.mBoundsLocalPivot.Set(0.f);
- gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
- gContext.mbUsingBounds = true;
- gContext.mEditingID = gContext.mActualID;
- gContext.mBoundsMatrix = gContext.mModelSource;
- }
- }
- if (gContext.mbUsingBounds && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID))
- {
- matrix_t scale;
- scale.SetToIdentity();
- // compute projected mouse position on plan
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
- vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
- // compute a reference and delta vectors base on mouse move
- vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
- vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
- // for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
- for (int i = 0; i < 2; i++)
- {
- int axisIndex1 = gContext.mBoundsAxis[i];
- if (axisIndex1 == -1)
- {
- continue;
- }
- float ratioAxis = 1.f;
- vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs();
- float dtAxis = axisDir.Dot(referenceVector);
- float boundSize = bounds[axisIndex1 + 3] - bounds[axisIndex1];
- if (dtAxis > FLT_EPSILON)
- {
- ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
- }
- if (snapValues)
- {
- float length = boundSize * ratioAxis;
- ComputeSnap(&length, snapValues[axisIndex1]);
- if (boundSize > FLT_EPSILON)
- {
- ratioAxis = length / boundSize;
- }
- }
- scale.component[axisIndex1] *= ratioAxis;
- }
- // transform matrix
- matrix_t preScale, postScale;
- preScale.Translation(-gContext.mBoundsLocalPivot);
- postScale.Translation(gContext.mBoundsLocalPivot);
- matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
- *matrix = res;
- // info text
- char tmps[512];
- ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
- ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z: %.2f"
- , (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
- , (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
- , (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
- );
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), GetColorU32(TEXT_SHADOW), tmps);
- drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), GetColorU32(TEXT), tmps);
- }
- if (!io.MouseDown[0]) {
- gContext.mbUsingBounds = false;
- gContext.mEditingID = -1;
- }
- if (gContext.mbUsingBounds)
- {
- break;
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- static int GetScaleType(OPERATION op)
- {
- if (gContext.mbUsing)
- {
- return MT_NONE;
- }
- ImGuiIO& io = ImGui::GetIO();
- int type = MT_NONE;
- // screen
- if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
- io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&
- Contains(op, SCALE))
- {
- type = MT_SCALE_XYZ;
- }
- // compute
- for (int i = 0; i < 3 && type == MT_NONE; i++)
- {
- if(!Intersects(op, static_cast<OPERATION>(SCALE_X << i)))
- {
- continue;
- }
- vec_t dirPlaneX, dirPlaneY, dirAxis;
- bool belowAxisLimit, belowPlaneLimit;
- ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
- dirAxis.TransformVector(gContext.mModelLocal);
- dirPlaneX.TransformVector(gContext.mModelLocal);
- dirPlaneY.TransformVector(gContext.mModelLocal);
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModelLocal.v.position, dirAxis));
- vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
- const float startOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.0f : 0.1f;
- const float endOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.4f : 1.0f;
- const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection);
- const ImVec2 axisStartOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * startOffset, gContext.mViewProjection);
- const ImVec2 axisEndOnScreen = worldToPos(gContext.mModelLocal.v.position + dirAxis * gContext.mScreenFactor * endOffset, gContext.mViewProjection);
- vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));
- if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size
- {
- type = MT_SCALE_X + i;
- }
- }
- // universal
- vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
- float dist = deltaScreen.Length();
- if (Contains(op, SCALEU) && dist >= 17.0f && dist < 23.0f)
- {
- type = MT_SCALE_XYZ;
- }
- for (int i = 0; i < 3 && type == MT_NONE; i++)
- {
- if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i)))
- {
- continue;
- }
- vec_t dirPlaneX, dirPlaneY, dirAxis;
- bool belowAxisLimit, belowPlaneLimit;
- ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);
- // draw axis
- if (belowAxisLimit)
- {
- bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));
- float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;
- //ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);
- //ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);
- ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale) * gContext.mScreenFactor, gContext.mMVPLocal);
- float distance = sqrtf(ImLengthSqr(worldDirSSpace - io.MousePos));
- if (distance < 12.f)
- {
- type = MT_SCALE_X + i;
- }
- }
- }
- return type;
- }
- static int GetRotateType(OPERATION op)
- {
- if (gContext.mbUsing)
- {
- return MT_NONE;
- }
- ImGuiIO& io = ImGui::GetIO();
- int type = MT_NONE;
- vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
- float dist = deltaScreen.Length();
- if (Intersects(op, ROTATE_SCREEN) && dist >= (gContext.mRadiusSquareCenter - 4.0f) && dist < (gContext.mRadiusSquareCenter + 4.0f))
- {
- type = MT_ROTATE_SCREEN;
- }
- const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir };
- vec_t modelViewPos;
- modelViewPos.TransformPoint(gContext.mModel.v.position, gContext.mViewMat);
- for (int i = 0; i < 3 && type == MT_NONE; i++)
- {
- if(!Intersects(op, static_cast<OPERATION>(ROTATE_X << i)))
- {
- continue;
- }
- // pickup plan
- vec_t pickupPlan = BuildPlan(gContext.mModel.v.position, planNormals[i]);
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan);
- const vec_t intersectWorldPos = gContext.mRayOrigin + gContext.mRayVector * len;
- vec_t intersectViewPos;
- intersectViewPos.TransformPoint(intersectWorldPos, gContext.mViewMat);
- if (ImAbs(modelViewPos.z) - ImAbs(intersectViewPos.z) < -FLT_EPSILON)
- {
- continue;
- }
- const vec_t localPos = intersectWorldPos - gContext.mModel.v.position;
- vec_t idealPosOnCircle = Normalized(localPos);
- idealPosOnCircle.TransformVector(gContext.mModelInverse);
- const ImVec2 idealPosOnCircleScreen = worldToPos(idealPosOnCircle * rotationDisplayFactor * gContext.mScreenFactor, gContext.mMVP);
- //gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, IM_COL32_WHITE);
- const ImVec2 distanceOnScreen = idealPosOnCircleScreen - io.MousePos;
- const float distance = makeVect(distanceOnScreen).Length();
- if (distance < 8.f) // pixel size
- {
- type = MT_ROTATE_X + i;
- }
- }
- return type;
- }
- static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion)
- {
- if(!Intersects(op, TRANSLATE) || gContext.mbUsing || !gContext.mbMouseOver)
- {
- return MT_NONE;
- }
- ImGuiIO& io = ImGui::GetIO();
- int type = MT_NONE;
- // screen
- if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&
- io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&
- Contains(op, TRANSLATE))
- {
- type = MT_MOVE_SCREEN;
- }
- const vec_t screenCoord = makeVect(io.MousePos - ImVec2(gContext.mX, gContext.mY));
- // compute
- for (int i = 0; i < 3 && type == MT_NONE; i++)
- {
- vec_t dirPlaneX, dirPlaneY, dirAxis;
- bool belowAxisLimit, belowPlaneLimit;
- ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
- dirAxis.TransformVector(gContext.mModel);
- dirPlaneX.TransformVector(gContext.mModel);
- dirPlaneY.TransformVector(gContext.mModel);
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, BuildPlan(gContext.mModel.v.position, dirAxis));
- vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;
- const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor * 0.1f, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);
- const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * gContext.mScreenFactor, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);
- vec_t closestPointOnAxis = PointOnSegment(screenCoord, makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));
- if ((closestPointOnAxis - screenCoord).Length() < 12.f && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i))) // pixel size
- {
- type = MT_MOVE_X + i;
- }
- const float dx = dirPlaneX.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
- const float dy = dirPlaneY.Dot3((posOnPlan - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor));
- if (belowPlaneLimit && dx >= quadUV[0] && dx <= quadUV[4] && dy >= quadUV[1] && dy <= quadUV[3] && Contains(op, TRANSLATE_PLANS[i]))
- {
- type = MT_MOVE_YZ + i;
- }
- if (gizmoHitProportion)
- {
- *gizmoHitProportion = makeVect(dx, dy, 0.f);
- }
- }
- return type;
- }
- static bool HandleTranslation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
- {
- if(!Intersects(op, TRANSLATE) || type != MT_NONE)
- {
- return false;
- }
- const ImGuiIO& io = ImGui::GetIO();
- const bool applyRotationLocaly = gContext.mMode == LOCAL || type == MT_MOVE_SCREEN;
- bool modified = false;
- // move
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsTranslateType(gContext.mCurrentOperation))
- {
- #if IMGUI_VERSION_NUM >= 18723
- ImGui::SetNextFrameWantCaptureMouse(true);
- #else
- ImGui::CaptureMouseFromApp();
- #endif
- const float signedLength = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
- const float len = fabsf(signedLength); // near plan
- const vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
- // compute delta
- const vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
- vec_t delta = newOrigin - gContext.mModel.v.position;
- // 1 axis constraint
- if (gContext.mCurrentOperation >= MT_MOVE_X && gContext.mCurrentOperation <= MT_MOVE_Z)
- {
- const int axisIndex = gContext.mCurrentOperation - MT_MOVE_X;
- const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex];
- const float lengthOnAxis = Dot(axisValue, delta);
- delta = axisValue * lengthOnAxis;
- }
- // snap
- if (snap)
- {
- vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin;
- if (applyRotationLocaly)
- {
- matrix_t modelSourceNormalized = gContext.mModelSource;
- modelSourceNormalized.OrthoNormalize();
- matrix_t modelSourceNormalizedInverse;
- modelSourceNormalizedInverse.Inverse(modelSourceNormalized);
- cumulativeDelta.TransformVector(modelSourceNormalizedInverse);
- ComputeSnap(cumulativeDelta, snap);
- cumulativeDelta.TransformVector(modelSourceNormalized);
- }
- else
- {
- ComputeSnap(cumulativeDelta, snap);
- }
- delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position;
- }
- if (delta != gContext.mTranslationLastDelta)
- {
- modified = true;
- }
- gContext.mTranslationLastDelta = delta;
- // compute matrix & delta
- matrix_t deltaMatrixTranslation;
- deltaMatrixTranslation.Translation(delta);
- if (deltaMatrix)
- {
- memcpy(deltaMatrix, deltaMatrixTranslation.m16, sizeof(float) * 16);
- }
- const matrix_t res = gContext.mModelSource * deltaMatrixTranslation;
- *(matrix_t*)matrix = res;
- if (!io.MouseDown[0])
- {
- gContext.mbUsing = false;
- }
- type = gContext.mCurrentOperation;
- }
- else
- {
- // find new possible way to move
- vec_t gizmoHitProportion;
- type = GetMoveType(op, &gizmoHitProportion);
- if (type != MT_NONE)
- {
- #if IMGUI_VERSION_NUM >= 18723
- ImGui::SetNextFrameWantCaptureMouse(true);
- #else
- ImGui::CaptureMouseFromApp();
- #endif
- }
- if (CanActivate() && type != MT_NONE)
- {
- gContext.mbUsing = true;
- gContext.mEditingID = gContext.mActualID;
- gContext.mCurrentOperation = type;
- vec_t movePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,
- gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,
- -gContext.mCameraDir };
- vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
- for (unsigned int i = 0; i < 3; i++)
- {
- vec_t orthoVector = Cross(movePlanNormal[i], cameraToModelNormalized);
- movePlanNormal[i].Cross(orthoVector);
- movePlanNormal[i].Normalize();
- }
- // pickup plan
- gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_MOVE_X]);
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
- gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
- gContext.mMatrixOrigin = gContext.mModel.v.position;
- gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
- }
- }
- return modified;
- }
- static bool HandleScale(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
- {
- if((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE || !gContext.mbMouseOver)
- {
- return false;
- }
- ImGuiIO& io = ImGui::GetIO();
- bool modified = false;
- if (!gContext.mbUsing)
- {
- // find new possible way to scale
- type = GetScaleType(op);
- if (type != MT_NONE)
- {
- #if IMGUI_VERSION_NUM >= 18723
- ImGui::SetNextFrameWantCaptureMouse(true);
- #else
- ImGui::CaptureMouseFromApp();
- #endif
- }
- if (CanActivate() && type != MT_NONE)
- {
- gContext.mbUsing = true;
- gContext.mEditingID = gContext.mActualID;
- gContext.mCurrentOperation = type;
- 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 };
- // pickup plan
- gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, movePlanNormal[type - MT_SCALE_X]);
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
- gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;
- gContext.mMatrixOrigin = gContext.mModel.v.position;
- gContext.mScale.Set(1.f, 1.f, 1.f);
- gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * (1.f / gContext.mScreenFactor);
- gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());
- gContext.mSaveMousePosx = io.MousePos.x;
- }
- }
- // scale
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsScaleType(gContext.mCurrentOperation))
- {
- #if IMGUI_VERSION_NUM >= 18723
- ImGui::SetNextFrameWantCaptureMouse(true);
- #else
- ImGui::CaptureMouseFromApp();
- #endif
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
- vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
- vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
- vec_t delta = newOrigin - gContext.mModelLocal.v.position;
- // 1 axis constraint
- if (gContext.mCurrentOperation >= MT_SCALE_X && gContext.mCurrentOperation <= MT_SCALE_Z)
- {
- int axisIndex = gContext.mCurrentOperation - MT_SCALE_X;
- const vec_t& axisValue = *(vec_t*)&gContext.mModelLocal.m[axisIndex];
- float lengthOnAxis = Dot(axisValue, delta);
- delta = axisValue * lengthOnAxis;
- vec_t baseVector = gContext.mTranslationPlanOrigin - gContext.mModelLocal.v.position;
- float ratio = Dot(axisValue, baseVector + delta) / Dot(axisValue, baseVector);
- gContext.mScale[axisIndex] = max(ratio, 0.001f);
- }
- else
- {
- float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;
- gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
- }
- // snap
- if (snap)
- {
- float scaleSnap[] = { snap[0], snap[0], snap[0] };
- ComputeSnap(gContext.mScale, scaleSnap);
- }
- // no 0 allowed
- for (int i = 0; i < 3; i++)
- gContext.mScale[i] = max(gContext.mScale[i], 0.001f);
- if (gContext.mScaleLast != gContext.mScale)
- {
- modified = true;
- }
- gContext.mScaleLast = gContext.mScale;
- // compute matrix & delta
- matrix_t deltaMatrixScale;
- deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin);
- matrix_t res = deltaMatrixScale * gContext.mModelLocal;
- *(matrix_t*)matrix = res;
- if (deltaMatrix)
- {
- vec_t deltaScale = gContext.mScale * gContext.mScaleValueOrigin;
- vec_t originalScaleDivider;
- originalScaleDivider.x = 1 / gContext.mModelScaleOrigin.x;
- originalScaleDivider.y = 1 / gContext.mModelScaleOrigin.y;
- originalScaleDivider.z = 1 / gContext.mModelScaleOrigin.z;
- deltaScale = deltaScale * originalScaleDivider;
- deltaMatrixScale.Scale(deltaScale);
- memcpy(deltaMatrix, deltaMatrixScale.m16, sizeof(float) * 16);
- }
- if (!io.MouseDown[0])
- {
- gContext.mbUsing = false;
- gContext.mScale.Set(1.f, 1.f, 1.f);
- }
- type = gContext.mCurrentOperation;
- }
- return modified;
- }
- static bool HandleRotation(float* matrix, float* deltaMatrix, OPERATION op, int& type, const float* snap)
- {
- if(!Intersects(op, ROTATE) || type != MT_NONE || !gContext.mbMouseOver)
- {
- return false;
- }
- ImGuiIO& io = ImGui::GetIO();
- bool applyRotationLocaly = gContext.mMode == LOCAL;
- bool modified = false;
- if (!gContext.mbUsing)
- {
- type = GetRotateType(op);
- if (type != MT_NONE)
- {
- #if IMGUI_VERSION_NUM >= 18723
- ImGui::SetNextFrameWantCaptureMouse(true);
- #else
- ImGui::CaptureMouseFromApp();
- #endif
- }
- if (type == MT_ROTATE_SCREEN)
- {
- applyRotationLocaly = true;
- }
- if (CanActivate() && type != MT_NONE)
- {
- gContext.mbUsing = true;
- gContext.mEditingID = gContext.mActualID;
- gContext.mCurrentOperation = type;
- const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir };
- // pickup plan
- if (applyRotationLocaly)
- {
- gContext.mTranslationPlan = BuildPlan(gContext.mModel.v.position, rotatePlanNormal[type - MT_ROTATE_X]);
- }
- else
- {
- gContext.mTranslationPlan = BuildPlan(gContext.mModelSource.v.position, directionUnary[type - MT_ROTATE_X]);
- }
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
- vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position;
- gContext.mRotationVectorSource = Normalized(localPos);
- gContext.mRotationAngleOrigin = ComputeAngleOnPlan();
- }
- }
- // rotation
- if (gContext.mbUsing && (gContext.mActualID == -1 || gContext.mActualID == gContext.mEditingID) && IsRotateType(gContext.mCurrentOperation))
- {
- #if IMGUI_VERSION_NUM >= 18723
- ImGui::SetNextFrameWantCaptureMouse(true);
- #else
- ImGui::CaptureMouseFromApp();
- #endif
- gContext.mRotationAngle = ComputeAngleOnPlan();
- if (snap)
- {
- float snapInRadian = snap[0] * DEG2RAD;
- ComputeSnap(&gContext.mRotationAngle, snapInRadian);
- }
- vec_t rotationAxisLocalSpace;
- rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);
- rotationAxisLocalSpace.Normalize();
- matrix_t deltaRotation;
- deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - gContext.mRotationAngleOrigin);
- if (gContext.mRotationAngle != gContext.mRotationAngleOrigin)
- {
- modified = true;
- }
- gContext.mRotationAngleOrigin = gContext.mRotationAngle;
- matrix_t scaleOrigin;
- scaleOrigin.Scale(gContext.mModelScaleOrigin);
- if (applyRotationLocaly)
- {
- *(matrix_t*)matrix = scaleOrigin * deltaRotation * gContext.mModelLocal;
- }
- else
- {
- matrix_t res = gContext.mModelSource;
- res.v.position.Set(0.f);
- *(matrix_t*)matrix = res * deltaRotation;
- ((matrix_t*)matrix)->v.position = gContext.mModelSource.v.position;
- }
- if (deltaMatrix)
- {
- *(matrix_t*)deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel;
- }
- if (!io.MouseDown[0])
- {
- gContext.mbUsing = false;
- gContext.mEditingID = -1;
- }
- type = gContext.mCurrentOperation;
- }
- return modified;
- }
- void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale)
- {
- matrix_t mat = *(matrix_t*)matrix;
- scale[0] = mat.v.right.Length();
- scale[1] = mat.v.up.Length();
- scale[2] = mat.v.dir.Length();
- mat.OrthoNormalize();
- rotation[0] = RAD2DEG * atan2f(mat.m[1][2], mat.m[2][2]);
- 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]));
- rotation[2] = RAD2DEG * atan2f(mat.m[0][1], mat.m[0][0]);
- translation[0] = mat.v.position.x;
- translation[1] = mat.v.position.y;
- translation[2] = mat.v.position.z;
- }
- void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix)
- {
- matrix_t& mat = *(matrix_t*)matrix;
- matrix_t rot[3];
- for (int i = 0; i < 3; i++)
- {
- rot[i].RotationAxis(directionUnary[i], rotation[i] * DEG2RAD);
- }
- mat = rot[0] * rot[1] * rot[2];
- float validScale[3];
- for (int i = 0; i < 3; i++)
- {
- if (fabsf(scale[i]) < FLT_EPSILON)
- {
- validScale[i] = 0.001f;
- }
- else
- {
- validScale[i] = scale[i];
- }
- }
- mat.v.right *= validScale[0];
- mat.v.up *= validScale[1];
- mat.v.dir *= validScale[2];
- mat.v.position.Set(translation[0], translation[1], translation[2], 1.f);
- }
- void SetID(int id)
- {
- gContext.mActualID = id;
- }
- void AllowAxisFlip(bool value)
- {
- gContext.mAllowAxisFlip = value;
- }
- void SetAxisLimit(float value)
- {
- gContext.mAxisLimit=value;
- }
- void SetPlaneLimit(float value)
- {
- gContext.mPlaneLimit = value;
- }
- 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)
- {
- // Scale is always local or matrix will be skewed when applying world scale or oriented matrix
- ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode);
- // set delta to identity
- if (deltaMatrix)
- {
- ((matrix_t*)deltaMatrix)->SetToIdentity();
- }
- // behind camera
- vec_t camSpacePosition;
- camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP);
- if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f && !gContext.mbUsing)
- {
- return false;
- }
- // --
- int type = MT_NONE;
- bool manipulated = false;
- if (gContext.mbEnable)
- {
- if (!gContext.mbUsingBounds)
- {
- manipulated = HandleTranslation(matrix, deltaMatrix, operation, type, snap) ||
- HandleScale(matrix, deltaMatrix, operation, type, snap) ||
- HandleRotation(matrix, deltaMatrix, operation, type, snap);
- }
- }
- if (localBounds && !gContext.mbUsing)
- {
- HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap, operation);
- }
- gContext.mOperation = operation;
- if (!gContext.mbUsingBounds)
- {
- DrawRotationGizmo(operation, type);
- DrawTranslationGizmo(operation, type);
- DrawScaleGizmo(operation, type);
- DrawScaleUniveralGizmo(operation, type);
- }
- return manipulated;
- }
- void SetGizmoSizeClipSpace(float value)
- {
- gContext.mGizmoSizeClipSpace = value;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- void ComputeFrustumPlanes(vec_t* frustum, const float* clip)
- {
- frustum[0].x = clip[3] - clip[0];
- frustum[0].y = clip[7] - clip[4];
- frustum[0].z = clip[11] - clip[8];
- frustum[0].w = clip[15] - clip[12];
- frustum[1].x = clip[3] + clip[0];
- frustum[1].y = clip[7] + clip[4];
- frustum[1].z = clip[11] + clip[8];
- frustum[1].w = clip[15] + clip[12];
- frustum[2].x = clip[3] + clip[1];
- frustum[2].y = clip[7] + clip[5];
- frustum[2].z = clip[11] + clip[9];
- frustum[2].w = clip[15] + clip[13];
- frustum[3].x = clip[3] - clip[1];
- frustum[3].y = clip[7] - clip[5];
- frustum[3].z = clip[11] - clip[9];
- frustum[3].w = clip[15] - clip[13];
- frustum[4].x = clip[3] - clip[2];
- frustum[4].y = clip[7] - clip[6];
- frustum[4].z = clip[11] - clip[10];
- frustum[4].w = clip[15] - clip[14];
- frustum[5].x = clip[3] + clip[2];
- frustum[5].y = clip[7] + clip[6];
- frustum[5].z = clip[11] + clip[10];
- frustum[5].w = clip[15] + clip[14];
- for (int i = 0; i < 6; i++)
- {
- frustum[i].Normalize();
- }
- }
- void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount)
- {
- matrix_t viewInverse;
- viewInverse.Inverse(*(matrix_t*)view);
- struct CubeFace
- {
- float z;
- ImVec2 faceCoordsScreen[4];
- ImU32 color;
- };
- CubeFace* faces = (CubeFace*)_malloca(sizeof(CubeFace) * matrixCount * 6);
- if (!faces)
- {
- return;
- }
- vec_t frustum[6];
- matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection;
- ComputeFrustumPlanes(frustum, viewProjection.m16);
- int cubeFaceCount = 0;
- for (int cube = 0; cube < matrixCount; cube++)
- {
- const float* matrix = &matrices[cube * 16];
- matrix_t res = *(matrix_t*)matrix * *(matrix_t*)view * *(matrix_t*)projection;
- for (int iFace = 0; iFace < 6; iFace++)
- {
- const int normalIndex = (iFace % 3);
- const int perpXIndex = (normalIndex + 1) % 3;
- const int perpYIndex = (normalIndex + 2) % 3;
- const float invert = (iFace > 2) ? -1.f : 1.f;
- const vec_t faceCoords[4] = { directionUnary[normalIndex] + directionUnary[perpXIndex] + directionUnary[perpYIndex],
- directionUnary[normalIndex] + directionUnary[perpXIndex] - directionUnary[perpYIndex],
- directionUnary[normalIndex] - directionUnary[perpXIndex] - directionUnary[perpYIndex],
- directionUnary[normalIndex] - directionUnary[perpXIndex] + directionUnary[perpYIndex],
- };
- // clipping
- /*
- bool skipFace = false;
- for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
- {
- vec_t camSpacePosition;
- camSpacePosition.TransformPoint(faceCoords[iCoord] * 0.5f * invert, res);
- if (camSpacePosition.z < 0.001f)
- {
- skipFace = true;
- break;
- }
- }
- if (skipFace)
- {
- continue;
- }
- */
- vec_t centerPosition, centerPositionVP;
- centerPosition.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, *(matrix_t*)matrix);
- centerPositionVP.TransformPoint(directionUnary[normalIndex] * 0.5f * invert, res);
- bool inFrustum = true;
- for (int iFrustum = 0; iFrustum < 6; iFrustum++)
- {
- float dist = DistanceToPlane(centerPosition, frustum[iFrustum]);
- if (dist < 0.f)
- {
- inFrustum = false;
- break;
- }
- }
- if (!inFrustum)
- {
- continue;
- }
- CubeFace& cubeFace = faces[cubeFaceCount];
- // 3D->2D
- //ImVec2 faceCoordsScreen[4];
- for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
- {
- cubeFace.faceCoordsScreen[iCoord] = worldToPos(faceCoords[iCoord] * 0.5f * invert, res);
- }
- ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex);
- cubeFace.color = directionColor | IM_COL32(0x80, 0x80, 0x80, 0);
- cubeFace.z = centerPositionVP.z / centerPositionVP.w;
- cubeFaceCount++;
- }
- }
- qsort(faces, cubeFaceCount, sizeof(CubeFace), [](void const* _a, void const* _b) {
- CubeFace* a = (CubeFace*)_a;
- CubeFace* b = (CubeFace*)_b;
- if (a->z < b->z)
- {
- return 1;
- }
- return -1;
- });
- // draw face with lighter color
- for (int iFace = 0; iFace < cubeFaceCount; iFace++)
- {
- const CubeFace& cubeFace = faces[iFace];
- gContext.mDrawList->AddConvexPolyFilled(cubeFace.faceCoordsScreen, 4, cubeFace.color);
- }
- _freea(faces);
- }
- void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize)
- {
- matrix_t viewProjection = *(matrix_t*)view * *(matrix_t*)projection;
- vec_t frustum[6];
- ComputeFrustumPlanes(frustum, viewProjection.m16);
- matrix_t res = *(matrix_t*)matrix * viewProjection;
- for (float f = -gridSize; f <= gridSize; f += 1.f)
- {
- for (int dir = 0; dir < 2; dir++)
- {
- vec_t ptA = makeVect(dir ? -gridSize : f, 0.f, dir ? f : -gridSize);
- vec_t ptB = makeVect(dir ? gridSize : f, 0.f, dir ? f : gridSize);
- bool visible = true;
- for (int i = 0; i < 6; i++)
- {
- float dA = DistanceToPlane(ptA, frustum[i]);
- float dB = DistanceToPlane(ptB, frustum[i]);
- if (dA < 0.f && dB < 0.f)
- {
- visible = false;
- break;
- }
- if (dA > 0.f && dB > 0.f)
- {
- continue;
- }
- if (dA < 0.f)
- {
- float len = fabsf(dA - dB);
- float t = fabsf(dA) / len;
- ptA.Lerp(ptB, t);
- }
- if (dB < 0.f)
- {
- float len = fabsf(dB - dA);
- float t = fabsf(dB) / len;
- ptB.Lerp(ptA, t);
- }
- }
- if (visible)
- {
- ImU32 col = IM_COL32(0x80, 0x80, 0x80, 0xFF);
- col = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? IM_COL32(0x90, 0x90, 0x90, 0xFF) : col;
- col = (fabsf(f) < FLT_EPSILON) ? IM_COL32(0x40, 0x40, 0x40, 0xFF): col;
- float thickness = 1.f;
- thickness = (fmodf(fabsf(f), 10.f) < FLT_EPSILON) ? 1.5f : thickness;
- thickness = (fabsf(f) < FLT_EPSILON) ? 2.3f : thickness;
- gContext.mDrawList->AddLine(worldToPos(ptA, res), worldToPos(ptB, res), col, thickness);
- }
- }
- }
- }
- void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor)
- {
- // Scale is always local or matrix will be skewed when applying world scale or oriented matrix
- ComputeContext(view, projection, matrix, (operation & SCALE) ? LOCAL : mode);
- ViewManipulate(view, length, position, size, backgroundColor);
- }
- void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor)
- {
- static bool isDraging = false;
- static bool isClicking = false;
- static bool isInside = false;
- static vec_t interpolationUp;
- static vec_t interpolationDir;
- static int interpolationFrames = 0;
- const vec_t referenceUp = makeVect(0.f, 1.f, 0.f);
- matrix_t svgView, svgProjection;
- svgView = gContext.mViewMat;
- svgProjection = gContext.mProjectionMat;
- ImGuiIO& io = ImGui::GetIO();
- gContext.mDrawList->AddRectFilled(position, position + size, backgroundColor);
- matrix_t viewInverse;
- viewInverse.Inverse(*(matrix_t*)view);
- const vec_t camTarget = viewInverse.v.position - viewInverse.v.dir * length;
- // view/projection matrices
- const float distance = 3.f;
- matrix_t cubeProjection, cubeView;
- float fov = acosf(distance / (sqrtf(distance * distance + 3.f))) * RAD2DEG;
- Perspective(fov / sqrtf(2.f), size.x / size.y, 0.01f, 1000.f, cubeProjection.m16);
- vec_t dir = makeVect(viewInverse.m[2][0], viewInverse.m[2][1], viewInverse.m[2][2]);
- vec_t up = makeVect(viewInverse.m[1][0], viewInverse.m[1][1], viewInverse.m[1][2]);
- vec_t eye = dir * distance;
- vec_t zero = makeVect(0.f, 0.f);
- LookAt(&eye.x, &zero.x, &up.x, cubeView.m16);
- // set context
- gContext.mViewMat = cubeView;
- gContext.mProjectionMat = cubeProjection;
- ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector, position, size);
- const matrix_t res = cubeView * cubeProjection;
- // panels
- static const ImVec2 panelPosition[9] = { ImVec2(0.75f,0.75f), ImVec2(0.25f, 0.75f), ImVec2(0.f, 0.75f),
- ImVec2(0.75f, 0.25f), ImVec2(0.25f, 0.25f), ImVec2(0.f, 0.25f),
- ImVec2(0.75f, 0.f), ImVec2(0.25f, 0.f), ImVec2(0.f, 0.f) };
- static const ImVec2 panelSize[9] = { ImVec2(0.25f,0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f),
- ImVec2(0.25f, 0.5f), ImVec2(0.5f, 0.5f), ImVec2(0.25f, 0.5f),
- ImVec2(0.25f, 0.25f), ImVec2(0.5f, 0.25f), ImVec2(0.25f, 0.25f) };
- // tag faces
- bool boxes[27]{};
- static int overBox = -1;
- for (int iPass = 0; iPass < 2; iPass++)
- {
- for (int iFace = 0; iFace < 6; iFace++)
- {
- const int normalIndex = (iFace % 3);
- const int perpXIndex = (normalIndex + 1) % 3;
- const int perpYIndex = (normalIndex + 2) % 3;
- const float invert = (iFace > 2) ? -1.f : 1.f;
- const vec_t indexVectorX = directionUnary[perpXIndex] * invert;
- const vec_t indexVectorY = directionUnary[perpYIndex] * invert;
- const vec_t boxOrigin = directionUnary[normalIndex] * -invert - indexVectorX - indexVectorY;
- // plan local space
- const vec_t n = directionUnary[normalIndex] * invert;
- vec_t viewSpaceNormal = n;
- vec_t viewSpacePoint = n * 0.5f;
- viewSpaceNormal.TransformVector(cubeView);
- viewSpaceNormal.Normalize();
- viewSpacePoint.TransformPoint(cubeView);
- const vec_t viewSpaceFacePlan = BuildPlan(viewSpacePoint, viewSpaceNormal);
- // back face culling
- if (viewSpaceFacePlan.w > 0.f)
- {
- continue;
- }
- const vec_t facePlan = BuildPlan(n * 0.5f, n);
- const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, facePlan);
- vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len - (n * 0.5f);
- float localx = Dot(directionUnary[perpXIndex], posOnPlan) * invert + 0.5f;
- float localy = Dot(directionUnary[perpYIndex], posOnPlan) * invert + 0.5f;
- // panels
- const vec_t dx = directionUnary[perpXIndex];
- const vec_t dy = directionUnary[perpYIndex];
- const vec_t origin = directionUnary[normalIndex] - dx - dy;
- for (int iPanel = 0; iPanel < 9; iPanel++)
- {
- vec_t boxCoord = boxOrigin + indexVectorX * float(iPanel % 3) + indexVectorY * float(iPanel / 3) + makeVect(1.f, 1.f, 1.f);
- const ImVec2 p = panelPosition[iPanel] * 2.f;
- const ImVec2 s = panelSize[iPanel] * 2.f;
- ImVec2 faceCoordsScreen[4];
- vec_t panelPos[4] = { dx * p.x + dy * p.y,
- dx * p.x + dy * (p.y + s.y),
- dx * (p.x + s.x) + dy * (p.y + s.y),
- dx * (p.x + s.x) + dy * p.y };
- for (unsigned int iCoord = 0; iCoord < 4; iCoord++)
- {
- faceCoordsScreen[iCoord] = worldToPos((panelPos[iCoord] + origin) * 0.5f * invert, res, position, size);
- }
- const ImVec2 panelCorners[2] = { panelPosition[iPanel], panelPosition[iPanel] + panelSize[iPanel] };
- bool insidePanel = localx > panelCorners[0].x && localx < panelCorners[1].x && localy > panelCorners[0].y && localy < panelCorners[1].y;
- int boxCoordInt = int(boxCoord.x * 9.f + boxCoord.y * 3.f + boxCoord.z);
- IM_ASSERT(boxCoordInt < 27);
- boxes[boxCoordInt] |= insidePanel && (!isDraging) && gContext.mbMouseOver;
- // draw face with lighter color
- if (iPass)
- {
- ImU32 directionColor = GetColorU32(DIRECTION_X + normalIndex);
- gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, (directionColor | IM_COL32(0x80, 0x80, 0x80, 0x80)) | (isInside ? IM_COL32(0x08, 0x08, 0x08, 0) : 0));
- if (boxes[boxCoordInt])
- {
- gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, IM_COL32(0xF0, 0xA0, 0x60, 0x80));
- if (io.MouseDown[0] && !isClicking && !isDraging && GImGui->ActiveId == 0) {
- overBox = boxCoordInt;
- isClicking = true;
- isDraging = true;
- }
- }
- }
- }
- }
- }
- if (interpolationFrames)
- {
- interpolationFrames--;
- vec_t newDir = viewInverse.v.dir;
- newDir.Lerp(interpolationDir, 0.2f);
- newDir.Normalize();
- vec_t newUp = viewInverse.v.up;
- newUp.Lerp(interpolationUp, 0.3f);
- newUp.Normalize();
- newUp = interpolationUp;
- vec_t newEye = camTarget + newDir * length;
- LookAt(&newEye.x, &camTarget.x, &newUp.x, view);
- }
- isInside = gContext.mbMouseOver && ImRect(position, position + size).Contains(io.MousePos);
- if (io.MouseDown[0] && (fabsf(io.MouseDelta[0]) || fabsf(io.MouseDelta[1])) && isClicking)
- {
- isClicking = false;
- }
- if (!io.MouseDown[0])
- {
- if (isClicking)
- {
- // apply new view direction
- int cx = overBox / 9;
- int cy = (overBox - cx * 9) / 3;
- int cz = overBox % 3;
- interpolationDir = makeVect(1.f - (float)cx, 1.f - (float)cy, 1.f - (float)cz);
- interpolationDir.Normalize();
- if (fabsf(Dot(interpolationDir, referenceUp)) > 1.0f - 0.01f)
- {
- vec_t right = viewInverse.v.right;
- if (fabsf(right.x) > fabsf(right.z))
- {
- right.z = 0.f;
- }
- else
- {
- right.x = 0.f;
- }
- right.Normalize();
- interpolationUp = Cross(interpolationDir, right);
- interpolationUp.Normalize();
- }
- else
- {
- interpolationUp = referenceUp;
- }
- interpolationFrames = 40;
- }
- isClicking = false;
- isDraging = false;
- }
- if (isDraging)
- {
- matrix_t rx, ry, roll;
- rx.RotationAxis(referenceUp, -io.MouseDelta.x * 0.01f);
- ry.RotationAxis(viewInverse.v.right, -io.MouseDelta.y * 0.01f);
- roll = rx * ry;
- vec_t newDir = viewInverse.v.dir;
- newDir.TransformVector(roll);
- newDir.Normalize();
- // clamp
- vec_t planDir = Cross(viewInverse.v.right, referenceUp);
- planDir.y = 0.f;
- planDir.Normalize();
- float dt = Dot(planDir, newDir);
- if (dt < 0.0f)
- {
- newDir += planDir * dt;
- newDir.Normalize();
- }
- vec_t newEye = camTarget + newDir * length;
- LookAt(&newEye.x, &camTarget.x, &referenceUp.x, view);
- }
- // restore view/projection because it was used to compute ray
- ComputeContext(svgView.m16, svgProjection.m16, gContext.mModelSource.m16, gContext.mMode);
- }
- };
|