| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370 |
- #include "float_math.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <math.h>
- #include <float.h>
- /*----------------------------------------------------------------------
- Copyright (c) 2004 Open Dynamics Framework Group
- www.physicstools.org
- All rights reserved.
- Redistribution and use in source and binary forms, with or without modification, are permitted provided
- that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions
- and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
- be used to endorse or promote products derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- -----------------------------------------------------------------------*/
- // http://codesuppository.blogspot.com
- //
- // mailto: [email protected]
- //
- // http://www.amillionpixels.us
- //
- #include "cd_hull.h"
- using namespace ConvexDecomposition;
- /*----------------------------------------------------------------------
- Copyright (c) 2004 Open Dynamics Framework Group
- www.physicstools.org
- All rights reserved.
- Redistribution and use in source and binary forms, with or without modification, are permitted provided
- that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions
- and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
- be used to endorse or promote products derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- -----------------------------------------------------------------------*/
- #define PI 3.14159264f
- //*****************************************************
- //*****************************************************
- //********* Stan Melax's vector math template needed
- //********* to use his hull building code.
- //*****************************************************
- //*****************************************************
- #define DEG2RAD (PI / 180.0f)
- #define RAD2DEG (180.0f / PI)
- #define SQRT_OF_2 (1.4142135f)
- #define OFFSET(Class, Member) (((char *)(&(((Class *)NULL)->Member))) - ((char *)NULL))
- namespace ConvexDecomposition
- {
- int argmin(float a[], int n);
- float sqr(float a);
- float clampf(float a);
- float Round(float a, float precision);
- float Interpolate(const float &f0, const float &f1, float alpha);
- template <class T>
- void Swap(T &a, T &b)
- {
- T tmp = a;
- a = b;
- b = tmp;
- }
- template <class T>
- T Max(const T &a, const T &b)
- {
- return (a > b) ? a : b;
- }
- template <class T>
- T Min(const T &a, const T &b)
- {
- return (a < b) ? a : b;
- }
- //----------------------------------
- class int3
- {
- public:
- int x, y, z;
- int3(){};
- int3(int _x, int _y, int _z)
- {
- x = _x;
- y = _y;
- z = _z;
- }
- const int &operator[](int i) const { return (&x)[i]; }
- int &operator[](int i) { return (&x)[i]; }
- };
- //-------- 2D --------
- class float2
- {
- public:
- float x, y;
- float2()
- {
- x = 0;
- y = 0;
- };
- float2(float _x, float _y)
- {
- x = _x;
- y = _y;
- }
- float &operator[](int i)
- {
- assert(i >= 0 && i < 2);
- return ((float *)this)[i];
- }
- const float &operator[](int i) const
- {
- assert(i >= 0 && i < 2);
- return ((float *)this)[i];
- }
- };
- inline float2 operator-(const float2 &a, const float2 &b) { return float2(a.x - b.x, a.y - b.y); }
- inline float2 operator+(const float2 &a, const float2 &b) { return float2(a.x + b.x, a.y + b.y); }
- //--------- 3D ---------
- class float3 // 3D
- {
- public:
- float x, y, z;
- float3()
- {
- x = 0;
- y = 0;
- z = 0;
- };
- float3(float _x, float _y, float _z)
- {
- x = _x;
- y = _y;
- z = _z;
- };
- //operator float *() { return &x;};
- float &operator[](int i)
- {
- assert(i >= 0 && i < 3);
- return ((float *)this)[i];
- }
- const float &operator[](int i) const
- {
- assert(i >= 0 && i < 3);
- return ((float *)this)[i];
- }
- #ifdef PLUGIN_3DSMAX
- float3(const Point3 &p) : x(p.x), y(p.y), z(p.z)
- {
- }
- operator Point3() { return *((Point3 *)this); }
- #endif
- };
- float3 &operator+=(float3 &a, const float3 &b);
- float3 &operator-=(float3 &a, const float3 &b);
- float3 &operator*=(float3 &v, const float s);
- float3 &operator/=(float3 &v, const float s);
- float magnitude(const float3 &v);
- float3 normalize(const float3 &v);
- float3 safenormalize(const float3 &v);
- float3 vabs(const float3 &v);
- float3 operator+(const float3 &a, const float3 &b);
- float3 operator-(const float3 &a, const float3 &b);
- float3 operator-(const float3 &v);
- float3 operator*(const float3 &v, const float s);
- float3 operator*(const float s, const float3 &v);
- float3 operator/(const float3 &v, const float s);
- inline int operator==(const float3 &a, const float3 &b) { return (a.x == b.x && a.y == b.y && a.z == b.z); }
- inline int operator!=(const float3 &a, const float3 &b) { return (a.x != b.x || a.y != b.y || a.z != b.z); }
- // due to ambiguity and inconsistent standards ther are no overloaded operators for mult such as va*vb.
- float dot(const float3 &a, const float3 &b);
- float3 cmul(const float3 &a, const float3 &b);
- float3 cross(const float3 &a, const float3 &b);
- float3 Interpolate(const float3 &v0, const float3 &v1, float alpha);
- float3 Round(const float3 &a, float precision);
- float3 VectorMax(const float3 &a, const float3 &b);
- float3 VectorMin(const float3 &a, const float3 &b);
- class float3x3
- {
- public:
- float3 x, y, z; // the 3 rows of the Matrix
- float3x3() {}
- float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz) : x(xx, xy, xz), y(yx, yy, yz), z(zx, zy, zz) {}
- float3x3(float3 _x, float3 _y, float3 _z) : x(_x), y(_y), z(_z) {}
- float3 &operator[](int i)
- {
- assert(i >= 0 && i < 3);
- return (&x)[i];
- }
- const float3 &operator[](int i) const
- {
- assert(i >= 0 && i < 3);
- return (&x)[i];
- }
- float &operator()(int r, int c)
- {
- assert(r >= 0 && r < 3 && c >= 0 && c < 3);
- return ((&x)[r])[c];
- }
- const float &operator()(int r, int c) const
- {
- assert(r >= 0 && r < 3 && c >= 0 && c < 3);
- return ((&x)[r])[c];
- }
- };
- float3x3 Transpose(const float3x3 &m);
- float3 operator*(const float3 &v, const float3x3 &m);
- float3 operator*(const float3x3 &m, const float3 &v);
- float3x3 operator*(const float3x3 &m, const float &s);
- float3x3 operator*(const float3x3 &ma, const float3x3 &mb);
- float3x3 operator/(const float3x3 &a, const float &s);
- float3x3 operator+(const float3x3 &a, const float3x3 &b);
- float3x3 operator-(const float3x3 &a, const float3x3 &b);
- float3x3 &operator+=(float3x3 &a, const float3x3 &b);
- float3x3 &operator-=(float3x3 &a, const float3x3 &b);
- float3x3 &operator*=(float3x3 &a, const float &s);
- float Determinant(const float3x3 &m);
- float3x3 Inverse(const float3x3 &a); // its just 3x3 so we simply do that cofactor method
- //-------- 4D Math --------
- class float4
- {
- public:
- float x, y, z, w;
- float4()
- {
- x = 0;
- y = 0;
- z = 0;
- w = 0;
- };
- float4(float _x, float _y, float _z, float _w)
- {
- x = _x;
- y = _y;
- z = _z;
- w = _w;
- }
- float4(const float3 &v, float _w)
- {
- x = v.x;
- y = v.y;
- z = v.z;
- w = _w;
- }
- //operator float *() { return &x;};
- float &operator[](int i)
- {
- assert(i >= 0 && i < 4);
- return ((float *)this)[i];
- }
- const float &operator[](int i) const
- {
- assert(i >= 0 && i < 4);
- return ((float *)this)[i];
- }
- const float3 &xyz() const { return *((float3 *)this); }
- float3 &xyz() { return *((float3 *)this); }
- };
- struct D3DXMATRIX;
- class float4x4
- {
- public:
- float4 x, y, z, w; // the 4 rows
- float4x4() {}
- float4x4(const float4 &_x, const float4 &_y, const float4 &_z, const float4 &_w) : x(_x), y(_y), z(_z), w(_w) {}
- float4x4(float m00, float m01, float m02, float m03,
- float m10, float m11, float m12, float m13,
- float m20, float m21, float m22, float m23,
- float m30, float m31, float m32, float m33)
- : x(m00, m01, m02, m03), y(m10, m11, m12, m13), z(m20, m21, m22, m23), w(m30, m31, m32, m33) {}
- float &operator()(int r, int c)
- {
- assert(r >= 0 && r < 4 && c >= 0 && c < 4);
- return ((&x)[r])[c];
- }
- const float &operator()(int r, int c) const
- {
- assert(r >= 0 && r < 4 && c >= 0 && c < 4);
- return ((&x)[r])[c];
- }
- operator float *() { return &x.x; }
- operator const float *() const { return &x.x; }
- operator struct D3DXMATRIX *() { return (struct D3DXMATRIX *)this; }
- operator const struct D3DXMATRIX *() const { return (struct D3DXMATRIX *)this; }
- };
- int operator==(const float4 &a, const float4 &b);
- float4 Homogenize(const float3 &v3, const float &w = 1.0f); // Turns a 3D float3 4D vector4 by appending w
- float4 cmul(const float4 &a, const float4 &b);
- float4 operator*(const float4 &v, float s);
- float4 operator*(float s, const float4 &v);
- float4 operator+(const float4 &a, const float4 &b);
- float4 operator-(const float4 &a, const float4 &b);
- float4x4 operator*(const float4x4 &a, const float4x4 &b);
- float4 operator*(const float4 &v, const float4x4 &m);
- float4x4 Inverse(const float4x4 &m);
- float4x4 MatrixRigidInverse(const float4x4 &m);
- float4x4 MatrixTranspose(const float4x4 &m);
- float4x4 MatrixPerspectiveFov(float fovy, float Aspect, float zn, float zf);
- float4x4 MatrixTranslation(const float3 &t);
- float4x4 MatrixRotationZ(const float angle_radians);
- float4x4 MatrixLookAt(const float3 &eye, const float3 &at, const float3 &up);
- int operator==(const float4x4 &a, const float4x4 &b);
- //-------- Quaternion ------------
- class Quaternion : public float4
- {
- public:
- Quaternion()
- {
- x = y = z = 0.0f;
- w = 1.0f;
- }
- Quaternion(float3 v, float t)
- {
- v = normalize(v);
- w = cosf(t / 2.0f);
- v = v * sinf(t / 2.0f);
- x = v.x;
- y = v.y;
- z = v.z;
- }
- Quaternion(float _x, float _y, float _z, float _w)
- {
- x = _x;
- y = _y;
- z = _z;
- w = _w;
- }
- float angle() const { return acosf(w) * 2.0f; }
- float3 axis() const
- {
- float3 a(x, y, z);
- if (fabsf(angle()) < 0.0000001f) return float3(1, 0, 0);
- return a * (1 / sinf(angle() / 2.0f));
- }
- float3 xdir() const { return float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y)); }
- float3 ydir() const { return float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x)); }
- float3 zdir() const { return float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y)); }
- float3x3 getmatrix() const { return float3x3(xdir(), ydir(), zdir()); }
- operator float3x3() { return getmatrix(); }
- void Normalize();
- };
- Quaternion &operator*=(Quaternion &a, float s);
- Quaternion operator*(const Quaternion &a, float s);
- Quaternion operator*(const Quaternion &a, const Quaternion &b);
- Quaternion operator+(const Quaternion &a, const Quaternion &b);
- Quaternion normalize(Quaternion a);
- float dot(const Quaternion &a, const Quaternion &b);
- float3 operator*(const Quaternion &q, const float3 &v);
- float3 operator*(const float3 &v, const Quaternion &q);
- Quaternion slerp(Quaternion a, const Quaternion &b, float interp);
- Quaternion Interpolate(const Quaternion &q0, const Quaternion &q1, float alpha);
- Quaternion RotationArc(float3 v0, float3 v1); // returns quat q where q*v0=v1
- Quaternion Inverse(const Quaternion &q);
- float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v);
- //------ Euler Angle -----
- Quaternion YawPitchRoll(float yaw, float pitch, float roll);
- float Yaw(const Quaternion &q);
- float Pitch(const Quaternion &q);
- float Roll(Quaternion q);
- float Yaw(const float3 &v);
- float Pitch(const float3 &v);
- //------- Plane ----------
- class Plane
- {
- public:
- float3 normal;
- float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
- Plane(const float3 &n, float d) : normal(n), dist(d) {}
- Plane() : normal(), dist(0) {}
- void Transform(const float3 &position, const Quaternion &orientation);
- };
- inline Plane PlaneFlip(const Plane &plane) { return Plane(-plane.normal, -plane.dist); }
- inline int operator==(const Plane &a, const Plane &b) { return (a.normal == b.normal && a.dist == b.dist); }
- inline int coplanar(const Plane &a, const Plane &b) { return (a == b || a == PlaneFlip(b)); }
- //--------- Utility Functions ------
- float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1);
- float3 PlaneProject(const Plane &plane, const float3 &point);
- float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a); // projects a onto infinite line p0p1
- float LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a);
- float3 ThreePlaneIntersection(const Plane &p0, const Plane &p1, const Plane &p2);
- int PolyHit(const float3 *vert, const int n, const float3 &v0, const float3 &v1, float3 *impact = NULL, float3 *normal = NULL);
- int BoxInside(const float3 &p, const float3 &bmin, const float3 &bmax);
- int BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax, float3 *impact);
- float DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint = NULL, float3 *vpoint = NULL);
- float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2);
- float3 NormalOf(const float3 *vert, const int n);
- Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir0, const float3 &dir1);
- float sqr(float a) { return a * a; }
- float clampf(float a) { return Min(1.0f, Max(0.0f, a)); }
- float Round(float a, float precision)
- {
- return floorf(0.5f + a / precision) * precision;
- }
- float Interpolate(const float &f0, const float &f1, float alpha)
- {
- return f0 * (1 - alpha) + f1 * alpha;
- }
- int argmin(float a[], int n)
- {
- int r = 0;
- for (int i = 1; i < n; i++)
- {
- if (a[i] < a[r])
- {
- r = i;
- }
- }
- return r;
- }
- //------------ float3 (3D) --------------
- float3 operator+(const float3 &a, const float3 &b)
- {
- return float3(a.x + b.x, a.y + b.y, a.z + b.z);
- }
- float3 operator-(const float3 &a, const float3 &b)
- {
- return float3(a.x - b.x, a.y - b.y, a.z - b.z);
- }
- float3 operator-(const float3 &v)
- {
- return float3(-v.x, -v.y, -v.z);
- }
- float3 operator*(const float3 &v, float s)
- {
- return float3(v.x * s, v.y * s, v.z * s);
- }
- float3 operator*(float s, const float3 &v)
- {
- return float3(v.x * s, v.y * s, v.z * s);
- }
- float3 operator/(const float3 &v, float s)
- {
- return v * (1.0f / s);
- }
- float dot(const float3 &a, const float3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
- float3 cmul(const float3 &v1, const float3 &v2)
- {
- return float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
- }
- float3 cross(const float3 &a, const float3 &b)
- {
- return float3(a.y * b.z - a.z * b.y,
- a.z * b.x - a.x * b.z,
- a.x * b.y - a.y * b.x);
- }
- float3 &operator+=(float3 &a, const float3 &b)
- {
- a.x += b.x;
- a.y += b.y;
- a.z += b.z;
- return a;
- }
- float3 &operator-=(float3 &a, const float3 &b)
- {
- a.x -= b.x;
- a.y -= b.y;
- a.z -= b.z;
- return a;
- }
- float3 &operator*=(float3 &v, float s)
- {
- v.x *= s;
- v.y *= s;
- v.z *= s;
- return v;
- }
- float3 &operator/=(float3 &v, float s)
- {
- float sinv = 1.0f / s;
- v.x *= sinv;
- v.y *= sinv;
- v.z *= sinv;
- return v;
- }
- float3 vabs(const float3 &v)
- {
- return float3(fabsf(v.x), fabsf(v.y), fabsf(v.z));
- }
- float magnitude(const float3 &v)
- {
- return sqrtf(sqr(v.x) + sqr(v.y) + sqr(v.z));
- }
- float3 normalize(const float3 &v)
- {
- // this routine, normalize, is ok, provided magnitude works!!
- float d = magnitude(v);
- if (d == 0)
- {
- printf("Cant normalize ZERO vector\n");
- assert(0); // yes this could go here
- d = 0.1f;
- }
- d = 1 / d;
- return float3(v.x * d, v.y * d, v.z * d);
- }
- float3 safenormalize(const float3 &v)
- {
- if (magnitude(v) <= 0.0f)
- {
- return float3(1, 0, 0);
- }
- return normalize(v);
- }
- float3 Round(const float3 &a, float precision)
- {
- return float3(Round(a.x, precision), Round(a.y, precision), Round(a.z, precision));
- }
- float3 Interpolate(const float3 &v0, const float3 &v1, float alpha)
- {
- return v0 * (1 - alpha) + v1 * alpha;
- }
- float3 VectorMin(const float3 &a, const float3 &b)
- {
- return float3(Min(a.x, b.x), Min(a.y, b.y), Min(a.z, b.z));
- }
- float3 VectorMax(const float3 &a, const float3 &b)
- {
- return float3(Max(a.x, b.x), Max(a.y, b.y), Max(a.z, b.z));
- }
- // the statement v1*v2 is ambiguous since there are 3 types
- // of vector multiplication
- // - componantwise (for example combining colors)
- // - dot product
- // - cross product
- // Therefore we never declare/implement this function.
- // So we will never see: float3 operator*(float3 a,float3 b)
- //------------ float3x3 ---------------
- float Determinant(const float3x3 &m)
- {
- return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z;
- }
- float3x3 Inverse(const float3x3 &a)
- {
- float3x3 b;
- float d = Determinant(a);
- assert(d != 0);
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- int i1 = (i + 1) % 3;
- int i2 = (i + 2) % 3;
- int j1 = (j + 1) % 3;
- int j2 = (j + 2) % 3;
- // reverse indexs i&j to take transpose
- b[j][i] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d;
- }
- }
- // Matrix check=a*b; // Matrix 'check' should be the identity (or close to it)
- return b;
- }
- float3x3 Transpose(const float3x3 &m)
- {
- return float3x3(float3(m.x.x, m.y.x, m.z.x),
- float3(m.x.y, m.y.y, m.z.y),
- float3(m.x.z, m.y.z, m.z.z));
- }
- float3 operator*(const float3 &v, const float3x3 &m)
- {
- return float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z),
- (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z),
- (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z));
- }
- float3 operator*(const float3x3 &m, const float3 &v)
- {
- return float3(dot(m.x, v), dot(m.y, v), dot(m.z, v));
- }
- float3x3 operator*(const float3x3 &a, const float3x3 &b)
- {
- return float3x3(a.x * b, a.y * b, a.z * b);
- }
- float3x3 operator*(const float3x3 &a, const float &s)
- {
- return float3x3(a.x * s, a.y * s, a.z * s);
- }
- float3x3 operator/(const float3x3 &a, const float &s)
- {
- float t = 1 / s;
- return float3x3(a.x * t, a.y * t, a.z * t);
- }
- float3x3 operator+(const float3x3 &a, const float3x3 &b)
- {
- return float3x3(a.x + b.x, a.y + b.y, a.z + b.z);
- }
- float3x3 operator-(const float3x3 &a, const float3x3 &b)
- {
- return float3x3(a.x - b.x, a.y - b.y, a.z - b.z);
- }
- float3x3 &operator+=(float3x3 &a, const float3x3 &b)
- {
- a.x += b.x;
- a.y += b.y;
- a.z += b.z;
- return a;
- }
- float3x3 &operator-=(float3x3 &a, const float3x3 &b)
- {
- a.x -= b.x;
- a.y -= b.y;
- a.z -= b.z;
- return a;
- }
- float3x3 &operator*=(float3x3 &a, const float &s)
- {
- a.x *= s;
- a.y *= s;
- a.z *= s;
- return a;
- }
- float3 ThreePlaneIntersection(const Plane &p0, const Plane &p1, const Plane &p2)
- {
- float3x3 mp = Transpose(float3x3(p0.normal, p1.normal, p2.normal));
- float3x3 mi = Inverse(mp);
- float3 b(p0.dist, p1.dist, p2.dist);
- return -b * mi;
- }
- //--------------- 4D ----------------
- float4 operator*(const float4 &v, const float4x4 &m)
- {
- return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works
- }
- int operator==(const float4 &a, const float4 &b)
- {
- return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
- }
- // Dont implement m*v for now, since that might confuse us
- // All our transforms are based on multiplying the "row" vector on the left
- //float4 operator*(const float4x4& m , const float4& v )
- //{
- // return float4(dot(v,m.x),dot(v,m.y),dot(v,m.z),dot(v,m.w));
- //}
- float4 cmul(const float4 &a, const float4 &b)
- {
- return float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
- }
- float4 operator*(const float4 &v, float s)
- {
- return float4(v.x * s, v.y * s, v.z * s, v.w * s);
- }
- float4 operator*(float s, const float4 &v)
- {
- return float4(v.x * s, v.y * s, v.z * s, v.w * s);
- }
- float4 operator+(const float4 &a, const float4 &b)
- {
- return float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
- }
- float4 operator-(const float4 &a, const float4 &b)
- {
- return float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
- }
- float4 Homogenize(const float3 &v3, const float &w)
- {
- return float4(v3.x, v3.y, v3.z, w);
- }
- float4x4 operator*(const float4x4 &a, const float4x4 &b)
- {
- return float4x4(a.x * b, a.y * b, a.z * b, a.w * b);
- }
- float4x4 MatrixTranspose(const float4x4 &m)
- {
- return float4x4(
- m.x.x, m.y.x, m.z.x, m.w.x,
- m.x.y, m.y.y, m.z.y, m.w.y,
- m.x.z, m.y.z, m.z.z, m.w.z,
- m.x.w, m.y.w, m.z.w, m.w.w);
- }
- float4x4 MatrixRigidInverse(const float4x4 &m)
- {
- float4x4 trans_inverse = MatrixTranslation(-m.w.xyz());
- float4x4 rot = m;
- rot.w = float4(0, 0, 0, 1);
- return trans_inverse * MatrixTranspose(rot);
- }
- float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf)
- {
- float h = 1.0f / tanf(fovy / 2.0f); // view space height
- float w = h / aspect; // view space width
- return float4x4(
- w, 0, 0, 0,
- 0, h, 0, 0,
- 0, 0, zf / (zn - zf), -1,
- 0, 0, zn * zf / (zn - zf), 0);
- }
- float4x4 MatrixLookAt(const float3 &eye, const float3 &at, const float3 &up)
- {
- float4x4 m;
- m.w.w = 1.0f;
- m.w.xyz() = eye;
- m.z.xyz() = normalize(eye - at);
- m.x.xyz() = normalize(cross(up, m.z.xyz()));
- m.y.xyz() = cross(m.z.xyz(), m.x.xyz());
- return MatrixRigidInverse(m);
- }
- float4x4 MatrixTranslation(const float3 &t)
- {
- return float4x4(
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- t.x, t.y, t.z, 1);
- }
- float4x4 MatrixRotationZ(const float angle_radians)
- {
- float s = sinf(angle_radians);
- float c = cosf(angle_radians);
- return float4x4(
- c, s, 0, 0,
- -s, c, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1);
- }
- int operator==(const float4x4 &a, const float4x4 &b)
- {
- return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
- }
- float4x4 Inverse(const float4x4 &m)
- {
- float4x4 d;
- float *dst = &d.x.x;
- float tmp[12]; /* temp array for pairs */
- float src[16]; /* array of transpose source matrix */
- float det; /* determinant */
- /* transpose matrix */
- for (int i = 0; i < 4; i++)
- {
- src[i] = m(i, 0);
- src[i + 4] = m(i, 1);
- src[i + 8] = m(i, 2);
- src[i + 12] = m(i, 3);
- }
- /* calculate pairs for first 8 elements (cofactors) */
- 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) */
- dst[0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7];
- dst[0] -= tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7];
- dst[1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7];
- dst[1] -= tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7];
- dst[2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7];
- dst[2] -= tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7];
- dst[3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6];
- dst[3] -= tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6];
- dst[4] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3];
- dst[4] -= tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3];
- dst[5] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3];
- dst[5] -= tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3];
- dst[6] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3];
- dst[6] -= tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3];
- dst[7] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2];
- dst[7] -= 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) */
- dst[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15];
- dst[8] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15];
- dst[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15];
- dst[9] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15];
- dst[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15];
- dst[10] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15];
- dst[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14];
- dst[11] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14];
- dst[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9];
- dst[12] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10];
- dst[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10];
- dst[13] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8];
- dst[14] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8];
- dst[14] -= tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9];
- dst[15] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9];
- dst[15] -= tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8];
- /* calculate determinant */
- det = src[0] * dst[0] + src[1] * dst[1] + src[2] * dst[2] + src[3] * dst[3];
- /* calculate matrix inverse */
- det = 1 / det;
- for (int j = 0; j < 16; j++)
- dst[j] *= det;
- return d;
- }
- //--------- Quaternion --------------
- Quaternion operator*(const Quaternion &a, const Quaternion &b)
- {
- Quaternion c;
- c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
- c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
- c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
- c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
- return c;
- }
- Quaternion operator*(const Quaternion &a, float b)
- {
- return Quaternion(a.x * b, a.y * b, a.z * b, a.w * b);
- }
- Quaternion Inverse(const Quaternion &q)
- {
- return Quaternion(-q.x, -q.y, -q.z, q.w);
- }
- Quaternion &operator*=(Quaternion &q, const float s)
- {
- q.x *= s;
- q.y *= s;
- q.z *= s;
- q.w *= s;
- return q;
- }
- void Quaternion::Normalize()
- {
- float m = sqrtf(sqr(w) + sqr(x) + sqr(y) + sqr(z));
- if (m < 0.000000001f)
- {
- w = 1.0f;
- x = y = z = 0.0f;
- return;
- }
- (*this) *= (1.0f / m);
- }
- float3 operator*(const Quaternion &q, const float3 &v)
- {
- // The following is equivalent to:
- //return (q.getmatrix() * v);
- float qx2 = q.x * q.x;
- float qy2 = q.y * q.y;
- float qz2 = q.z * q.z;
- float qxqy = q.x * q.y;
- float qxqz = q.x * q.z;
- float qxqw = q.x * q.w;
- float qyqz = q.y * q.z;
- float qyqw = q.y * q.w;
- float qzqw = q.z * q.w;
- return float3(
- (1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z,
- (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z,
- (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z);
- }
- float3 operator*(const float3 &v, const Quaternion &q)
- {
- assert(0); // must multiply with the quat on the left
- return float3(0.0f, 0.0f, 0.0f);
- }
- Quaternion operator+(const Quaternion &a, const Quaternion &b)
- {
- return Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
- }
- float dot(const Quaternion &a, const Quaternion &b)
- {
- return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z);
- }
- Quaternion normalize(Quaternion a)
- {
- float m = sqrtf(sqr(a.w) + sqr(a.x) + sqr(a.y) + sqr(a.z));
- if (m < 0.000000001)
- {
- a.w = 1;
- a.x = a.y = a.z = 0;
- return a;
- }
- return a * (1 / m);
- }
- Quaternion slerp(Quaternion a, const Quaternion &b, float interp)
- {
- if (dot(a, b) < 0.0)
- {
- a.w = -a.w;
- a.x = -a.x;
- a.y = -a.y;
- a.z = -a.z;
- }
- float d = dot(a, b);
- if (d >= 1.0)
- {
- return a;
- }
- float theta = acosf(d);
- if (theta == 0.0f)
- {
- return (a);
- }
- return a * (sinf(theta - interp * theta) / sinf(theta)) + b * (sinf(interp * theta) / sinf(theta));
- }
- Quaternion Interpolate(const Quaternion &q0, const Quaternion &q1, float alpha)
- {
- return slerp(q0, q1, alpha);
- }
- Quaternion YawPitchRoll(float yaw, float pitch, float roll)
- {
- roll *= DEG2RAD;
- yaw *= DEG2RAD;
- pitch *= DEG2RAD;
- return Quaternion(float3(0.0f, 0.0f, 1.0f), yaw) * Quaternion(float3(1.0f, 0.0f, 0.0f), pitch) * Quaternion(float3(0.0f, 1.0f, 0.0f), roll);
- }
- float Yaw(const Quaternion &q)
- {
- float3 v;
- v = q.ydir();
- return (v.y == 0.0 && v.x == 0.0) ? 0.0f : atan2f(-v.x, v.y) * RAD2DEG;
- }
- float Pitch(const Quaternion &q)
- {
- float3 v;
- v = q.ydir();
- return atan2f(v.z, sqrtf(sqr(v.x) + sqr(v.y))) * RAD2DEG;
- }
- float Roll(Quaternion q)
- {
- q = Quaternion(float3(0.0f, 0.0f, 1.0f), -Yaw(q) * DEG2RAD) * q;
- q = Quaternion(float3(1.0f, 0.0f, 0.0f), -Pitch(q) * DEG2RAD) * q;
- return atan2f(-q.xdir().z, q.xdir().x) * RAD2DEG;
- }
- float Yaw(const float3 &v)
- {
- return (v.y == 0.0 && v.x == 0.0) ? 0.0f : atan2f(-v.x, v.y) * RAD2DEG;
- }
- float Pitch(const float3 &v)
- {
- return atan2f(v.z, sqrtf(sqr(v.x) + sqr(v.y))) * RAD2DEG;
- }
- //------------- Plane --------------
- void Plane::Transform(const float3 &position, const Quaternion &orientation)
- {
- // Transforms the plane to the space defined by the
- // given position/orientation.
- float3 newnormal;
- float3 origin;
- newnormal = Inverse(orientation) * normal;
- origin = Inverse(orientation) * (-normal * dist - position);
- normal = newnormal;
- dist = -dot(newnormal, origin);
- }
- //--------- utility functions -------------
- // RotationArc()
- // Given two vectors v0 and v1 this function
- // returns quaternion q where q*v0==v1.
- // Routine taken from game programming gems.
- Quaternion RotationArc(float3 v0, float3 v1)
- {
- Quaternion q;
- v0 = normalize(v0); // Comment these two lines out if you know its not needed.
- v1 = normalize(v1); // If vector is already unit length then why do it again?
- float3 c = cross(v0, v1);
- float d = dot(v0, v1);
- if (d <= -1.0f)
- {
- return Quaternion(1, 0, 0, 0);
- } // 180 about x axis
- float s = sqrtf((1 + d) * 2);
- q.x = c.x / s;
- q.y = c.y / s;
- q.z = c.z / s;
- q.w = s / 2.0f;
- return q;
- }
- float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v)
- {
- // builds a 4x4 transformation matrix based on orientation q and translation v
- float qx2 = q.x * q.x;
- float qy2 = q.y * q.y;
- float qz2 = q.z * q.z;
- float qxqy = q.x * q.y;
- float qxqz = q.x * q.z;
- float qxqw = q.x * q.w;
- float qyqz = q.y * q.z;
- float qyqw = q.y * q.w;
- float qzqw = q.z * q.w;
- return float4x4(
- 1 - 2 * (qy2 + qz2),
- 2 * (qxqy + qzqw),
- 2 * (qxqz - qyqw),
- 0,
- 2 * (qxqy - qzqw),
- 1 - 2 * (qx2 + qz2),
- 2 * (qyqz + qxqw),
- 0,
- 2 * (qxqz + qyqw),
- 2 * (qyqz - qxqw),
- 1 - 2 * (qx2 + qy2),
- 0,
- v.x,
- v.y,
- v.z,
- 1.0f);
- }
- float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1)
- {
- // returns the point where the line p0-p1 intersects the plane n&d
- float3 dif;
- dif = p1 - p0;
- float dn = dot(plane.normal, dif);
- float t = -(plane.dist + dot(plane.normal, p0)) / dn;
- return p0 + (dif * t);
- }
- float3 PlaneProject(const Plane &plane, const float3 &point)
- {
- return point - plane.normal * (dot(point, plane.normal) + plane.dist);
- }
- float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a)
- {
- float3 w;
- w = p1 - p0;
- float t = dot(w, (a - p0)) / (sqr(w.x) + sqr(w.y) + sqr(w.z));
- return p0 + w * t;
- }
- float LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a)
- {
- float3 w;
- w = p1 - p0;
- float t = dot(w, (a - p0)) / (sqr(w.x) + sqr(w.y) + sqr(w.z));
- return t;
- }
- float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2)
- {
- // return the normal of the triangle
- // inscribed by v0, v1, and v2
- float3 cp = cross(v1 - v0, v2 - v1);
- float m = magnitude(cp);
- if (m == 0) return float3(1, 0, 0);
- return cp * (1.0f / m);
- }
- int BoxInside(const float3 &p, const float3 &bmin, const float3 &bmax)
- {
- return (p.x >= bmin.x && p.x <= bmax.x &&
- p.y >= bmin.y && p.y <= bmax.y &&
- p.z >= bmin.z && p.z <= bmax.z);
- }
- int BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax, float3 *impact)
- {
- if (BoxInside(v0, bmin, bmax))
- {
- *impact = v0;
- return 1;
- }
- if (v0.x <= bmin.x && v1.x >= bmin.x)
- {
- float a = (bmin.x - v0.x) / (v1.x - v0.x);
- //v.x = bmin.x;
- float vy = (1 - a) * v0.y + a * v1.y;
- float vz = (1 - a) * v0.z + a * v1.z;
- if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
- {
- impact->x = bmin.x;
- impact->y = vy;
- impact->z = vz;
- return 1;
- }
- }
- else if (v0.x >= bmax.x && v1.x <= bmax.x)
- {
- float a = (bmax.x - v0.x) / (v1.x - v0.x);
- //v.x = bmax.x;
- float vy = (1 - a) * v0.y + a * v1.y;
- float vz = (1 - a) * v0.z + a * v1.z;
- if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
- {
- impact->x = bmax.x;
- impact->y = vy;
- impact->z = vz;
- return 1;
- }
- }
- if (v0.y <= bmin.y && v1.y >= bmin.y)
- {
- float a = (bmin.y - v0.y) / (v1.y - v0.y);
- float vx = (1 - a) * v0.x + a * v1.x;
- //v.y = bmin.y;
- float vz = (1 - a) * v0.z + a * v1.z;
- if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
- {
- impact->x = vx;
- impact->y = bmin.y;
- impact->z = vz;
- return 1;
- }
- }
- else if (v0.y >= bmax.y && v1.y <= bmax.y)
- {
- float a = (bmax.y - v0.y) / (v1.y - v0.y);
- float vx = (1 - a) * v0.x + a * v1.x;
- // vy = bmax.y;
- float vz = (1 - a) * v0.z + a * v1.z;
- if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
- {
- impact->x = vx;
- impact->y = bmax.y;
- impact->z = vz;
- return 1;
- }
- }
- if (v0.z <= bmin.z && v1.z >= bmin.z)
- {
- float a = (bmin.z - v0.z) / (v1.z - v0.z);
- float vx = (1 - a) * v0.x + a * v1.x;
- float vy = (1 - a) * v0.y + a * v1.y;
- // v.z = bmin.z;
- if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
- {
- impact->x = vx;
- impact->y = vy;
- impact->z = bmin.z;
- return 1;
- }
- }
- else if (v0.z >= bmax.z && v1.z <= bmax.z)
- {
- float a = (bmax.z - v0.z) / (v1.z - v0.z);
- float vx = (1 - a) * v0.x + a * v1.x;
- float vy = (1 - a) * v0.y + a * v1.y;
- // v.z = bmax.z;
- if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
- {
- impact->x = vx;
- impact->y = vy;
- impact->z = bmax.z;
- return 1;
- }
- }
- return 0;
- }
- float DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint, float3 *vpoint)
- {
- float3 cp;
- cp = normalize(cross(udir, vdir));
- float distu = -dot(cp, ustart);
- float distv = -dot(cp, vstart);
- float dist = (float)fabs(distu - distv);
- if (upoint)
- {
- Plane plane;
- plane.normal = normalize(cross(vdir, cp));
- plane.dist = -dot(plane.normal, vstart);
- *upoint = PlaneLineIntersection(plane, ustart, ustart + udir);
- }
- if (vpoint)
- {
- Plane plane;
- plane.normal = normalize(cross(udir, cp));
- plane.dist = -dot(plane.normal, ustart);
- *vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir);
- }
- return dist;
- }
- Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir1, const float3 &dir2)
- {
- // routine taken from game programming gems.
- // Implement track ball functionality to spin stuf on the screen
- // cop center of projection
- // cor center of rotation
- // dir1 old mouse direction
- // dir2 new mouse direction
- // pretend there is a sphere around cor. Then find the points
- // where dir1 and dir2 intersect that sphere. Find the
- // rotation that takes the first point to the second.
- float m;
- // compute plane
- float3 nrml = cor - cop;
- float fudgefactor = 1.0f / (magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
- nrml = normalize(nrml);
- float dist = -dot(nrml, cor);
- float3 u = PlaneLineIntersection(Plane(nrml, dist), cop, cop + dir1);
- u = u - cor;
- u = u * fudgefactor;
- m = magnitude(u);
- if (m > 1)
- {
- u /= m;
- }
- else
- {
- u = u - (nrml * sqrtf(1 - m * m));
- }
- float3 v = PlaneLineIntersection(Plane(nrml, dist), cop, cop + dir2);
- v = v - cor;
- v = v * fudgefactor;
- m = magnitude(v);
- if (m > 1)
- {
- v /= m;
- }
- else
- {
- v = v - (nrml * sqrtf(1 - m * m));
- }
- return RotationArc(u, v);
- }
- int countpolyhit = 0;
- int PolyHit(const float3 *vert, const int n, const float3 &v0, const float3 &v1, float3 *impact, float3 *normal)
- {
- countpolyhit++;
- int i;
- float3 nrml(0, 0, 0);
- for (i = 0; i < n; i++)
- {
- int i1 = (i + 1) % n;
- int i2 = (i + 2) % n;
- nrml = nrml + cross(vert[i1] - vert[i], vert[i2] - vert[i1]);
- }
- float m = magnitude(nrml);
- if (m == 0.0)
- {
- return 0;
- }
- nrml = nrml * (1.0f / m);
- float dist = -dot(nrml, vert[0]);
- float d0, d1;
- if ((d0 = dot(v0, nrml) + dist) < 0 || (d1 = dot(v1, nrml) + dist) > 0)
- {
- return 0;
- }
- float3 the_point;
- // By using the cached plane distances d0 and d1
- // we can optimize the following:
- // the_point = planelineintersection(nrml,dist,v0,v1);
- float a = d0 / (d0 - d1);
- the_point = v0 * (1 - a) + v1 * a;
- int inside = 1;
- for (int j = 0; inside && j < n; j++)
- {
- // let inside = 0 if outside
- float3 pp1, pp2, side;
- pp1 = vert[j];
- pp2 = vert[(j + 1) % n];
- side = cross((pp2 - pp1), (the_point - pp1));
- inside = (dot(nrml, side) >= 0.0);
- }
- if (inside)
- {
- if (normal)
- {
- *normal = nrml;
- }
- if (impact)
- {
- *impact = the_point;
- }
- }
- return inside;
- }
- //**************************************************************************
- //**************************************************************************
- //*** Stan Melax's array template, needed to compile his hull generation code
- //**************************************************************************
- //**************************************************************************
- template <class Type>
- class ArrayRet;
- template <class Type>
- class Array
- {
- public:
- Array(int s = 0);
- Array(Array<Type> &array);
- Array(ArrayRet<Type> &array);
- ~Array();
- void allocate(int s);
- void SetSize(int s);
- void Pack();
- Type &Add(Type);
- void AddUnique(Type);
- int Contains(Type);
- void Insert(Type, int);
- int IndexOf(Type);
- void Remove(Type);
- void DelIndex(int i);
- Type *element;
- int count;
- int array_size;
- const Type &operator[](int i) const
- {
- assert(i >= 0 && i < count);
- return element[i];
- }
- Type &operator[](int i)
- {
- assert(i >= 0 && i < count);
- return element[i];
- }
- Type &Pop()
- {
- assert(count);
- count--;
- return element[count];
- }
- Array<Type> &operator=(Array<Type> &array);
- Array<Type> &operator=(ArrayRet<Type> &array);
- // operator ArrayRet<Type> &() { return *(ArrayRet<Type> *)this;} // this worked but i suspect could be dangerous
- };
- template <class Type>
- class ArrayRet : public Array<Type>
- {
- };
- template <class Type>
- Array<Type>::Array(int s)
- {
- count = 0;
- array_size = 0;
- element = NULL;
- if (s)
- {
- allocate(s);
- }
- }
- template <class Type>
- Array<Type>::Array(Array<Type> &array)
- {
- count = 0;
- array_size = 0;
- element = NULL;
- for (int i = 0; i < array.count; i++)
- {
- Add(array[i]);
- }
- }
- template <class Type>
- Array<Type>::Array(ArrayRet<Type> &array)
- {
- *this = array;
- }
- template <class Type>
- Array<Type> &Array<Type>::operator=(ArrayRet<Type> &array)
- {
- count = array.count;
- array_size = array.array_size;
- element = array.element;
- array.element = NULL;
- array.count = 0;
- array.array_size = 0;
- return *this;
- }
- template <class Type>
- Array<Type> &Array<Type>::operator=(Array<Type> &array)
- {
- count = 0;
- for (int i = 0; i < array.count; i++)
- {
- Add(array[i]);
- }
- return *this;
- }
- template <class Type>
- Array<Type>::~Array()
- {
- if (element != NULL)
- {
- free(element);
- }
- count = 0;
- array_size = 0;
- element = NULL;
- }
- template <class Type>
- void Array<Type>::allocate(int s)
- {
- assert(s > 0);
- assert(s >= count);
- Type *old = element;
- array_size = s;
- element = (Type *)malloc(sizeof(Type) * array_size);
- assert(element);
- for (int i = 0; i < count; i++)
- {
- element[i] = old[i];
- }
- if (old)
- {
- free(old);
- }
- }
- template <class Type>
- void Array<Type>::SetSize(int s)
- {
- if (s == 0)
- {
- if (element)
- {
- free(element);
- element = NULL;
- }
- array_size = s;
- }
- else
- {
- allocate(s);
- }
- count = s;
- }
- template <class Type>
- void Array<Type>::Pack()
- {
- allocate(count);
- }
- template <class Type>
- Type &Array<Type>::Add(Type t)
- {
- assert(count <= array_size);
- if (count == array_size)
- {
- allocate((array_size) ? array_size * 2 : 16);
- }
- element[count++] = t;
- return element[count - 1];
- }
- template <class Type>
- int Array<Type>::Contains(Type t)
- {
- int i;
- int found = 0;
- for (i = 0; i < count; i++)
- {
- if (element[i] == t) found++;
- }
- return found;
- }
- template <class Type>
- void Array<Type>::AddUnique(Type t)
- {
- if (!Contains(t)) Add(t);
- }
- template <class Type>
- void Array<Type>::DelIndex(int i)
- {
- assert(i < count);
- count--;
- while (i < count)
- {
- element[i] = element[i + 1];
- i++;
- }
- }
- template <class Type>
- void Array<Type>::Remove(Type t)
- {
- int i;
- for (i = 0; i < count; i++)
- {
- if (element[i] == t)
- {
- break;
- }
- }
- assert(i < count); // assert object t is in the array.
- DelIndex(i);
- for (i = 0; i < count; i++)
- {
- assert(element[i] != t);
- }
- }
- template <class Type>
- void Array<Type>::Insert(Type t, int k)
- {
- int i = count;
- Add(t); // to allocate space
- while (i > k)
- {
- element[i] = element[i - 1];
- i--;
- }
- assert(i == k);
- element[k] = t;
- }
- template <class Type>
- int Array<Type>::IndexOf(Type t)
- {
- int i;
- for (i = 0; i < count; i++)
- {
- if (element[i] == t)
- {
- return i;
- }
- }
- assert(0);
- return -1;
- }
- //*********************************************************************
- //*********************************************************************
- //******** Hull header
- //*********************************************************************
- //*********************************************************************
- class PHullResult
- {
- public:
- PHullResult(void)
- {
- mVcount = 0;
- mIndexCount = 0;
- mFaceCount = 0;
- mVertices = 0;
- mIndices = 0;
- }
- unsigned int mVcount;
- unsigned int mIndexCount;
- unsigned int mFaceCount;
- float *mVertices;
- unsigned int *mIndices;
- };
- #define REAL3 float3
- #define REAL float
- #define COPLANAR (0)
- #define UNDER (1)
- #define OVER (2)
- #define SPLIT (OVER | UNDER)
- #define PAPERWIDTH (0.001f)
- float planetestepsilon = PAPERWIDTH;
- class ConvexH
- {
- public:
- class HalfEdge
- {
- public:
- short ea; // the other half of the edge (index into edges list)
- unsigned char v; // the vertex at the start of this edge (index into vertices list)
- unsigned char p; // the facet on which this edge lies (index into facets list)
- HalfEdge() {}
- HalfEdge(short _ea, unsigned char _v, unsigned char _p) : ea(_ea), v(_v), p(_p) {}
- };
- Array<REAL3> vertices;
- Array<HalfEdge> edges;
- Array<Plane> facets;
- ConvexH(int vertices_size, int edges_size, int facets_size);
- };
- typedef ConvexH::HalfEdge HalfEdge;
- ConvexH::ConvexH(int vertices_size, int edges_size, int facets_size)
- : vertices(vertices_size), edges(edges_size), facets(facets_size)
- {
- vertices.count = vertices_size;
- edges.count = edges_size;
- facets.count = facets_size;
- }
- ConvexH *ConvexHDup(ConvexH *src)
- {
- ConvexH *dst = new ConvexH(src->vertices.count, src->edges.count, src->facets.count);
- memcpy(dst->vertices.element, src->vertices.element, sizeof(float3) * src->vertices.count);
- memcpy(dst->edges.element, src->edges.element, sizeof(HalfEdge) * src->edges.count);
- memcpy(dst->facets.element, src->facets.element, sizeof(Plane) * src->facets.count);
- return dst;
- }
- int PlaneTest(const Plane &p, const REAL3 &v)
- {
- REAL a = dot(v, p.normal) + p.dist;
- int flag = (a > planetestepsilon) ? OVER : ((a < -planetestepsilon) ? UNDER : COPLANAR);
- return flag;
- }
- int SplitTest(ConvexH &convex, const Plane &plane)
- {
- int flag = 0;
- for (int i = 0; i < convex.vertices.count; i++)
- {
- flag |= PlaneTest(plane, convex.vertices[i]);
- }
- return flag;
- }
- class VertFlag
- {
- public:
- unsigned char planetest;
- unsigned char junk;
- unsigned char undermap;
- unsigned char overmap;
- };
- class EdgeFlag
- {
- public:
- unsigned char planetest;
- unsigned char fixes;
- short undermap;
- short overmap;
- };
- class PlaneFlag
- {
- public:
- unsigned char undermap;
- unsigned char overmap;
- };
- class Coplanar
- {
- public:
- unsigned short ea;
- unsigned char v0;
- unsigned char v1;
- };
- int AssertIntact(ConvexH &convex)
- {
- int i;
- int estart = 0;
- for (i = 0; i < convex.edges.count; i++)
- {
- if (convex.edges[estart].p != convex.edges[i].p)
- {
- estart = i;
- }
- int inext = i + 1;
- if (inext >= convex.edges.count || convex.edges[inext].p != convex.edges[i].p)
- {
- inext = estart;
- }
- assert(convex.edges[inext].p == convex.edges[i].p);
- int nb = convex.edges[i].ea;
- assert(nb != 255);
- if (nb == 255 || nb == -1) return 0;
- assert(nb != -1);
- assert(i == convex.edges[nb].ea);
- }
- for (i = 0; i < convex.edges.count; i++)
- {
- assert(COPLANAR == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v]));
- if (COPLANAR != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v])) return 0;
- if (convex.edges[estart].p != convex.edges[i].p)
- {
- estart = i;
- }
- int i1 = i + 1;
- if (i1 >= convex.edges.count || convex.edges[i1].p != convex.edges[i].p)
- {
- i1 = estart;
- }
- int i2 = i1 + 1;
- if (i2 >= convex.edges.count || convex.edges[i2].p != convex.edges[i].p)
- {
- i2 = estart;
- }
- if (i == i2) continue; // i sliced tangent to an edge and created 2 meaningless edges
- REAL3 localnormal = TriNormal(convex.vertices[convex.edges[i].v],
- convex.vertices[convex.edges[i1].v],
- convex.vertices[convex.edges[i2].v]);
- assert(dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0);
- if (dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0) return 0;
- }
- return 1;
- }
- // back to back quads
- ConvexH *test_btbq()
- {
- ConvexH *convex = new ConvexH(4, 8, 2);
- convex->vertices[0] = REAL3(0, 0, 0);
- convex->vertices[1] = REAL3(1, 0, 0);
- convex->vertices[2] = REAL3(1, 1, 0);
- convex->vertices[3] = REAL3(0, 1, 0);
- convex->facets[0] = Plane(REAL3(0, 0, 1), 0);
- convex->facets[1] = Plane(REAL3(0, 0, -1), 0);
- convex->edges[0] = HalfEdge(7, 0, 0);
- convex->edges[1] = HalfEdge(6, 1, 0);
- convex->edges[2] = HalfEdge(5, 2, 0);
- convex->edges[3] = HalfEdge(4, 3, 0);
- convex->edges[4] = HalfEdge(3, 0, 1);
- convex->edges[5] = HalfEdge(2, 3, 1);
- convex->edges[6] = HalfEdge(1, 2, 1);
- convex->edges[7] = HalfEdge(0, 1, 1);
- AssertIntact(*convex);
- return convex;
- }
- ConvexH *test_cube()
- {
- ConvexH *convex = new ConvexH(8, 24, 6);
- convex->vertices[0] = REAL3(0, 0, 0);
- convex->vertices[1] = REAL3(0, 0, 1);
- convex->vertices[2] = REAL3(0, 1, 0);
- convex->vertices[3] = REAL3(0, 1, 1);
- convex->vertices[4] = REAL3(1, 0, 0);
- convex->vertices[5] = REAL3(1, 0, 1);
- convex->vertices[6] = REAL3(1, 1, 0);
- convex->vertices[7] = REAL3(1, 1, 1);
- convex->facets[0] = Plane(REAL3(-1, 0, 0), 0);
- convex->facets[1] = Plane(REAL3(1, 0, 0), -1);
- convex->facets[2] = Plane(REAL3(0, -1, 0), 0);
- convex->facets[3] = Plane(REAL3(0, 1, 0), -1);
- convex->facets[4] = Plane(REAL3(0, 0, -1), 0);
- convex->facets[5] = Plane(REAL3(0, 0, 1), -1);
- convex->edges[0] = HalfEdge(11, 0, 0);
- convex->edges[1] = HalfEdge(23, 1, 0);
- convex->edges[2] = HalfEdge(15, 3, 0);
- convex->edges[3] = HalfEdge(16, 2, 0);
- convex->edges[4] = HalfEdge(13, 6, 1);
- convex->edges[5] = HalfEdge(21, 7, 1);
- convex->edges[6] = HalfEdge(9, 5, 1);
- convex->edges[7] = HalfEdge(18, 4, 1);
- convex->edges[8] = HalfEdge(19, 0, 2);
- convex->edges[9] = HalfEdge(6, 4, 2);
- convex->edges[10] = HalfEdge(20, 5, 2);
- convex->edges[11] = HalfEdge(0, 1, 2);
- convex->edges[12] = HalfEdge(22, 3, 3);
- convex->edges[13] = HalfEdge(4, 7, 3);
- convex->edges[14] = HalfEdge(17, 6, 3);
- convex->edges[15] = HalfEdge(2, 2, 3);
- convex->edges[16] = HalfEdge(3, 0, 4);
- convex->edges[17] = HalfEdge(14, 2, 4);
- convex->edges[18] = HalfEdge(7, 6, 4);
- convex->edges[19] = HalfEdge(8, 4, 4);
- convex->edges[20] = HalfEdge(10, 1, 5);
- convex->edges[21] = HalfEdge(5, 5, 5);
- convex->edges[22] = HalfEdge(12, 7, 5);
- convex->edges[23] = HalfEdge(1, 3, 5);
- return convex;
- }
- ConvexH *ConvexHMakeCube(const REAL3 &bmin, const REAL3 &bmax)
- {
- ConvexH *convex = test_cube();
- convex->vertices[0] = REAL3(bmin.x, bmin.y, bmin.z);
- convex->vertices[1] = REAL3(bmin.x, bmin.y, bmax.z);
- convex->vertices[2] = REAL3(bmin.x, bmax.y, bmin.z);
- convex->vertices[3] = REAL3(bmin.x, bmax.y, bmax.z);
- convex->vertices[4] = REAL3(bmax.x, bmin.y, bmin.z);
- convex->vertices[5] = REAL3(bmax.x, bmin.y, bmax.z);
- convex->vertices[6] = REAL3(bmax.x, bmax.y, bmin.z);
- convex->vertices[7] = REAL3(bmax.x, bmax.y, bmax.z);
- convex->facets[0] = Plane(REAL3(-1, 0, 0), bmin.x);
- convex->facets[1] = Plane(REAL3(1, 0, 0), -bmax.x);
- convex->facets[2] = Plane(REAL3(0, -1, 0), bmin.y);
- convex->facets[3] = Plane(REAL3(0, 1, 0), -bmax.y);
- convex->facets[4] = Plane(REAL3(0, 0, -1), bmin.z);
- convex->facets[5] = Plane(REAL3(0, 0, 1), -bmax.z);
- return convex;
- }
- ConvexH *ConvexHCrop(ConvexH &convex, const Plane &slice)
- {
- int i;
- int vertcountunder = 0;
- int vertcountover = 0;
- Array<int> vertscoplanar; // existing vertex members of convex that are coplanar
- vertscoplanar.count = 0;
- Array<int> edgesplit; // existing edges that members of convex that cross the splitplane
- edgesplit.count = 0;
- assert(convex.edges.count < 480);
- EdgeFlag edgeflag[512];
- VertFlag vertflag[256];
- PlaneFlag planeflag[128];
- HalfEdge tmpunderedges[512];
- Plane tmpunderplanes[128];
- Coplanar coplanaredges[512];
- int coplanaredges_num = 0;
- Array<REAL3> createdverts;
- // do the side-of-plane tests
- for (i = 0; i < convex.vertices.count; i++)
- {
- vertflag[i].planetest = PlaneTest(slice, convex.vertices[i]);
- if (vertflag[i].planetest == COPLANAR)
- {
- // ? vertscoplanar.Add(i);
- vertflag[i].undermap = vertcountunder++;
- vertflag[i].overmap = vertcountover++;
- }
- else if (vertflag[i].planetest == UNDER)
- {
- vertflag[i].undermap = vertcountunder++;
- }
- else
- {
- assert(vertflag[i].planetest == OVER);
- vertflag[i].overmap = vertcountover++;
- vertflag[i].undermap = 255; // for debugging purposes
- }
- }
- int vertcountunderold = vertcountunder; // for debugging only
- int under_edge_count = 0;
- int underplanescount = 0;
- int e0 = 0;
- for (int currentplane = 0; currentplane < convex.facets.count; currentplane++)
- {
- int estart = e0;
- int enextface = 0;
- int planeside = 0;
- int e1 = e0 + 1;
- int vout = -1;
- int vin = -1;
- int coplanaredge = -1;
- do
- {
- if (e1 >= convex.edges.count || convex.edges[e1].p != currentplane)
- {
- enextface = e1;
- e1 = estart;
- }
- HalfEdge &edge0 = convex.edges[e0];
- HalfEdge &edge1 = convex.edges[e1];
- HalfEdge &edgea = convex.edges[edge0.ea];
- planeside |= vertflag[edge0.v].planetest;
- //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) {
- // assert(ecop==-1);
- // ecop=e;
- //}
- if (vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == OVER)
- {
- // both endpoints over plane
- edgeflag[e0].undermap = -1;
- }
- else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == UNDER)
- {
- // at least one endpoint under, the other coplanar or under
- edgeflag[e0].undermap = under_edge_count;
- tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
- tmpunderedges[under_edge_count].p = underplanescount;
- if (edge0.ea < e0)
- {
- // connect the neighbors
- assert(edgeflag[edge0.ea].undermap != -1);
- tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
- tmpunderedges[edgeflag[edge0.ea].undermap].ea = under_edge_count;
- }
- under_edge_count++;
- }
- else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == COPLANAR)
- {
- // both endpoints coplanar
- // must check a 3rd point to see if UNDER
- int e2 = e1 + 1;
- if (e2 >= convex.edges.count || convex.edges[e2].p != currentplane)
- {
- e2 = estart;
- }
- assert(convex.edges[e2].p == currentplane);
- HalfEdge &edge2 = convex.edges[e2];
- if (vertflag[edge2.v].planetest == UNDER)
- {
- edgeflag[e0].undermap = under_edge_count;
- tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
- tmpunderedges[under_edge_count].p = underplanescount;
- tmpunderedges[under_edge_count].ea = -1;
- // make sure this edge is added to the "coplanar" list
- coplanaredge = under_edge_count;
- vout = vertflag[edge0.v].undermap;
- vin = vertflag[edge1.v].undermap;
- under_edge_count++;
- }
- else
- {
- edgeflag[e0].undermap = -1;
- }
- }
- else if (vertflag[edge0.v].planetest == UNDER && vertflag[edge1.v].planetest == OVER)
- {
- // first is under 2nd is over
- edgeflag[e0].undermap = under_edge_count;
- tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
- tmpunderedges[under_edge_count].p = underplanescount;
- if (edge0.ea < e0)
- {
- assert(edgeflag[edge0.ea].undermap != -1);
- // connect the neighbors
- tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
- tmpunderedges[edgeflag[edge0.ea].undermap].ea = under_edge_count;
- vout = tmpunderedges[edgeflag[edge0.ea].undermap].v;
- }
- else
- {
- Plane &p0 = convex.facets[edge0.p];
- Plane &pa = convex.facets[edgea.p];
- createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
- //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
- //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
- vout = vertcountunder++;
- }
- under_edge_count++;
- /// hmmm something to think about: i might be able to output this edge regarless of
- // wheter or not we know v-in yet. ok i;ll try this now:
- tmpunderedges[under_edge_count].v = vout;
- tmpunderedges[under_edge_count].p = underplanescount;
- tmpunderedges[under_edge_count].ea = -1;
- coplanaredge = under_edge_count;
- under_edge_count++;
- if (vin != -1)
- {
- // we previously processed an edge where we came under
- // now we know about vout as well
- // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
- }
- }
- else if (vertflag[edge0.v].planetest == COPLANAR && vertflag[edge1.v].planetest == OVER)
- {
- // first is coplanar 2nd is over
- edgeflag[e0].undermap = -1;
- vout = vertflag[edge0.v].undermap;
- // I hate this but i have to make sure part of this face is UNDER before ouputting this vert
- int k = estart;
- assert(edge0.p == currentplane);
- while (!(planeside & UNDER) && k < convex.edges.count && convex.edges[k].p == edge0.p)
- {
- planeside |= vertflag[convex.edges[k].v].planetest;
- k++;
- }
- if (planeside & UNDER)
- {
- tmpunderedges[under_edge_count].v = vout;
- tmpunderedges[under_edge_count].p = underplanescount;
- tmpunderedges[under_edge_count].ea = -1;
- coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on
- under_edge_count++;
- }
- }
- else if (vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == UNDER)
- {
- // first is over next is under
- // new vertex!!!
- assert(vin == -1);
- if (e0 < edge0.ea)
- {
- Plane &p0 = convex.facets[edge0.p];
- Plane &pa = convex.facets[edgea.p];
- createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
- //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
- //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
- vin = vertcountunder++;
- }
- else
- {
- // find the new vertex that was created by edge[edge0.ea]
- int nea = edgeflag[edge0.ea].undermap;
- assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p);
- vin = tmpunderedges[nea + 1].v;
- assert(vin < vertcountunder);
- assert(vin >= vertcountunderold); // for debugging only
- }
- if (vout != -1)
- {
- // we previously processed an edge where we went over
- // now we know vin too
- // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
- }
- // output edge
- tmpunderedges[under_edge_count].v = vin;
- tmpunderedges[under_edge_count].p = underplanescount;
- edgeflag[e0].undermap = under_edge_count;
- if (e0 > edge0.ea)
- {
- assert(edgeflag[edge0.ea].undermap != -1);
- // connect the neighbors
- tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
- tmpunderedges[edgeflag[edge0.ea].undermap].ea = under_edge_count;
- }
- assert(edgeflag[e0].undermap == under_edge_count);
- under_edge_count++;
- }
- else if (vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == COPLANAR)
- {
- // first is over next is coplanar
- edgeflag[e0].undermap = -1;
- vin = vertflag[edge1.v].undermap;
- assert(vin != -1);
- if (vout != -1)
- {
- // we previously processed an edge where we came under
- // now we know both endpoints
- // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
- }
- }
- else
- {
- assert(0);
- }
- e0 = e1;
- e1++; // do the modulo at the beginning of the loop
- } while (e0 != estart);
- e0 = enextface;
- if (planeside & UNDER)
- {
- planeflag[currentplane].undermap = underplanescount;
- tmpunderplanes[underplanescount] = convex.facets[currentplane];
- underplanescount++;
- }
- else
- {
- planeflag[currentplane].undermap = 0;
- }
- if (vout >= 0 && (planeside & UNDER))
- {
- assert(vin >= 0);
- assert(coplanaredge >= 0);
- assert(coplanaredge != 511);
- coplanaredges[coplanaredges_num].ea = coplanaredge;
- coplanaredges[coplanaredges_num].v0 = vin;
- coplanaredges[coplanaredges_num].v1 = vout;
- coplanaredges_num++;
- }
- }
- // add the new plane to the mix:
- if (coplanaredges_num > 0)
- {
- tmpunderplanes[underplanescount++] = slice;
- }
- for (i = 0; i < coplanaredges_num - 1; i++)
- {
- if (coplanaredges[i].v1 != coplanaredges[i + 1].v0)
- {
- int j = 0;
- for (j = i + 2; j < coplanaredges_num; j++)
- {
- if (coplanaredges[i].v1 == coplanaredges[j].v0)
- {
- Coplanar tmp = coplanaredges[i + 1];
- coplanaredges[i + 1] = coplanaredges[j];
- coplanaredges[j] = tmp;
- break;
- }
- }
- if (j >= coplanaredges_num)
- {
- assert(j < coplanaredges_num);
- return NULL;
- }
- }
- }
- ConvexH *punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount);
- ConvexH &under = *punder;
- int k = 0;
- for (i = 0; i < convex.vertices.count; i++)
- {
- if (vertflag[i].planetest != OVER)
- {
- under.vertices[k++] = convex.vertices[i];
- }
- }
- i = 0;
- while (k < vertcountunder)
- {
- under.vertices[k++] = createdverts[i++];
- }
- assert(i == createdverts.count);
- for (i = 0; i < coplanaredges_num; i++)
- {
- under.edges[under_edge_count + i].p = underplanescount - 1;
- under.edges[under_edge_count + i].ea = coplanaredges[i].ea;
- tmpunderedges[coplanaredges[i].ea].ea = under_edge_count + i;
- under.edges[under_edge_count + i].v = coplanaredges[i].v0;
- }
- memcpy(under.edges.element, tmpunderedges, sizeof(HalfEdge) * under_edge_count);
- memcpy(under.facets.element, tmpunderplanes, sizeof(Plane) * underplanescount);
- return punder;
- }
- static int candidateplane(Plane *planes, int planes_count, ConvexH *convex, float epsilon)
- {
- int p = 0;
- REAL md = 0;
- int i;
- for (i = 0; i < planes_count; i++)
- {
- REAL d = 0;
- for (int j = 0; j < convex->vertices.count; j++)
- {
- d = Max(d, dot(convex->vertices[j], planes[i].normal) + planes[i].dist);
- }
- if (i == 0 || d > md)
- {
- p = i;
- md = d;
- }
- }
- return (md > epsilon) ? p : -1;
- }
- template <class T>
- inline int maxdir(const T *p, int count, const T &dir)
- {
- assert(count);
- int m = 0;
- float currDotm = dot(p[0], dir);
- for (int i = 1; i < count; i++)
- {
- const float currDoti = dot(p[i], dir);
- if (currDoti > currDotm)
- {
- currDotm = currDoti;
- m = i;
- }
- }
- return m;
- }
- template <class T>
- int maxdirfiltered(const T *p, int count, const T &dir, Array<int> &allow)
- {
- assert(count);
- int m = -1;
- float currDotm = dot(p[0], dir);
- for (int i = 0; i < count; i++)
- {
- if (allow[i])
- {
- if (m == -1)
- {
- currDotm = dot(p[i], dir);
- m = i;
- }
- else
- {
- const float currDoti = dot(p[i], dir);
- if (currDoti > currDotm)
- {
- currDotm = currDoti;
- m = i;
- }
- }
- }
- }
- assert(m != -1);
- return m;
- }
- float3 orth(const float3 &v)
- {
- float3 a = cross(v, float3(0, 0, 1));
- float3 b = cross(v, float3(0, 1, 0));
- return normalize((magnitude(a) > magnitude(b)) ? a : b);
- }
- template <class T>
- int maxdirsterid(const T *p, int count, const T &dir, Array<int> &allow)
- {
- int m = -1;
- while (m == -1)
- {
- m = maxdirfiltered(p, count, dir, allow);
- if (allow[m] == 3) return m;
- T u = orth(dir);
- T v = cross(u, dir);
- int ma = -1;
- for (float x = 0.0f; x <= 360.0f; x += 45.0f)
- {
- float s = sinf(DEG2RAD * (x));
- float c = cosf(DEG2RAD * (x));
- int mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
- if (ma == m && mb == m)
- {
- allow[m] = 3;
- return m;
- }
- if (ma != -1 && ma != mb) // Yuck - this is really ugly
- {
- int mc = ma;
- for (float xx = x - 40.0f; xx <= x; xx += 5.0f)
- {
- float s = sinf(DEG2RAD * (xx));
- float c = cosf(DEG2RAD * (xx));
- int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
- if (mc == m && md == m)
- {
- allow[m] = 3;
- return m;
- }
- mc = md;
- }
- }
- ma = mb;
- }
- allow[m] = 0;
- m = -1;
- }
- assert(0);
- return m;
- }
- int operator==(const int3 &a, const int3 &b)
- {
- for (int i = 0; i < 3; i++)
- {
- if (a[i] != b[i]) return 0;
- }
- return 1;
- }
- int3 roll3(int3 a)
- {
- int tmp = a[0];
- a[0] = a[1];
- a[1] = a[2];
- a[2] = tmp;
- return a;
- }
- int isa(const int3 &a, const int3 &b)
- {
- return (a == b || roll3(a) == b || a == roll3(b));
- }
- int b2b(const int3 &a, const int3 &b)
- {
- return isa(a, int3(b[2], b[1], b[0]));
- }
- int above(float3 *vertices, const int3 &t, const float3 &p, float epsilon)
- {
- float3 n = TriNormal(vertices[t[0]], vertices[t[1]], vertices[t[2]]);
- return (dot(n, p - vertices[t[0]]) > epsilon); // EPSILON???
- }
- int hasedge(const int3 &t, int a, int b)
- {
- for (int i = 0; i < 3; i++)
- {
- int i1 = (i + 1) % 3;
- if (t[i] == a && t[i1] == b) return 1;
- }
- return 0;
- }
- int hasvert(const int3 &t, int v)
- {
- return (t[0] == v || t[1] == v || t[2] == v);
- }
- int shareedge(const int3 &a, const int3 &b)
- {
- int i;
- for (i = 0; i < 3; i++)
- {
- int i1 = (i + 1) % 3;
- if (hasedge(a, b[i1], b[i])) return 1;
- }
- return 0;
- }
- class btHullTriangle;
- //Array<btHullTriangle*> tris;
- class btHullTriangle : public int3
- {
- public:
- int3 n;
- int id;
- int vmax;
- float rise;
- Array<btHullTriangle *> *tris;
- btHullTriangle(int a, int b, int c, Array<btHullTriangle *> *pTris) : int3(a, b, c), n(-1, -1, -1)
- {
- tris = pTris;
- id = tris->count;
- tris->Add(this);
- vmax = -1;
- rise = 0.0f;
- }
- ~btHullTriangle()
- {
- assert((*tris)[id] == this);
- (*tris)[id] = NULL;
- }
- int &neib(int a, int b);
- };
- int &btHullTriangle::neib(int a, int b)
- {
- static int er = -1;
- int i;
- for (i = 0; i < 3; i++)
- {
- int i1 = (i + 1) % 3;
- int i2 = (i + 2) % 3;
- if ((*this)[i] == a && (*this)[i1] == b) return n[i2];
- if ((*this)[i] == b && (*this)[i1] == a) return n[i2];
- }
- assert(0);
- return er;
- }
- void b2bfix(btHullTriangle *s, btHullTriangle *t, Array<btHullTriangle *> &tris)
- {
- int i;
- for (i = 0; i < 3; i++)
- {
- int i1 = (i + 1) % 3;
- int i2 = (i + 2) % 3;
- int a = (*s)[i1];
- int b = (*s)[i2];
- assert(tris[s->neib(a, b)]->neib(b, a) == s->id);
- assert(tris[t->neib(a, b)]->neib(b, a) == t->id);
- tris[s->neib(a, b)]->neib(b, a) = t->neib(b, a);
- tris[t->neib(b, a)]->neib(a, b) = s->neib(a, b);
- }
- }
- void removeb2b(btHullTriangle *s, btHullTriangle *t, Array<btHullTriangle *> &tris)
- {
- b2bfix(s, t, tris);
- delete s;
- delete t;
- }
- void checkit(btHullTriangle *t, Array<btHullTriangle *> &tris)
- {
- int i;
- assert(tris[t->id] == t);
- for (i = 0; i < 3; i++)
- {
- int i1 = (i + 1) % 3;
- int i2 = (i + 2) % 3;
- int a = (*t)[i1];
- int b = (*t)[i2];
- assert(a != b);
- assert(tris[t->n[i]]->neib(b, a) == t->id);
- }
- }
- void extrude(btHullTriangle *t0, int v, Array<btHullTriangle *> &tris)
- {
- int3 t = *t0;
- int n = tris.count;
- btHullTriangle *ta = new btHullTriangle(v, t[1], t[2], &tris);
- ta->n = int3(t0->n[0], n + 1, n + 2);
- tris[t0->n[0]]->neib(t[1], t[2]) = n + 0;
- btHullTriangle *tb = new btHullTriangle(v, t[2], t[0], &tris);
- tb->n = int3(t0->n[1], n + 2, n + 0);
- tris[t0->n[1]]->neib(t[2], t[0]) = n + 1;
- btHullTriangle *tc = new btHullTriangle(v, t[0], t[1], &tris);
- tc->n = int3(t0->n[2], n + 0, n + 1);
- tris[t0->n[2]]->neib(t[0], t[1]) = n + 2;
- checkit(ta, tris);
- checkit(tb, tris);
- checkit(tc, tris);
- if (hasvert(*tris[ta->n[0]], v)) removeb2b(ta, tris[ta->n[0]], tris);
- if (hasvert(*tris[tb->n[0]], v)) removeb2b(tb, tris[tb->n[0]], tris);
- if (hasvert(*tris[tc->n[0]], v)) removeb2b(tc, tris[tc->n[0]], tris);
- delete t0;
- }
- btHullTriangle *extrudable(float epsilon, Array<btHullTriangle *> &tris)
- {
- int i;
- btHullTriangle *t = NULL;
- for (i = 0; i < tris.count; i++)
- {
- if (!t || (tris[i] && t->rise < tris[i]->rise))
- {
- t = tris[i];
- }
- }
- return (t->rise > epsilon) ? t : NULL;
- }
- class int4
- {
- public:
- int x, y, z, w;
- int4(){};
- int4(int _x, int _y, int _z, int _w)
- {
- x = _x;
- y = _y;
- z = _z;
- w = _w;
- }
- const int &operator[](int i) const { return (&x)[i]; }
- int &operator[](int i) { return (&x)[i]; }
- };
- int4 FindSimplex(float3 *verts, int verts_count, Array<int> &allow)
- {
- float3 basis[3];
- basis[0] = float3(0.01f, 0.02f, 1.0f);
- int p0 = maxdirsterid(verts, verts_count, basis[0], allow);
- int p1 = maxdirsterid(verts, verts_count, -basis[0], allow);
- basis[0] = verts[p0] - verts[p1];
- if (p0 == p1 || basis[0] == float3(0, 0, 0))
- return int4(-1, -1, -1, -1);
- basis[1] = cross(float3(1, 0.02f, 0), basis[0]);
- basis[2] = cross(float3(-0.02f, 1, 0), basis[0]);
- basis[1] = normalize((magnitude(basis[1]) > magnitude(basis[2])) ? basis[1] : basis[2]);
- int p2 = maxdirsterid(verts, verts_count, basis[1], allow);
- if (p2 == p0 || p2 == p1)
- {
- p2 = maxdirsterid(verts, verts_count, -basis[1], allow);
- }
- if (p2 == p0 || p2 == p1)
- return int4(-1, -1, -1, -1);
- basis[1] = verts[p2] - verts[p0];
- basis[2] = normalize(cross(basis[1], basis[0]));
- int p3 = maxdirsterid(verts, verts_count, basis[2], allow);
- if (p3 == p0 || p3 == p1 || p3 == p2) p3 = maxdirsterid(verts, verts_count, -basis[2], allow);
- if (p3 == p0 || p3 == p1 || p3 == p2)
- return int4(-1, -1, -1, -1);
- assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3));
- if (dot(verts[p3] - verts[p0], cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0)
- {
- Swap(p2, p3);
- }
- return int4(p0, p1, p2, p3);
- }
- int calchullgen(float3 *verts, int verts_count, int vlimit, Array<btHullTriangle *> &tris)
- {
- if (verts_count < 4) return 0;
- if (vlimit == 0) vlimit = 1000000000;
- int j;
- float3 bmin(*verts), bmax(*verts);
- Array<int> isextreme(verts_count);
- Array<int> allow(verts_count);
- for (j = 0; j < verts_count; j++)
- {
- allow.Add(1);
- isextreme.Add(0);
- bmin = VectorMin(bmin, verts[j]);
- bmax = VectorMax(bmax, verts[j]);
- }
- float epsilon = magnitude(bmax - bmin) * 0.001f;
- int4 p = FindSimplex(verts, verts_count, allow);
- if (p.x == -1) return 0; // simplex failed
- float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point
- btHullTriangle *t0 = new btHullTriangle(p[2], p[3], p[1], &tris);
- t0->n = int3(2, 3, 1);
- btHullTriangle *t1 = new btHullTriangle(p[3], p[2], p[0], &tris);
- t1->n = int3(3, 2, 0);
- btHullTriangle *t2 = new btHullTriangle(p[0], p[1], p[3], &tris);
- t2->n = int3(0, 1, 3);
- btHullTriangle *t3 = new btHullTriangle(p[1], p[0], p[2], &tris);
- t3->n = int3(1, 0, 2);
- isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1;
- checkit(t0, tris);
- checkit(t1, tris);
- checkit(t2, tris);
- checkit(t3, tris);
- for (j = 0; j < tris.count; j++)
- {
- btHullTriangle *t = tris[j];
- assert(t);
- assert(t->vmax < 0);
- float3 n = TriNormal(verts[(*t)[0]], verts[(*t)[1]], verts[(*t)[2]]);
- t->vmax = maxdirsterid(verts, verts_count, n, allow);
- t->rise = dot(n, verts[t->vmax] - verts[(*t)[0]]);
- }
- btHullTriangle *te;
- vlimit -= 4;
- while (vlimit > 0 && (te = extrudable(epsilon, tris)))
- {
- // int3 ti=*te;
- int v = te->vmax;
- assert(!isextreme[v]); // wtf we've already done this vertex
- isextreme[v] = 1;
- //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
- j = tris.count;
- while (j--)
- {
- if (!tris[j]) continue;
- int3 t = *tris[j];
- if (above(verts, t, verts[v], 0.01f * epsilon))
- {
- extrude(tris[j], v, tris);
- }
- }
- // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
- j = tris.count;
- while (j--)
- {
- if (!tris[j]) continue;
- if (!hasvert(*tris[j], v)) break;
- int3 nt = *tris[j];
- if (above(verts, nt, center, 0.01f * epsilon) || magnitude(cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f)
- {
- btHullTriangle *nb = tris[tris[j]->n[0]];
- assert(nb);
- assert(!hasvert(*nb, v));
- assert(nb->id < j);
- extrude(nb, v, tris);
- j = tris.count;
- }
- }
- j = tris.count;
- while (j--)
- {
- btHullTriangle *t = tris[j];
- if (!t) continue;
- if (t->vmax >= 0) break;
- float3 n = TriNormal(verts[(*t)[0]], verts[(*t)[1]], verts[(*t)[2]]);
- t->vmax = maxdirsterid(verts, verts_count, n, allow);
- if (isextreme[t->vmax])
- {
- t->vmax = -1; // already done that vertex - algorithm needs to be able to terminate.
- }
- else
- {
- t->rise = dot(n, verts[t->vmax] - verts[(*t)[0]]);
- }
- }
- vlimit--;
- }
- return 1;
- }
- int calchull(float3 *verts, int verts_count, int *&tris_out, int &tris_count, int vlimit, Array<btHullTriangle *> &tris)
- {
- int rc = calchullgen(verts, verts_count, vlimit, tris);
- if (!rc) return 0;
- Array<int> ts;
- for (int i = 0; i < tris.count; i++)
- if (tris[i])
- {
- for (int j = 0; j < 3; j++) ts.Add((*tris[i])[j]);
- delete tris[i];
- }
- tris_count = ts.count / 3;
- tris_out = ts.element;
- ts.element = NULL;
- ts.count = ts.array_size = 0;
- tris.count = 0;
- return 1;
- }
- int calchullpbev(float3 *verts, int verts_count, int vlimit, Array<Plane> &planes, float bevangle, Array<btHullTriangle *> &tris)
- {
- int i, j;
- planes.count = 0;
- int rc = calchullgen(verts, verts_count, vlimit, tris);
- if (!rc) return 0;
- for (i = 0; i < tris.count; i++)
- if (tris[i])
- {
- Plane p;
- btHullTriangle *t = tris[i];
- p.normal = TriNormal(verts[(*t)[0]], verts[(*t)[1]], verts[(*t)[2]]);
- p.dist = -dot(p.normal, verts[(*t)[0]]);
- planes.Add(p);
- for (j = 0; j < 3; j++)
- {
- if (t->n[j] < t->id) continue;
- btHullTriangle *s = tris[t->n[j]];
- REAL3 snormal = TriNormal(verts[(*s)[0]], verts[(*s)[1]], verts[(*s)[2]]);
- if (dot(snormal, p.normal) >= cos(bevangle * DEG2RAD)) continue;
- REAL3 n = normalize(snormal + p.normal);
- planes.Add(Plane(n, -dot(n, verts[maxdir(verts, verts_count, n)])));
- }
- }
- for (i = 0; i < tris.count; i++)
- if (tris[i])
- {
- delete tris[i]; // delete tris[i];
- }
- tris.count = 0;
- return 1;
- }
- int overhull(Plane *planes, int planes_count, float3 *verts, int verts_count, int maxplanes,
- float3 *&verts_out, int &verts_count_out, int *&faces_out, int &faces_count_out, float inflate)
- {
- int i, j;
- if (verts_count < 4) return 0;
- maxplanes = Min(maxplanes, planes_count);
- float3 bmin(verts[0]), bmax(verts[0]);
- for (i = 0; i < verts_count; i++)
- {
- bmin = VectorMin(bmin, verts[i]);
- bmax = VectorMax(bmax, verts[i]);
- }
- // float diameter = magnitude(bmax-bmin);
- // inflate *=diameter; // RELATIVE INFLATION
- bmin -= float3(inflate, inflate, inflate);
- bmax += float3(inflate, inflate, inflate);
- for (i = 0; i < planes_count; i++)
- {
- planes[i].dist -= inflate;
- }
- float3 emin = bmin; // VectorMin(bmin,float3(0,0,0));
- float3 emax = bmax; // VectorMax(bmax,float3(0,0,0));
- float epsilon = magnitude(emax - emin) * 0.025f;
- planetestepsilon = magnitude(emax - emin) * PAPERWIDTH;
- // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think.
- // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter));
- ConvexH *c = ConvexHMakeCube(REAL3(bmin), REAL3(bmax));
- int k;
- while (maxplanes-- && (k = candidateplane(planes, planes_count, c, epsilon)) >= 0)
- {
- ConvexH *tmp = c;
- c = ConvexHCrop(*tmp, planes[k]);
- if (c == NULL)
- {
- c = tmp;
- break;
- } // might want to debug this case better!!!
- if (!AssertIntact(*c))
- {
- c = tmp;
- break;
- } // might want to debug this case better too!!!
- delete tmp;
- }
- assert(AssertIntact(*c));
- //return c;
- faces_out = (int *)malloc(sizeof(int) * (1 + c->facets.count + c->edges.count)); // new int[1+c->facets.count+c->edges.count];
- faces_count_out = 0;
- i = 0;
- faces_out[faces_count_out++] = -1;
- k = 0;
- while (i < c->edges.count)
- {
- j = 1;
- while (j + i < c->edges.count && c->edges[i].p == c->edges[i + j].p)
- {
- j++;
- }
- faces_out[faces_count_out++] = j;
- while (j--)
- {
- faces_out[faces_count_out++] = c->edges[i].v;
- i++;
- }
- k++;
- }
- faces_out[0] = k; // number of faces.
- assert(k == c->facets.count);
- assert(faces_count_out == 1 + c->facets.count + c->edges.count);
- verts_out = c->vertices.element; // new float3[c->vertices.count];
- verts_count_out = c->vertices.count;
- for (i = 0; i < c->vertices.count; i++)
- {
- verts_out[i] = float3(c->vertices[i]);
- }
- c->vertices.count = c->vertices.array_size = 0;
- c->vertices.element = NULL;
- delete c;
- return 1;
- }
- int overhullv(float3 *verts, int verts_count, int maxplanes,
- float3 *&verts_out, int &verts_count_out, int *&faces_out, int &faces_count_out, float inflate, float bevangle, int vlimit, Array<btHullTriangle *> &tris)
- {
- if (!verts_count) return 0;
- extern int calchullpbev(float3 * verts, int verts_count, int vlimit, Array<Plane> &planes, float bevangle, Array<btHullTriangle *> &tris);
- Array<Plane> planes;
- int rc = calchullpbev(verts, verts_count, vlimit, planes, bevangle, tris);
- if (!rc) return 0;
- return overhull(planes.element, planes.count, verts, verts_count, maxplanes, verts_out, verts_count_out, faces_out, faces_count_out, inflate);
- }
- bool ComputeHull(unsigned int vcount, const float *vertices, PHullResult &result, unsigned int vlimit, float inflate, Array<btHullTriangle *> &arrtris)
- {
- int index_count;
- int *faces;
- float3 *verts_out;
- int verts_count_out;
- if (inflate == 0.0f)
- {
- int *tris_out;
- int tris_count;
- int ret = calchull((float3 *)vertices, (int)vcount, tris_out, tris_count, vlimit, arrtris);
- if (!ret) return false;
- result.mIndexCount = (unsigned int)(tris_count * 3);
- result.mFaceCount = (unsigned int)tris_count;
- result.mVertices = (float *)vertices;
- result.mVcount = (unsigned int)vcount;
- result.mIndices = (unsigned int *)tris_out;
- return true;
- }
- int ret = overhullv((float3 *)vertices, vcount, 35, verts_out, verts_count_out, faces, index_count, inflate, 120.0f, vlimit, arrtris);
- if (!ret) return false;
- Array<int3> tris;
- int n = faces[0];
- int k = 1;
- for (int i = 0; i < n; i++)
- {
- int pn = faces[k++];
- for (int j = 2; j < pn; j++) tris.Add(int3(faces[k], faces[k + j - 1], faces[k + j]));
- k += pn;
- }
- assert(tris.count == index_count - 1 - (n * 3));
- result.mIndexCount = (unsigned int)(tris.count * 3);
- result.mFaceCount = (unsigned int)tris.count;
- result.mVertices = (float *)verts_out;
- result.mVcount = (unsigned int)verts_count_out;
- result.mIndices = (unsigned int *)tris.element;
- tris.element = NULL;
- tris.count = tris.array_size = 0;
- return true;
- }
- void ReleaseHull(PHullResult &result)
- {
- if (result.mIndices)
- {
- free(result.mIndices);
- }
- result.mVcount = 0;
- result.mIndexCount = 0;
- result.mIndices = 0;
- result.mVertices = 0;
- result.mIndices = 0;
- }
- //*********************************************************************
- //*********************************************************************
- //******** HullLib header
- //*********************************************************************
- //*********************************************************************
- //*********************************************************************
- //*********************************************************************
- //******** HullLib implementation
- //*********************************************************************
- //*********************************************************************
- HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request
- HullResult &result) // contains the resulst
- {
- HullError ret = QE_FAIL;
- PHullResult hr;
- unsigned int vcount = desc.mVcount;
- if (vcount < 8) vcount = 8;
- float *vsource = (float *)malloc(sizeof(float) * vcount * 3);
- float scale[3];
- unsigned int ovcount;
- bool ok = CleanupVertices(desc.mVcount, desc.mVertices, desc.mVertexStride, ovcount, vsource, desc.mNormalEpsilon, scale); // normalize point cloud, remove duplicates!
- if (ok)
- {
- if (1) // scale vertices back to their original size.
- {
- for (unsigned int i = 0; i < ovcount; i++)
- {
- float *v = &vsource[i * 3];
- v[0] *= scale[0];
- v[1] *= scale[1];
- v[2] *= scale[2];
- }
- }
- float skinwidth = 0;
- if (desc.HasHullFlag(QF_SKIN_WIDTH))
- skinwidth = desc.mSkinWidth;
- Array<btHullTriangle *> tris;
- ok = ComputeHull(ovcount, vsource, hr, desc.mMaxVertices, skinwidth, tris);
- if (ok)
- {
- // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
- float *vscratch = (float *)malloc(sizeof(float) * hr.mVcount * 3);
- BringOutYourDead(hr.mVertices, hr.mVcount, vscratch, ovcount, hr.mIndices, hr.mIndexCount);
- ret = QE_OK;
- if (desc.HasHullFlag(QF_TRIANGLES)) // if he wants the results as triangle!
- {
- result.mPolygons = false;
- result.mNumOutputVertices = ovcount;
- result.mOutputVertices = (float *)malloc(sizeof(float) * ovcount * 3);
- result.mNumFaces = hr.mFaceCount;
- result.mNumIndices = hr.mIndexCount;
- result.mIndices = (unsigned int *)malloc(sizeof(unsigned int) * hr.mIndexCount);
- memcpy(result.mOutputVertices, vscratch, sizeof(float) * 3 * ovcount);
- if (desc.HasHullFlag(QF_REVERSE_ORDER))
- {
- const unsigned int *source = hr.mIndices;
- unsigned int *dest = result.mIndices;
- for (unsigned int i = 0; i < hr.mFaceCount; i++)
- {
- dest[0] = source[2];
- dest[1] = source[1];
- dest[2] = source[0];
- dest += 3;
- source += 3;
- }
- }
- else
- {
- memcpy(result.mIndices, hr.mIndices, sizeof(unsigned int) * hr.mIndexCount);
- }
- }
- else
- {
- result.mPolygons = true;
- result.mNumOutputVertices = ovcount;
- result.mOutputVertices = (float *)malloc(sizeof(float) * ovcount * 3);
- result.mNumFaces = hr.mFaceCount;
- result.mNumIndices = hr.mIndexCount + hr.mFaceCount;
- result.mIndices = (unsigned int *)malloc(sizeof(unsigned int) * result.mNumIndices);
- memcpy(result.mOutputVertices, vscratch, sizeof(float) * 3 * ovcount);
- if (1)
- {
- const unsigned int *source = hr.mIndices;
- unsigned int *dest = result.mIndices;
- for (unsigned int i = 0; i < hr.mFaceCount; i++)
- {
- dest[0] = 3;
- if (desc.HasHullFlag(QF_REVERSE_ORDER))
- {
- dest[1] = source[2];
- dest[2] = source[1];
- dest[3] = source[0];
- }
- else
- {
- dest[1] = source[0];
- dest[2] = source[1];
- dest[3] = source[2];
- }
- dest += 4;
- source += 3;
- }
- }
- }
- ReleaseHull(hr);
- if (vscratch)
- {
- free(vscratch);
- }
- }
- }
- if (vsource)
- {
- free(vsource);
- }
- return ret;
- }
- HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it.
- {
- if (result.mOutputVertices)
- {
- free(result.mOutputVertices);
- result.mOutputVertices = 0;
- }
- if (result.mIndices)
- {
- free(result.mIndices);
- result.mIndices = 0;
- }
- return QE_OK;
- }
- static void addPoint(unsigned int &vcount, float *p, float x, float y, float z)
- {
- float *dest = &p[vcount * 3];
- dest[0] = x;
- dest[1] = y;
- dest[2] = z;
- vcount++;
- }
- float GetDist(float px, float py, float pz, const float *p2)
- {
- float dx = px - p2[0];
- float dy = py - p2[1];
- float dz = pz - p2[2];
- return dx * dx + dy * dy + dz * dz;
- }
- bool HullLibrary::CleanupVertices(unsigned int svcount,
- const float *svertices,
- unsigned int stride,
- unsigned int &vcount, // output number of vertices
- float *vertices, // location to store the results.
- float normalepsilon,
- float *scale)
- {
- if (svcount == 0) return false;
- #define EPSILON 0.000001f /* close enough to consider two floating point numbers to be 'the same'. */
- vcount = 0;
- float recip[3];
- if (scale)
- {
- scale[0] = 1;
- scale[1] = 1;
- scale[2] = 1;
- }
- float bmin[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
- float bmax[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- const char *vtx = (const char *)svertices;
- if (1)
- {
- for (unsigned int i = 0; i < svcount; i++)
- {
- const float *p = (const float *)vtx;
- vtx += stride;
- for (int j = 0; j < 3; j++)
- {
- if (p[j] < bmin[j]) bmin[j] = p[j];
- if (p[j] > bmax[j]) bmax[j] = p[j];
- }
- }
- }
- float dx = bmax[0] - bmin[0];
- float dy = bmax[1] - bmin[1];
- float dz = bmax[2] - bmin[2];
- float center[3];
- center[0] = dx * 0.5f + bmin[0];
- center[1] = dy * 0.5f + bmin[1];
- center[2] = dz * 0.5f + bmin[2];
- if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3)
- {
- float len = FLT_MAX;
- if (dx > EPSILON && dx < len) len = dx;
- if (dy > EPSILON && dy < len) len = dy;
- if (dz > EPSILON && dz < len) len = dz;
- if (len == FLT_MAX)
- {
- dx = dy = dz = 0.01f; // one centimeter
- }
- else
- {
- if (dx < EPSILON) dx = len * 0.05f; // 1/5th the shortest non-zero edge.
- if (dy < EPSILON) dy = len * 0.05f;
- if (dz < EPSILON) dz = len * 0.05f;
- }
- float x1 = center[0] - dx;
- float x2 = center[0] + dx;
- float y1 = center[1] - dy;
- float y2 = center[1] + dy;
- float z1 = center[2] - dz;
- float z2 = center[2] + dz;
- addPoint(vcount, vertices, x1, y1, z1);
- addPoint(vcount, vertices, x2, y1, z1);
- addPoint(vcount, vertices, x2, y2, z1);
- addPoint(vcount, vertices, x1, y2, z1);
- addPoint(vcount, vertices, x1, y1, z2);
- addPoint(vcount, vertices, x2, y1, z2);
- addPoint(vcount, vertices, x2, y2, z2);
- addPoint(vcount, vertices, x1, y2, z2);
- return true; // return cube
- }
- else
- {
- if (scale)
- {
- scale[0] = dx;
- scale[1] = dy;
- scale[2] = dz;
- recip[0] = 1 / dx;
- recip[1] = 1 / dy;
- recip[2] = 1 / dz;
- center[0] *= recip[0];
- center[1] *= recip[1];
- center[2] *= recip[2];
- }
- }
- vtx = (const char *)svertices;
- for (unsigned int i = 0; i < svcount; i++)
- {
- const float *p = (const float *)vtx;
- vtx += stride;
- float px = p[0];
- float py = p[1];
- float pz = p[2];
- if (scale)
- {
- px = px * recip[0]; // normalize
- py = py * recip[1]; // normalize
- pz = pz * recip[2]; // normalize
- }
- if (1)
- {
- unsigned int j;
- for (j = 0; j < vcount; j++)
- {
- float *v = &vertices[j * 3];
- float x = v[0];
- float y = v[1];
- float z = v[2];
- float dx = fabsf(x - px);
- float dy = fabsf(y - py);
- float dz = fabsf(z - pz);
- if (dx < normalepsilon && dy < normalepsilon && dz < normalepsilon)
- {
- // ok, it is close enough to the old one
- // now let us see if it is further from the center of the point cloud than the one we already recorded.
- // in which case we keep this one instead.
- float dist1 = GetDist(px, py, pz, center);
- float dist2 = GetDist(v[0], v[1], v[2], center);
- if (dist1 > dist2)
- {
- v[0] = px;
- v[1] = py;
- v[2] = pz;
- }
- break;
- }
- }
- if (j == vcount)
- {
- float *dest = &vertices[vcount * 3];
- dest[0] = px;
- dest[1] = py;
- dest[2] = pz;
- vcount++;
- }
- }
- }
- // ok..now make sure we didn't prune so many vertices it is now invalid.
- if (1)
- {
- float bmin[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
- float bmax[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- for (unsigned int i = 0; i < vcount; i++)
- {
- const float *p = &vertices[i * 3];
- for (int j = 0; j < 3; j++)
- {
- if (p[j] < bmin[j]) bmin[j] = p[j];
- if (p[j] > bmax[j]) bmax[j] = p[j];
- }
- }
- float dx = bmax[0] - bmin[0];
- float dy = bmax[1] - bmin[1];
- float dz = bmax[2] - bmin[2];
- if (dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3)
- {
- float cx = dx * 0.5f + bmin[0];
- float cy = dy * 0.5f + bmin[1];
- float cz = dz * 0.5f + bmin[2];
- float len = FLT_MAX;
- if (dx >= EPSILON && dx < len) len = dx;
- if (dy >= EPSILON && dy < len) len = dy;
- if (dz >= EPSILON && dz < len) len = dz;
- if (len == FLT_MAX)
- {
- dx = dy = dz = 0.01f; // one centimeter
- }
- else
- {
- if (dx < EPSILON) dx = len * 0.05f; // 1/5th the shortest non-zero edge.
- if (dy < EPSILON) dy = len * 0.05f;
- if (dz < EPSILON) dz = len * 0.05f;
- }
- float x1 = cx - dx;
- float x2 = cx + dx;
- float y1 = cy - dy;
- float y2 = cy + dy;
- float z1 = cz - dz;
- float z2 = cz + dz;
- vcount = 0; // add box
- addPoint(vcount, vertices, x1, y1, z1);
- addPoint(vcount, vertices, x2, y1, z1);
- addPoint(vcount, vertices, x2, y2, z1);
- addPoint(vcount, vertices, x1, y2, z1);
- addPoint(vcount, vertices, x1, y1, z2);
- addPoint(vcount, vertices, x2, y1, z2);
- addPoint(vcount, vertices, x2, y2, z2);
- addPoint(vcount, vertices, x1, y2, z2);
- return true;
- }
- }
- return true;
- }
- void HullLibrary::BringOutYourDead(const float *verts, unsigned int vcount, float *overts, unsigned int &ocount, unsigned int *indices, unsigned indexcount)
- {
- unsigned int *used = (unsigned int *)malloc(sizeof(unsigned int) * vcount);
- memset(used, 0, sizeof(unsigned int) * vcount);
- ocount = 0;
- for (unsigned int i = 0; i < indexcount; i++)
- {
- unsigned int v = indices[i]; // original array index
- assert(v >= 0 && v < vcount);
- if (used[v]) // if already remapped
- {
- indices[i] = used[v] - 1; // index to new array
- }
- else
- {
- indices[i] = ocount; // new index mapping
- overts[ocount * 3 + 0] = verts[v * 3 + 0]; // copy old vert to new vert array
- overts[ocount * 3 + 1] = verts[v * 3 + 1];
- overts[ocount * 3 + 2] = verts[v * 3 + 2];
- ocount++; // increment output vert count
- assert(ocount >= 0 && ocount <= vcount);
- used[v] = ocount; // assign new index remapping
- }
- }
- free(used);
- }
- } // namespace ConvexDecomposition
|