├── .gitattributes ├── .gitignore ├── MyMath.h ├── README.md ├── cAnimationController.cpp └── cAnimationController.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Azure Emulator 159 | efc/ 160 | rfc/ 161 | 162 | # Windows Store app package directory 163 | AppPackages/ 164 | 165 | # Visual Studio cache files 166 | # files ending in .cache can be ignored 167 | *.[Cc]ache 168 | # but keep track of directories ending in .cache 169 | !*.[Cc]ache/ 170 | 171 | # Others 172 | ClientBin/ 173 | [Ss]tyle[Cc]op.* 174 | ~$* 175 | *~ 176 | *.dbmdl 177 | *.dbproj.schemaview 178 | *.pfx 179 | *.publishsettings 180 | node_modules/ 181 | orleans.codegen.cs 182 | 183 | # RIA/Silverlight projects 184 | Generated_Code/ 185 | 186 | # Backup & report files from converting an old project file 187 | # to a newer Visual Studio version. Backup files are not needed, 188 | # because we have git ;-) 189 | _UpgradeReport_Files/ 190 | Backup*/ 191 | UpgradeLog*.XML 192 | UpgradeLog*.htm 193 | 194 | # SQL Server files 195 | *.mdf 196 | *.ldf 197 | 198 | # Business Intelligence projects 199 | *.rdl.data 200 | *.bim.layout 201 | *.bim_*.settings 202 | 203 | # Microsoft Fakes 204 | FakesAssemblies/ 205 | 206 | # GhostDoc plugin setting file 207 | *.GhostDoc.xml 208 | 209 | # Node.js Tools for Visual Studio 210 | .ntvs_analysis.dat 211 | 212 | # Visual Studio 6 build log 213 | *.plg 214 | 215 | # Visual Studio 6 workspace options file 216 | *.opt 217 | 218 | # Visual Studio LightSwitch build output 219 | **/*.HTMLClient/GeneratedArtifacts 220 | **/*.DesktopClient/GeneratedArtifacts 221 | **/*.DesktopClient/ModelManifest.xml 222 | **/*.Server/GeneratedArtifacts 223 | **/*.Server/ModelManifest.xml 224 | _Pvt_Extensions 225 | 226 | # Paket dependency manager 227 | .paket/paket.exe 228 | 229 | # FAKE - F# Make 230 | .fake/ 231 | 232 | # ========================= 233 | # Operating System Files 234 | # ========================= 235 | 236 | # OSX 237 | # ========================= 238 | 239 | .DS_Store 240 | .AppleDouble 241 | .LSOverride 242 | 243 | # Thumbnails 244 | ._* 245 | 246 | # Files that might appear in the root of a volume 247 | .DocumentRevisions-V100 248 | .fseventsd 249 | .Spotlight-V100 250 | .TemporaryItems 251 | .Trashes 252 | .VolumeIcon.icns 253 | 254 | # Directories potentially created on remote AFP share 255 | .AppleDB 256 | .AppleDesktop 257 | Network Trash Folder 258 | Temporary Items 259 | .apdisk 260 | 261 | # Windows 262 | # ========================= 263 | 264 | # Windows image file caches 265 | Thumbs.db 266 | ehthumbs.db 267 | 268 | # Folder config file 269 | Desktop.ini 270 | 271 | # Recycle Bin used on file shares 272 | $RECYCLE.BIN/ 273 | 274 | # Windows Installer files 275 | *.cab 276 | *.msi 277 | *.msm 278 | *.msp 279 | 280 | # Windows shortcuts 281 | *.lnk 282 | -------------------------------------------------------------------------------- /MyMath.h: -------------------------------------------------------------------------------- 1 | #ifndef MYMATH_H 2 | #define MYMATH_H 3 | /* 4 | /** 5 | * MathLibrary 6 | * Copyright (c) 2011 NoLimitsDesigns 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 3. Neither the name of the copyright holders nor the names of its 18 | * contributors may be used to endorse or promote products derived from 19 | * this software without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 | * THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | * If there are any concerns or questions about the code, please e-mail smasherprog@gmail.com or visit www.nolimitsdesigns.com 34 | */ 35 | 36 | /** 37 | * Author: Scott Lee 38 | */ 39 | #include 40 | #include "float.h" 41 | #include "math.h" 42 | #include 43 | #include "stdint.h" 44 | #include 45 | 46 | #define Pi 3.14159265358979323846f 47 | #define INV_Pi 1.0f/Pi 48 | #define PI_D_CI 2*Pi/360.0f//pi divided by circle 49 | #define CI_D_PI 360.0f/(Pi*2)// circle divided by pi 50 | #define MATH_EPS 0.0001f 51 | #define TWOPI (Pi * 2.0f) 52 | #define ONEOVERTWOPI (1.0f / TWOPI) 53 | #define PIOVER180 (Pi / 180.0f) 54 | #define ONEEIGHTYOVERPI (180.0f / Pi) 55 | #define PIOVERTWO (Pi /2.0f) 56 | #ifndef max 57 | #define max(a,b) (((a) > (b)) ? (a) : (b)) 58 | #endif 59 | #ifndef min 60 | #define min(a,b) (((a) < (b)) ? (a) : (b)) 61 | #endif 62 | 63 | inline float wrapPi(float theta) { 64 | theta += Pi; 65 | theta -= floor(theta * ONEOVERTWOPI) * TWOPI; 66 | theta -= Pi; 67 | return theta; 68 | } 69 | inline void sincosf(float& s, float& c, const float theta) { 70 | s = sinf(theta); 71 | c = cosf(theta); 72 | } 73 | //A floating-point value; 32-bit floating-point formats use IEEE 754 single-precision (s23e8 format): sign bit, 8-bit biased (127) exponent, and 23-bit mantissa. 74 | //16-bit floating-point formats use half-precision (s10e5 format): sign bit, 5-bit biased (15) exponent, and 10-bit mantissa. 75 | inline uint16_t Uint16ToFloat16(uint16_t v) {// this function is really only used for Direct x's 16 bit float format... 76 | float t(static_cast(v));// convert it to a real float.... 77 | uint16_t* p(reinterpret_cast(&t)); 78 | uint16_t ret(0);// this is what will be returned 79 | ret |= *p >> 13;// get the last two bytes of data, which is part of the mantisaa and shift off the extra data 80 | ret |= *(p + 1) & 0xC000;// get the sign of the number and the sign of the exponent 81 | ret |= (*(p + 1) & 0x07FF) << 3;// only get 4 bits of exponent, and the rest of the mantissa 82 | return ret; 83 | } 84 | inline float Float16ToFloat32(uint16_t v) { 85 | float ret(0); 86 | uint16_t* r = reinterpret_cast(&ret);// this is what will be returned 87 | *(r + 1) = (v & 0x03ff); 88 | *reinterpret_cast(&ret) >>= 3;//shift the mantisaa into place 89 | *(r + 1) |= (v & 0x3C00) >> 3; 90 | *(r + 1) |= v & 0xC000;// get the sign 91 | return ret; 92 | } 93 | inline uint16_t Float32ToFloat16(float v) {// this function is really only used for Direct x's 16 bit float format... 94 | uint16_t* p(reinterpret_cast(&v)); 95 | uint16_t ret(0);// this is what will be returned 96 | ret |= *p >> 13;// get the last two bytes of data, which is part of the mantisaa and shift off the extra data 97 | ret |= *(p + 1) & 0xC000;// get the sign of the number and the sign of the exponent 98 | ret |= (*(p + 1) & 0x07FF) << 3;// only get 4 bits of exponent, and the rest of the mantissa 99 | return ret; 100 | } 101 | // the Below code was taken from graphics.stanford.edu/~seander/bithacks.html 102 | static const int MultiplyDeBruijnBitPosition[32] = 103 | { 104 | 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 105 | 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 106 | }; 107 | // this works for 32 bit integers 108 | inline unsigned int BSR(unsigned int v) { 109 | v |= v >> 1; // first round down to one less than a power of 2 110 | v |= v >> 2; 111 | v |= v >> 4; 112 | v |= v >> 8; 113 | v |= v >> 16; 114 | return MultiplyDeBruijnBitPosition[(unsigned int)(v * 0x07C4ACDDU) >> 27]; 115 | } 116 | 117 | template inline void Swap(T &a, T &b) { 118 | const T temp(a); 119 | a = b; 120 | b = temp; 121 | } 122 | 123 | inline float CircleX(float x, float a, float b) {// simple circle right meow, a and b are the height and width of the desired circle (NOT SQUARED) returns the y value, given a x 124 | return sqrtf((1.0f - (x*x) / (b*b)) *a*a); 125 | }// I hope the compiler can optimize all of this away since the values will all be computable and known at runtime 126 | 127 | // the following function will take the range [fromleft, fromright] and convert that range to [toleft, toright] 128 | // x must be in the range [fromleft, fromright] and the returned value with be the value converted to the [toleft, toright] 129 | struct cRange { 130 | float scale, invtrans, trans; 131 | }; 132 | inline cRange CreateRange(float fromleft, float fromright, float toleft, float toright) { 133 | float fromrange(abs(fromleft - fromright)); 134 | float torange(abs(toleft - toright)); 135 | cRange te; 136 | te.scale = torange / fromrange; 137 | te.invtrans = fromleft < fromright ? fromleft : fromright;// get the smallest number of the two for the invtrans 138 | te.trans = toleft < toright ? toleft : toright;// get the smallest number of the two for the trans 139 | return te; 140 | } 141 | inline float ChangeRange(float x, float fromleft, float fromright, float toleft, float toright) { 142 | float fromrange(abs(fromleft - fromright)); 143 | float torange(abs(toleft - toright)); 144 | float scale(torange / fromrange); 145 | float invtrans(fromleft < fromright ? -fromleft : -fromright); 146 | float trans(toleft < toright ? toleft : toright); 147 | return (((x - invtrans) * scale) + trans); 148 | } 149 | inline float ChangeRange(float x, const cRange& range) { 150 | return (((x - range.invtrans) * range.scale) + range.trans); 151 | } 152 | templateT Clamp(T Value, T Min, T Max) { 153 | return (Value < Min) ? Min : (Value > Max) ? Max : Value; 154 | } 155 | #define DEGTORAD(deg) (deg*(Pi/180.0f)) 156 | #define RADTODEG(Rad) (Rad*(180.0f/Pi)) 157 | inline bool QuadraticFormula(const float a, const float b, const float c, float& r1, float& r2) { 158 | const float q = b*b - 4 * a*c; 159 | if (q >= 0) { 160 | const float sq = sqrtf(q); 161 | const float d = 1 / (2 * a); 162 | r1 = (-b + sq) * d; 163 | r2 = (-b - sq) * d; 164 | return true;//real roots 165 | } 166 | return false;//complex roots 167 | } 168 | 169 | #define POWOFTWO(a) (a && ! (a & (a - 1) ) )// returns true if the number is a power of two.. false otherwise 170 | inline float lerp(const float u, const float v, const float x) { return u * (1 - x) + v * x; } 171 | inline float cerp(const float u0, const float u1, const float u2, const float u3, const float x) { 172 | float p = (u3 - u2) - (u0 - u1); 173 | float q = (u0 - u1) - p; 174 | float r = u2 - u0; 175 | return x * (x * (x * p + q) + r) + u1; 176 | } 177 | 178 | inline float herp(const float u0, const float u1, const float u2, const float u3, const float x, const float tension, const float bias) { 179 | float m0 = (u1 - u0) * (1 + bias) * (1 - tension) / 2 + (u2 - u1) * (1 - bias) * (1 - tension) / 2; 180 | float m1 = (u2 - u1) * (1 + bias) * (1 - tension) / 2 + (u3 - u2) * (1 - bias) * (1 - tension) / 2; 181 | float x2 = x * x; 182 | float x3 = x * x2; 183 | float a0 = 2 * x3 - 3 * x2 + 1; 184 | float a1 = x3 - 2 * x2 + x; 185 | float a2 = x3 - x2; 186 | float a3 = -2 * x3 + 3 * x2; 187 | 188 | return a0 * u1 + a1 * m0 + a2 * m1 + a3 * u2; 189 | } 190 | 191 | 192 | class vec2 { 193 | public: 194 | 195 | union { 196 | struct { 197 | float x, y; 198 | }; 199 | 200 | float data[2]; 201 | }; 202 | 203 | vec2() {}// when initaling a vec2or, it is left in a scalartate of unknown!!! 204 | vec2(const vec2 &a) : x(a.x), y(a.y) {} 205 | vec2(float nx, float ny) : x(nx), y(ny) {} 206 | 207 | void operator += (const float scalar) { x += scalar; y += scalar; } 208 | void operator += (const vec2 &v) { x += v.x; y += v.y; } 209 | void operator -= (const float scalar) { x -= scalar; y -= scalar; } 210 | void operator -= (const vec2 &v) { x -= v.x; y -= v.y; } 211 | void operator *= (const float scalar) { x *= scalar; y *= scalar; } 212 | void operator *= (const vec2 &v) { x *= v.x; y *= v.y; } 213 | void operator /= (const float scalar) { float inv(1.0f / scalar); x *= inv; y *= inv; }// NOTE: no check for divide by zero here 214 | void operator /= (const vec2 &v) { x /= v.x; y /= v.y; } 215 | 216 | void zero() { x = y = 0.0f; }// zero's out the scalartruct 217 | 218 | float LengthSq() const { return x*x + y*y; } 219 | float Length() const { return sqrtf(LengthSq()); } 220 | float& operator [](size_t index) { return data[index]; } 221 | float operator [](size_t index) const { return data[index]; } 222 | 223 | }; 224 | 225 | inline vec2 operator + (const vec2 &u, const vec2 &v) { return vec2(u.x + v.x, u.y + v.y); } 226 | inline vec2 operator + (const vec2 &v, const float scalar) { return vec2(v.x + scalar, v.y + scalar); } 227 | inline vec2 operator + (const float scalar, const vec2 &v) { return vec2(v.x + scalar, v.y + scalar); } 228 | inline vec2 operator - (const vec2 &u, const vec2 &v) { return vec2(u.x - v.x, u.y - v.y); } 229 | inline vec2 operator - (const vec2 &v, const float scalar) { return vec2(v.x - scalar, v.y - scalar); } 230 | inline vec2 operator - (const float scalar, const vec2 &v) { return vec2(v.x - scalar, v.y - scalar); } 231 | inline vec2 operator - (const vec2 &v) { return vec2(-v.x, -v.y); } 232 | inline vec2 operator * (const vec2 &u, const vec2 &v) { return vec2(u.x * v.x, u.y * v.y); } 233 | inline vec2 operator * (const float scalar, const vec2 &v) { return vec2(v.x * scalar, v.y * scalar); } 234 | inline vec2 operator * (const vec2 &v, const float scalar) { return vec2(v.x * scalar, v.y * scalar); } 235 | inline vec2 operator / (const vec2 &u, const vec2 &v) { return vec2(u.x / v.x, u.y / v.y); }// NOTE: no check for divide by zero here 236 | inline vec2 operator / (const vec2 &v, const float scalar) { float inv(1.0f / scalar); return vec2(v.x *inv, v.y *inv); }// NOTE: no check for divide by zero here 237 | inline vec2 operator / (const float scalar, const vec2 &v) { float inv(1.0f / scalar); return vec2(v.x *inv, v.y *inv); }// NOTE: no check for divide by zero here 238 | inline bool operator == (const vec2 &u, const vec2 &v) { return ((u.x == v.x) & (u.y == v.y)); } 239 | inline bool operator != (const vec2 &u, const vec2 &v) { return ((u.x != v.x) | (u.y != v.y)); } 240 | 241 | inline float Dot(const vec2& a, const vec2 &b) { return a.x*b.x + a.y*b.y; } 242 | inline vec2 Min(const vec2& a, const vec2& b) { return vec2(min(a.x, b.x), min(a.y, b.y)); } 243 | inline vec2 Max(const vec2& a, const vec2& b) { return vec2(max(a.x, b.x), max(a.y, b.y)); } 244 | inline vec2 Floor(const vec2& a) { return vec2(floor(a.x), floor(a.y)); } 245 | 246 | inline vec2 Lerp(const vec2 &u, const vec2 &v, const vec2 &x) { return u + x * (v - u); } 247 | inline vec2 Lerp(const vec2 &u, const vec2 &v, const float x) { return u + x * (v - u); } 248 | 249 | inline vec2 Serp(const vec2 &u0, const vec2 &u1, const vec2 &u2, const vec2 &u3, const float x) { 250 | vec2 p = (u3 - u2) - (u0 - u1); 251 | vec2 q = (u0 - u1) - p; 252 | vec2 r = u2 - u0; 253 | return x * (x * (x * p + q) + r) + u1; 254 | } 255 | inline float Length(const vec2 &a, const vec2 &b) { return (a - b).Length(); } 256 | inline float LengthSq(const vec2 &a, const vec2 &b) { return (a - b).LengthSq(); } 257 | 258 | inline bool CloseTo(const vec2& p1, const vec2& p2, const float epison = .001f) { vec2 temp(p1 - p2); return (abs(Dot(temp, temp)) < epison); } 259 | inline vec2 abs(const vec2& v) { return vec2(abs(v.x), abs(v.y)); } 260 | inline std::ostream& operator<<(std::ostream& strem, const vec2& obj) { 261 | strem << "x=" << obj.x << " y=" << obj.y; 262 | return strem; 263 | } 264 | 265 | 266 | /* --------------------------------VEC3---------------------------------------------- */ 267 | 268 | 269 | class vec3 { 270 | public: 271 | 272 | union { 273 | float data[3]; 274 | struct { 275 | float x, y, z; 276 | }; 277 | }; 278 | vec3() {}// when initaling a std::vector, it is left in a scalartate of unknown!!! 279 | vec3(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {} 280 | vec3(const vec2& v) : x(v.x), y(v.y), z(0.0f) {} 281 | vec3(const vec3 &a) : x(a.x), y(a.y), z(a.z) {} 282 | vec3(const float* v) : x(*v), y(*(v + 1)), z(*(v + 2)) {}// array initialization 283 | vec3(const vec2 &iv, const float iz) : x(iv.x), y(iv.y), z(iz) {} 284 | vec3(const float ix, const vec2 &iv) : x(ix), y(iv.x), z(iv.y) {} 285 | 286 | void operator += (const float scalar) { x += scalar; y += scalar; z += scalar; } 287 | void operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; } 288 | void operator -= (const float scalar) { x -= scalar; y -= scalar; z -= scalar; } 289 | void operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; } 290 | void operator *= (const float scalar) { x *= scalar; y *= scalar; z *= scalar; } 291 | void operator *= (const vec3 &v) { x *= v.x; y *= v.y; z *= v.z; } 292 | void operator /= (const float scalar) { float inv(1.0f / scalar); x *= inv; y *= inv; z *= inv; } 293 | void operator /= (const vec3 &v) { x /= v.x; y /= v.y; z /= v.z; } 294 | 295 | // utility 296 | float& operator [](size_t index) { return data[index]; } 297 | float operator [](size_t index) const { return data[index]; } 298 | void zero() { x = y = z = 0.0f; }// zero's out the scalartruct 299 | void normalize() { float inv(1.0f / Length()); x *= inv; y *= inv; z *= inv; }// no check for div by zero!!!!!! 300 | float LengthSq() const { return x*x + y*y + z*z; } 301 | float Length() const { return sqrtf(LengthSq()); } 302 | }; 303 | 304 | inline vec3 operator + (const vec3 &u, const vec3 &v) { return vec3(u.x + v.x, u.y + v.y, u.z + v.z); } 305 | inline vec3 operator + (const vec3 &v, const float scalar) { return vec3(v.x + scalar, v.y + scalar, v.z + scalar); } 306 | inline vec3 operator + (const float scalar, const vec3 &v) { return vec3(v.x + scalar, v.y + scalar, v.z + scalar); } 307 | inline vec3 operator - (const vec3 &u, const vec3 &v) { return vec3(u.x - v.x, u.y - v.y, u.z - v.z); } 308 | inline vec3 operator - (const vec3 &v, const float scalar) { return vec3(v.x - scalar, v.y - scalar, v.z - scalar); } 309 | inline vec3 operator - (const float scalar, const vec3 &v) { return vec3(v.x - scalar, v.y - scalar, v.z - scalar); } 310 | inline vec3 operator - (const vec3 &v) { return vec3(-v.x, -v.y, -v.z); } 311 | inline vec3 operator * (const vec3 &u, const vec3 &v) { return vec3(u.x * v.x, u.y * v.y, u.z * v.z); } 312 | inline vec3 operator * (const float scalar, const vec3 &v) { return vec3(v.x * scalar, v.y * scalar, v.z * scalar); } 313 | inline vec3 operator * (const vec3 &v, const float scalar) { return vec3(v.x * scalar, v.y * scalar, v.z * scalar); } 314 | 315 | inline vec3 operator / (const vec3 &u, const vec3 &v) { return vec3(u.x / v.x, u.y / v.y, u.z / v.z); } // no check for div by zero!!!!!! 316 | inline vec3 operator / (const vec3 &v, const float scalar) { float inv(1.0f / scalar); return vec3(v.x *inv, v.y *inv, v.z *inv); }// no check for div by zero!!!!!! 317 | inline vec3 operator / (const float scalar, const vec3 &v) { float inv(1.0f / scalar); return vec3(inv* v.x, inv* v.y, inv* v.z); } // no check for div by zero!!!!!! 318 | inline bool operator == (const vec3 &u, const vec3 &v) { return ((u.x == v.x) & (u.y == v.y) & (u.z == v.z)); } 319 | inline bool operator != (const vec3 &u, const vec3 &v) { return ((u.x != v.x) | (u.y != v.y) | (u.z != v.z)); } 320 | 321 | inline vec3 Min(const vec3& a, const vec3& b) { return vec3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); } 322 | inline vec3 Max(const vec3& a, const vec3& b) { return vec3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); } 323 | 324 | inline vec3 Lerp(const vec3 &u, const vec3 &v, const vec3 &x) { return u + x * (v - u); } 325 | inline vec3 Lerp(const vec3 &u, const vec3 &v, const float x) { return u + x * (v - u); } 326 | vec3 Serp(const vec3 &u0, const vec3 &u1, const vec3 &u2, const vec3 &u3, const float x); 327 | 328 | inline float Dot(const vec3& a, const vec3& b) { return b.x*a.x + b.y*a.y + b.z*a.z; } 329 | 330 | 331 | inline bool CloseTo(const vec3& p1, const vec3& p2, const float epison = .001f) { vec3 temp(p1 - p2); return (abs(Dot(temp, temp)) < epison); } 332 | inline vec3 abs(const vec3& v) { return vec3(abs(v.x), abs(v.y), abs(v.z)); } 333 | inline vec3 Cross(const vec3 &a, const vec3 &b) { return vec3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); } 334 | 335 | inline float Length(const vec3 &a, const vec3 &b) { return (a - b).Length(); } 336 | inline float LengthSq(const vec3 &a, const vec3 &b) { return (a - b).LengthSq(); } 337 | inline vec3 floor(const vec3& a) { return vec3(floor(a.x), floor(a.y), floor(a.z)); } 338 | inline vec3 ceil(const vec3& a) { return vec3(ceil(a.x), ceil(a.y), ceil(a.z)); } 339 | /* --------------------------------TRIANGLE---------------------------------------------- */ 340 | 341 | 342 | struct cTriangle { 343 | uint32_t Indices[3];// THIS IS RELATIVE TO ITS OWN INDEX BUFFER IF THERE IS ONE 344 | vec3 Vertices[3];//THE ACTUAL OBJECT SPACE POSITIONS!!! 345 | }; 346 | 347 | 348 | /* --------------------------------PLANE---------------------------------------------- */ 349 | 350 | 351 | 352 | class Plane { 353 | public: 354 | union { 355 | struct { vec3 Normal; float pad; }; 356 | struct { float a, b, c, d; }; 357 | }; 358 | Plane() {} 359 | Plane(const cTriangle& tri) { 360 | Normal = Cross(tri.Vertices[1] - tri.Vertices[0], tri.Vertices[2] - tri.Vertices[0]); 361 | Normal.normalize(); 362 | d = -Dot(Normal, tri.Vertices[0]); 363 | } 364 | Plane(const vec3& p0, const vec3& n) : Normal(n), d(-Dot(Normal, p0)) {}//Lengthance from the plane to the origin from a normal and a point 365 | Plane(const vec3& p0, const vec3& p1, const vec3& p2) { 366 | Normal = Cross(p1 - p0, p2 - p0); 367 | Normal.normalize(); 368 | d = -Dot(Normal, p0); 369 | } 370 | Plane(const float ap, const float bp, const float cp, const float dp) : a(ap), b(bp), c(cp), d(dp) {} 371 | float LengthToPoint(const vec3& p) const { return Dot(Normal, p) + d; }//signed Length from the plane topoint 'p' along the unit normal 372 | void Normalize() { 373 | float mag = 1.0f / Normal.Length(); 374 | a = a * mag; 375 | b = b * mag; 376 | c = c * mag; 377 | d = d * mag; 378 | } 379 | }; 380 | 381 | 382 | /* --------------------------------VEC3 CONT'D---------------------------------------------- */ 383 | inline float Dot(const vec3& a, const Plane& b) { return b.a*a.x + b.b*a.y + b.c*a.z; } 384 | inline bool Intersect(const vec3& raydir, const vec3& rayorigin, const Plane& plane, vec3& pointhit) {// assumes an infinite length ray 385 | float bot(Dot(raydir, plane)); 386 | if (bot >= 0) return false;// no intersection, the plane and the ray are parallel or the ray points in the same direction as the plane normal 387 | 388 | float scale = (-Dot(rayorigin, plane) - plane.d) / bot;// this is the length of the ray needed to intersect with the plane . . . 389 | pointhit = (raydir*scale) + rayorigin;// scale the raydir to the correct length, then add that onto the orgin to correctly translate the point 390 | return true; 391 | } 392 | inline float RayAABBIntersect(const vec3& min, const vec3& max, const vec3& rayOrg, const vec3& rayDelta) { 393 | // check for point inside box, trivial reject 394 | // Check for point inside box, trivial reject, and determine parametric 395 | // distance to each front face 396 | bool inside = true; 397 | 398 | float xt, xn; 399 | if (rayOrg.x < min.x) { 400 | xt = min.x - rayOrg.x; 401 | if (xt > rayDelta.x) return INFINITY; 402 | xt /= rayDelta.x; 403 | inside = false; 404 | xn = -1.0f; 405 | } 406 | else if (rayOrg.x > max.x) { 407 | xt = max.x - rayOrg.x; 408 | if (xt < rayDelta.x) return INFINITY; 409 | xt /= rayDelta.x; 410 | inside = false; 411 | xn = 1.0f; 412 | } 413 | else { 414 | xt = -1.0f; 415 | } 416 | 417 | float yt, yn; 418 | if (rayOrg.y < min.y) { 419 | yt = min.y - rayOrg.y; 420 | if (yt > rayDelta.y) return INFINITY; 421 | yt /= rayDelta.y; 422 | inside = false; 423 | yn = -1.0f; 424 | } 425 | else if (rayOrg.y > max.y) { 426 | yt = max.y - rayOrg.y; 427 | if (yt < rayDelta.y) return INFINITY; 428 | yt /= rayDelta.y; 429 | inside = false; 430 | yn = 1.0f; 431 | } 432 | else { 433 | yt = -1.0f; 434 | } 435 | 436 | float zt, zn; 437 | if (rayOrg.z < min.z) { 438 | zt = min.z - rayOrg.z; 439 | if (zt > rayDelta.z) return INFINITY; 440 | zt /= rayDelta.z; 441 | inside = false; 442 | zn = -1.0f; 443 | } 444 | else if (rayOrg.z > max.z) { 445 | zt = max.z - rayOrg.z; 446 | if (zt < rayDelta.z) return INFINITY; 447 | zt /= rayDelta.z; 448 | inside = false; 449 | zn = 1.0f; 450 | } 451 | else { 452 | zt = -1.0f; 453 | } 454 | 455 | // Inside box? 456 | 457 | if (inside) { 458 | return 0.0f; 459 | } 460 | 461 | // Select farthest plane - this is 462 | // the plane of intersection. 463 | 464 | int which = 0; 465 | float t = xt; 466 | if (yt > t) { 467 | which = 1; 468 | t = yt; 469 | } 470 | if (zt > t) { 471 | which = 2; 472 | t = zt; 473 | } 474 | 475 | switch (which) { 476 | 477 | case 0: // intersect with yz plane 478 | { 479 | float y = rayOrg.y + rayDelta.y*t; 480 | if (y < min.y || y > max.y) return INFINITY; 481 | float z = rayOrg.z + rayDelta.z*t; 482 | if (z < min.z || z > max.z) return INFINITY; 483 | } break; 484 | 485 | case 1: // intersect with xz plane 486 | { 487 | float x = rayOrg.x + rayDelta.x*t; 488 | if (x < min.x || x > max.x) return INFINITY; 489 | float z = rayOrg.z + rayDelta.z*t; 490 | if (z < min.z || z > max.z) return INFINITY; 491 | } break; 492 | 493 | case 2: // intersect with xy plane 494 | { 495 | float x = rayOrg.x + rayDelta.x*t; 496 | if (x < min.x || x > max.x) return INFINITY; 497 | float y = rayOrg.y + rayDelta.y*t; 498 | if (y < min.y || y > max.y) return INFINITY; 499 | 500 | } break; 501 | } 502 | 503 | // Return parametric point of intersection 504 | 505 | return t; 506 | } 507 | // this function will find the intersection of ray1 with ray two. ray1 is assumed infinit length, ray2 however, is of finite length 508 | // I use this for testing whether my mouse click hits a line segment in the world. 509 | inline vec2 RayRayIntersect(const vec3& ray1, const vec3& origin1, const float lengthof2, const vec3& ray2, const vec3& origin2) { 510 | vec3 temp(Cross(ray1, ray2));// cross product of the normalized std::vectors 511 | float det = temp.LengthSq();// magnitude squared 512 | if (abs(det) < .01f) return vec2(INFINITY, INFINITY);// if det ==0.0f, but there might be floating point precision error, so make sure.. mmkay? this means the two rays are basically parallel 513 | det = 1.0f / det;// inverse 514 | vec3 p2mp1(origin2 - origin1); 515 | vec3 temp1(Cross(p2mp1, ray1)); 516 | float t2 = Dot(temp1, temp)*det; 517 | if ((t2 < 0.0f) | (t2 > lengthof2)) return vec2(INFINITY, INFINITY);// the rays did not intersect 518 | temp1 = Cross(p2mp1, ray2); 519 | float t1 = Dot(temp1, temp)*det; 520 | return vec2(t1, t2);// returns the distance each ray needs to be scaled to hit each other 521 | } 522 | // find the intersection of two rays given a direction and starting position for each 523 | inline vec2 RayRayIntersect(const vec3& ray1, const vec3& origin1, const vec3& ray2, const vec3& origin2) { 524 | vec3 temp(Cross(ray1, ray2));// cross product of the normalized std::vectors 525 | float det = temp.LengthSq();// magnitude squared 526 | if (abs(det) < .01f) return vec2(INFINITY, INFINITY);// if det ==0.0f, but there might be floating point precision error, so make sure.. mmkay? this means the two rays are basically parallel 527 | det = 1.0f / det;// inverse 528 | vec3 p2mp1(origin2 - origin1); 529 | vec3 temp1(Cross(p2mp1, ray1)); 530 | float t2 = Dot(temp1, temp)*det; 531 | temp1 = Cross(p2mp1, ray2); 532 | float t1 = Dot(temp1, temp)*det; 533 | return vec2(t1, t2);// returns the distance the rays need to be scaled by to intersect with each other 534 | } 535 | inline std::ostream& operator<<(std::ostream& strem, const vec3& obj) { 536 | strem << "x=" << obj.x << " y=" << obj.y << " z=" << obj.z; 537 | return strem; 538 | } 539 | 540 | inline int32_t GetRGBAFromHeights(float t, float b, float l, float r, float bump) { 541 | vec3 tanZ(0.0f, (t - b), 1.0f); 542 | vec3 tanX(1.0f, (r - l), 0.0f); 543 | vec3 N; 544 | N = Cross(tanZ, tanX); 545 | N.normalize(); 546 | int8_t rgba[4];// this needs to be stored in little endian format, which is why the info is stored as a bgr instead of rgb 547 | rgba[3] = static_cast(bump); 548 | float x = N.x * 127.0f; 549 | rgba[2] = static_cast(x);// CAST!!! 550 | float y = N.y * 127.0f; 551 | rgba[1] = static_cast(y);// CAST!!! 552 | float z = N.z * 127.0f; 553 | rgba[0] = static_cast(z);// CAST!!! 554 | return *reinterpret_cast(rgba); 555 | } 556 | 557 | /* --------------------------------------VEC4------------------------------------ */ 558 | 559 | 560 | class vec4 { 561 | public: 562 | union { 563 | #ifdef _WIN64 564 | __m128 vec; 565 | #endif 566 | float data[4]; 567 | struct { 568 | float x, y, z, w; 569 | }; 570 | struct { 571 | float top, left, right, bottom; 572 | }; 573 | }; 574 | vec4() {}// when initaling a vec4, it is left in a state of unknown!!! 575 | vec4(const vec3 &a) : x(a.x), y(a.y), z(a.z), w(0.0f) {} 576 | vec4(float nx, float ny, float nz, float nw) : x(nx), y(ny), z(nz), w(nw) {} 577 | vec4(const vec2& iv, const float nz, const float nw) : x(iv.x), y(iv.y), z(nz), w(nw) {} 578 | vec4(const float nx, const vec2& iv, const float nw) : x(nx), y(iv.x), z(iv.y), w(nw) {} 579 | vec4(const float nx, const float ny, const vec2& iv) : x(nx), y(ny), z(iv.x), w(iv.y) {} 580 | vec4(const vec2& nv0, const vec2& nv1) : x(nv0.x), y(nv0.y), z(nv1.x), w(nv1.y) {} 581 | vec4(const vec3& iv, const float iw) : x(iv.x), y(iv.y), z(iv.z), w(iw) {} 582 | vec4(const float ix, const vec3& iv) : x(ix), y(iv.x), z(iv.y), w(iv.z) {} 583 | vec4(const float* v) : x(*v), y(*(v + 1)), z(*(v + 2)), w(*(v + 3)) {}// array initialization 584 | 585 | #ifdef _WIN64 586 | vec4(__m128& ve) : vec(ve) {} 587 | vec4(const vec4 &a) : vec(a.vec) {} 588 | void operator += (const float scalar) { vec = _mm_add_ps(vec, _mm_set_ps1(scalar)); } 589 | void operator += (const vec4 &v) { vec = _mm_add_ps(vec, v.vec); } 590 | void operator -= (const float scalar) { vec = _mm_sub_ps(vec, _mm_set_ps1(scalar)); } 591 | void operator -= (const vec4 &v) { vec = _mm_sub_ps(vec, v.vec); } 592 | void operator *= (const float scalar) { vec = _mm_mul_ps(vec, _mm_set_ps1(scalar)); } 593 | void operator *= (const vec4 &v) { vec = _mm_mul_ps(vec, v.vec); } 594 | void operator /= (const float scalar) { vec = _mm_div_ps(vec, _mm_set_ps1(scalar)); } 595 | void operator /= (const vec4 &v) { vec = _mm_div_ps(vec, v.vec); } 596 | void zero() { vec = _mm_setzero_ps(); }// zero's out the struct 597 | void normalize() { 598 | vec = _mm_mul_ps(vec, _mm_set_ps1(1.0f / Length())); 599 | } 600 | float LengthSq() const { 601 | __m128 temp(_mm_mul_ps(vec, vec)); 602 | float* t(reinterpret_cast(&temp)); 603 | return t[0] + t[1] + t[2] + t[3]; 604 | } 605 | void floor() { x = floorf(x); y = floorf(y); z = floorf(z); w = floorf(w); } 606 | void ceil() { x = ceilf(x); y = ceilf(y); z = ceilf(z); w = ceilf(w); } 607 | #else 608 | vec4(const vec4 &a) : x(a.x), y(a.y), z(a.z), w(a.w) {} 609 | void operator += (const float scalar) { x += scalar; y += scalar; z += scalar; w += scalar; } 610 | void operator += (const vec4 &v) { x += v.x; y += v.y; z += v.z; w += v.w; } 611 | void operator -= (const float scalar) { x -= scalar; y -= scalar; z -= scalar; w -= scalar; } 612 | void operator -= (const vec4 &v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; } 613 | void operator *= (const float scalar) { x *= scalar; y *= scalar; z *= scalar; w *= scalar; } 614 | void operator *= (const vec4 &v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; } 615 | void operator /= (const float scalar) { float inv(1.0f / scalar); x *= inv; y *= inv; z *= inv; w *= inv; } 616 | void operator /= (const vec4 &v) { x /= v.x; y /= v.y; z /= v.z; w /= v.w; } 617 | void zero() { x = y = z = w = 0.0f; }// zero's out the struct 618 | void normalize() { float inv(1.0f / Length()); x *= inv; y *= inv; z *= inv; w *= inv; } // no check for div by zero!!!!!! 619 | float LengthSq() const { return x*x + y*y + z*z + w*w; } 620 | #endif 621 | operator uint32_t () const {// convert from [0, 1] to rgba 8 622 | uint32_t dwR = x >= 1.0f ? 0xff : x <= 0.0f ? 0x00 : (uint32_t)(x * 255.0f + 0.5f); 623 | uint32_t dwG = y >= 1.0f ? 0xff : y <= 0.0f ? 0x00 : (uint32_t)(y * 255.0f + 0.5f); 624 | uint32_t dwB = z >= 1.0f ? 0xff : z <= 0.0f ? 0x00 : (uint32_t)(z * 255.0f + 0.5f); 625 | uint32_t dwA = w >= 1.0f ? 0xff : w <= 0.0f ? 0x00 : (uint32_t)(w * 255.0f + 0.5f); 626 | return (dwA << 24) | (dwR << 16) | (dwG << 8) | (dwB << 0); 627 | } 628 | 629 | float Length() const { return sqrtf(LengthSq()); } 630 | float& operator [](size_t index) { return data[index]; } 631 | float operator [](size_t index) const { return data[index]; } 632 | 633 | }; 634 | 635 | #ifdef _WIN64 636 | 637 | inline vec4 operator + (const vec4 &u, const vec4 &v) { return vec4(_mm_add_ps(u.vec, v.vec)); } 638 | inline vec4 operator + (const vec4 &v, const float s) { return vec4(_mm_add_ps(v.vec, _mm_set_ps1(s))); } 639 | inline vec4 operator + (const float s, const vec4 &v) { return vec4(_mm_add_ps(_mm_set_ps1(s), v.vec)); } 640 | inline vec4 operator - (const vec4 &u, const vec4 &v) { return vec4(_mm_sub_ps(u.vec, v.vec)); } 641 | inline vec4 operator - (const vec4 &v, const float s) { return vec4(_mm_sub_ps(v.vec, _mm_set_ps1(s))); } 642 | inline vec4 operator - (const float s, const vec4 &v) { return vec4(_mm_sub_ps(_mm_set_ps1(s), v.vec)); } 643 | inline vec4 operator - (const vec4 &v) { return vec4(_mm_mul_ps(_mm_set_ps1(-1.0f), v.vec)); } 644 | inline vec4 operator * (const vec4 &u, const vec4 &v) { return vec4(_mm_mul_ps(u.vec, v.vec)); } 645 | inline vec4 operator * (const float s, const vec4 &v) { return vec4(_mm_mul_ps(_mm_set_ps1(s), v.vec)); } 646 | inline vec4 operator * (const vec4 &v, const float s) { return vec4(_mm_mul_ps(v.vec, _mm_set_ps1(s))); } 647 | inline vec4 operator / (const vec4 &u, const vec4 &v) { return vec4(_mm_div_ps(u.vec, v.vec)); } 648 | inline vec4 operator / (const vec4 &v, const float s) { return vec4(_mm_div_ps(v.vec, _mm_set_ps1(s))); } 649 | inline vec4 operator / (const float s, const vec4 &v) { return vec4(_mm_div_ps(_mm_set_ps1(s), v.vec)); } 650 | 651 | inline vec4 Min(const vec4& a, const vec4& b) { return vec4(_mm_min_ps(a.vec, b.vec)); } 652 | inline vec4 Max(const vec4& a, const vec4& b) { return vec4(_mm_max_ps(a.vec, b.vec)); } 653 | 654 | inline float Dot(const vec4& a, const vec4& b) { 655 | __m128 ts(_mm_mul_ps(a.vec, b.vec)); 656 | float* t(reinterpret_cast(&ts)); 657 | return t[0] + t[1] + t[2] + t[3];// using the _mm_hadd_ps function is slower than doing this... dont believe me? try it 658 | } 659 | inline vec4 floor(const vec4& a) { return vec4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w)); } 660 | inline vec4 ceil(const vec4& a) { return vec4(ceilf(a.x), ceilf(a.y), ceilf(a.z), ceilf(a.w)); } 661 | #else 662 | inline vec4 operator + (const vec4 &u, const vec4 &v) { return vec4(u.x + v.x, u.y + v.y, u.z + v.z, u.w + v.w); } 663 | inline vec4 operator + (const vec4 &v, const float s) { return vec4(v.x + s, v.y + s, v.z + s, v.w + s); } 664 | inline vec4 operator + (const float s, const vec4 &v) { return vec4(v.x + s, v.y + s, v.z + s, v.w + s); } 665 | inline vec4 operator - (const vec4 &u, const vec4 &v) { return vec4(u.x - v.x, u.y - v.y, u.z - v.z, u.w - v.w); } 666 | inline vec4 operator - (const vec4 &v, const float s) { return vec4(v.x - s, v.y - s, v.z - s, v.w - s); } 667 | inline vec4 operator - (const float s, const vec4 &v) { return vec4(v.x - s, v.y - s, v.z - s, v.w - s); } 668 | inline vec4 operator - (const vec4 &v) { return vec4(-v.x, -v.y, -v.z, -v.w); } 669 | inline vec4 operator * (const vec4 &u, const vec4 &v) { return vec4(u.x * v.x, u.y * v.y, u.z * v.z, u.w * v.w); } 670 | inline vec4 operator * (const float s, const vec4 &v) { return vec4(v.x * s, v.y * s, v.z * s, v.w * s); } 671 | inline vec4 operator * (const vec4 &v, const float s) { return vec4(v.x * s, v.y * s, v.z * s, v.w * s); } 672 | inline vec4 operator / (const vec4 &u, const vec4 &v) { return vec4(u.x / v.x, u.y / v.y, u.z / v.z, u.w / v.w); } 673 | inline vec4 operator / (const vec4 &v, const float s) { return vec4(v.x / s, v.y / s, v.z / s, v.w / s); } 674 | inline vec4 operator / (const float s, const vec4 &v) { return vec4(s / v.x, s / v.y, s / v.z, s / v.w); } 675 | inline float Dot(const vec4& a, const vec4& b) { return b.x*a.x + b.y*a.y + b.z*a.z + b.w*a.w; } 676 | inline vec4 Min(const vec4& a, const vec4& b) { return vec4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); } 677 | inline vec4 Max(const vec4& a, const vec4& b) { return vec4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); } 678 | 679 | #endif 680 | 681 | inline bool operator == (const vec4 &u, const vec4 &v) { return (u.x == v.x) & (u.y == v.y) & (u.z == v.z) & (u.w == v.w); } 682 | inline bool operator != (const vec4 &u, const vec4 &v) { return (u.x != v.x) | (u.y != v.y) | (u.z != v.z) | (u.w != v.w); } 683 | 684 | inline vec4 Lerp(const vec4 &u, const vec4 &v, const vec4 &x) { return u + x * (v - u); } 685 | inline vec4 Lerp(const vec4 &u, const vec4 &v, const float x) { return u + x * (v - u); } 686 | inline vec4 Serp(const vec4 &u0, const vec4 &u1, const vec4 &u2, const vec4 &u3, const float x) { 687 | vec4 p = (u3 - u2) - (u0 - u1); 688 | vec4 q = (u0 - u1) - p; 689 | vec4 r = u2 - u0; 690 | return x * (x * (x * p + q) + r) + u1; 691 | } 692 | inline bool CloseTo(const vec4& p1, const vec4& p2, const float epison = MATH_EPS) { vec4 temp(p1 - p2); return (abs(Dot(temp, temp)) < epison); } 693 | 694 | extern const vec4 ABSROWVAL; 695 | 696 | inline vec4 abs(const vec4& v) { 697 | #ifdef _WIN64 698 | return vec4(_mm_and_ps(v.vec, ABSROWVAL.vec)); 699 | #else 700 | return vec4(abs(v.x), abs(v.y), abs(v.z), abs(v.w)); 701 | #endif 702 | } 703 | inline std::ostream& operator<<(std::ostream& strem, const vec4& obj) { 704 | strem << "x=" << obj.x << " y=" << obj.y << " z=" << obj.z << " w=" << obj.w; 705 | return strem; 706 | } 707 | inline void copy(vec4& dst, __m128* src) {// copy used for 32 bit because the compiler cannot guarantee alignment of __m128 on the stack 708 | dst.x = *(reinterpret_cast(src) + 0); 709 | dst.y = *(reinterpret_cast(src) + 1); 710 | dst.z = *(reinterpret_cast(src) + 2); 711 | dst.w = *(reinterpret_cast(src) + 3); 712 | } 713 | inline void copy(__m128* dst, const vec4& src) {// copy used for 32 bit because the compiler cannot guarantee alignment of __m128 on the stack 714 | *(reinterpret_cast(dst) + 0) = src.x; 715 | *(reinterpret_cast(dst) + 1) = src.y; 716 | *(reinterpret_cast(dst) + 2) = src.z; 717 | *(reinterpret_cast(dst) + 3) = src.w; 718 | } 719 | 720 | 721 | /* --------------------------------------QUAT------------------------------------ */ 722 | 723 | 724 | 725 | class mat4;// forward declaration 726 | class euler;// forward declaration 727 | class quat { 728 | public: 729 | 730 | union { 731 | float data[4]; 732 | #ifdef _WIN64 733 | __m128 vec; 734 | 735 | #endif 736 | struct { 737 | vec4 row_v; 738 | }; 739 | struct { 740 | float x, y, z, w; 741 | }; 742 | }; 743 | 744 | quat() {} 745 | quat(const vec4& vec4) : row_v(vec4) {} 746 | #ifdef _WIN64 747 | quat(const __m128 v) : vec(v) {} 748 | quat(const float nx, const float ny, const float nz, const float nw) { vec = _mm_set_ps(nw, nz, ny, nx); } 749 | void identity() { vec = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f); } 750 | #else 751 | quat(const float nx, const float ny, const float nz, const float nw) : x(nx), y(ny), z(nz), w(nw) {} 752 | void identity() { x = y = z = 0.0f; w = 1.0f; } 753 | #endif 754 | 755 | void SetupRotation(const vec3& rots) { SetupRotation(rots.x, rots.y, rots.z); } 756 | inline void SetupRotation(const euler &orientation); 757 | void setToRotateAboutX(float theta) { sincosf(x, w, theta * .5f); y = z = 0.0f; }// theta is expected to be in radians 758 | void setToRotateAboutY(float theta) { sincosf(y, w, theta * .5f); x = z = 0.0f; }// theta is expected to be in radians 759 | void setToRotateAboutZ(float theta) { sincosf(z, w, theta * .5f); x = y = 0.0f; }// theta is expected to be in radians 760 | void setToRotateAboutAxis(const vec3 &axis, float theta) {// theta is expected to be in radians 761 | float sinThetaOver2; 762 | sincosf(sinThetaOver2, w, theta * .5f); 763 | x = axis.x * sinThetaOver2; 764 | y = axis.y * sinThetaOver2; 765 | z = axis.z * sinThetaOver2; 766 | } 767 | void SetupRotation(const float heading, const float pitch, const float bank) {// angles are expected to be in radians 768 | float sp, sb, sh;// Compute sine and cosine of the half angles 769 | float cp, cb, ch; 770 | sincosf(sp, cp, pitch * 0.5f); 771 | sincosf(sb, cb, bank * 0.5f); 772 | sincosf(sh, ch, heading * 0.5f); 773 | w = ch*cp*cb + sh*sp*sb; 774 | x = ch*sp*cb + sh*cp*sb; 775 | y = -ch*sp*sb + sh*cp*cb; 776 | z = -sh*sp*cb + ch*cp*sb; 777 | } 778 | 779 | void operator *=(const quat &a) { 780 | *this = quat(w*a.x + x*a.w + z*a.y - y*a.z, 781 | w*a.y + y*a.w + x*a.z - z*a.x, 782 | w*a.z + z*a.w + y*a.x - x*a.y, 783 | w*a.w - x*a.x - y*a.y - z*a.z); 784 | } 785 | float& operator [](size_t index) { return data[index]; } 786 | float operator [](size_t index) const { return data[index]; } 787 | 788 | 789 | void normalize() { row_v.normalize(); } // no check for div by zero!!!!!! 790 | float getRotationAngle() const { return acosf(w) * 2.0f; } 791 | vec3 getRotationAxis() const { 792 | float sinThetaOver2Sq = 1.0f - w*w;// Compute sin^2(theta/2). Remember that w = cosf(theta/2), and sin^2(x) + cos^2(x) = 1 793 | if (sinThetaOver2Sq <= 0.0f) return vec3(1.0f, 0.0f, 0.0f);// Protect against numerical imprecision 794 | // Identi_42 quaternion, or numerical imprecision. Just return any valid vector, since it doesn't matter 795 | float oneOverSinThetaOver2 = 1.0f / sqrtf(sinThetaOver2Sq);// Compute 1 / sinf(theta/2) 796 | return vec3(x * oneOverSinThetaOver2, y * oneOverSinThetaOver2, z * oneOverSinThetaOver2);// Return axis of rotation 797 | } 798 | 799 | inline void frommatrix(const mat4& pm); 800 | }; 801 | inline std::ostream& operator<<(std::ostream& strem, const quat& obj) { 802 | strem << obj.row_v; 803 | return strem; 804 | } 805 | 806 | inline float Dot(const quat &a, const quat &b) { return Dot(a.row_v, b.row_v); } 807 | 808 | inline quat slerp(const quat &q0, const quat &q1, float t) { 809 | if (t <= 0.0f) return q0;// Check for out-of range parameter and return edge points if so 810 | if (t >= 1.0f) return q1; 811 | float cosOmega = Dot(q0, q1);// Compute "cosine of angle between quaternions" using Dot product 812 | // If negative Dot, use -q1. Two quaternions q and -q represent the same rotation, but may produce different slerp. We chose q or -q to rotate using the acute angle. 813 | 814 | vec4 tempq1(q1.row_v); 815 | if (cosOmega < 0.0f) { 816 | tempq1 *= vec4(-1.0f, -1.0f, -1.0f, -1.0f); 817 | cosOmega = -cosOmega; 818 | } 819 | // We should have two unit quaternions, so Dot should be <= 1.0 Compute interpolation fraction, checking for quaternions almost exactly the same 820 | float k0, k1; 821 | if (cosOmega > 0.9999f) {// Very close - just use linear interpolation, which will protect againt a divide by zero 822 | k0 = 1.0f - t; 823 | k1 = t; 824 | } 825 | else {// Compute the sin of the angle using the trig identi_42 sin^2(omega) + cos^2(omega) = 1 826 | float sinOmega = sqrtf(1.0f - cosOmega*cosOmega); 827 | float omega = atan2(sinOmega, cosOmega);// Compute the angle from its sin and cosine 828 | float oneOverSinOmega = 1.0f / sinOmega;// Compute inverse of denominator, so we only have to divide once 829 | k0 = sinf((1.0f - t) * omega) * oneOverSinOmega;// Compute interpolation parameters 830 | k1 = sinf(t * omega) * oneOverSinOmega; 831 | } 832 | // Interpolate 833 | return (tempq1*vec4(k1, k1, k1, k1)) + (vec4(k0, k0, k0, k0) * vec4(q0.row_v)); 834 | } 835 | 836 | //NOTE standard QUATERNION multiplication is dont opposite from standard multiplication. For example with matricies, you mutliply in the order you want the operations to occur from left to right. Like Scaling * Rotation * Translation 837 | //With quaternions, that should be opposite. However,I deviate from the standard and wrote the multiplication to occur as you would expect with the left handed coordinate system. So, write your quaternion multiplications in order of the way you want the rotations to occur 838 | inline quat operator *(const quat &a, const quat &b) {// quat cross product, which concatonates multiple angular displacements. 839 | //The order of multiplication, from left to right, corresponds to the order that the angular displacements are applied. This is backwards from the *standard* definition of quaternion multiplication. 840 | return quat(b.w*a.x + b.x*a.w + b.z*a.y - b.y*a.z, 841 | b.w*a.y + b.y*a.w + b.x*a.z - b.z*a.x, 842 | b.w*a.z + b.z*a.w + b.y*a.x - b.x*a.y, 843 | b.w*a.w - b.x*a.x - b.y*a.y - b.z*a.z); 844 | } 845 | 846 | 847 | inline quat conjugate(const quat &q) { return quat(q.w, -q.x, -q.y, -q.z); }// Compute the quaternion conjugate. This is the quaternian with the opposite rotation as the original quaternian. 848 | 849 | inline quat pow(const quat &q, float exponent) { 850 | if (fabs(q.w) > .9999f) return q;// Check for the case of an identical quaternion. This will protect against divide by zero 851 | float alpha = acosf(q.w);// Extract the half angle alpha (alpha = theta/2) 852 | float newAlpha = alpha * exponent;// Compute new alpha value 853 | float mult = sinf(newAlpha) / sinf(alpha);// Compute new xyz values 854 | return quat(q.x * mult, q.y * mult, q.z * mult, cosf(newAlpha)); 855 | } 856 | 857 | 858 | /* --------------------------------------EULER------------------------------------ */ 859 | 860 | 861 | class euler { 862 | public: 863 | 864 | union { 865 | struct { 866 | float heading, pitch, bank; 867 | }; 868 | }; 869 | euler() {} 870 | euler(float heading, float pitch, float bank) : heading(heading), pitch(pitch), bank(bank) {} 871 | euler(vec3& ang) : heading(ang.x), pitch(ang.y), bank(ang.z) {} 872 | void identity() { heading = pitch = bank = 0.0f; } 873 | 874 | void canonize() { 875 | pitch = wrapPi(pitch); // Now, check for "the back side" of the matrix, pitch outside the canonical range of -pi/2 ... pi/2 876 | if (pitch < -PIOVERTWO) { 877 | pitch = -Pi - pitch; 878 | heading += Pi; 879 | bank += Pi; 880 | } 881 | else if (pitch > PIOVERTWO) { 882 | pitch = Pi - pitch; 883 | heading += Pi; 884 | bank += Pi; 885 | }// OK, now check for the gimbel lock case (within a slight tolerance) 886 | if (fabs(pitch) > PIOVERTWO - 1e-4) { // We are in gimbel lock. Assign all rotation about the vertical axis to heading 887 | heading += bank; 888 | bank = 0.0f; 889 | } 890 | else bank = wrapPi(bank); // Not in gimbel lock. Wrap the bank angle in canonical range 891 | // Wrap heading in canonical range 892 | heading = wrapPi(heading); 893 | } 894 | void fromquat(const quat &q) {// Setup the Euler angles, given an object->inertial rotation quaternion 895 | float sp = -2.0f * (q.y*q.z - q.w*q.x);// Extract sinf(pitch) 896 | if (fabs(sp) > 0.9999f) {// Check for Gimbel lock, giving slight tolerance for numerical imprecision 897 | pitch = PIOVERTWO * sp;// Looking straight up or down 898 | heading = atan2(-q.x*q.z + q.w*q.y, 0.5f - q.y*q.y - q.z*q.z);// Compute heading, slam bank to zero 899 | bank = 0.0f; 900 | } 901 | else {// Compute angles. We don't have to use the "safe" asin function because we already checked for range errors when checking for Gimbel lock 902 | pitch = asinf(sp); 903 | heading = atan2(q.x*q.z + q.w*q.y, 0.5f - q.x*q.x - q.y*q.y); 904 | bank = atan2(q.x*q.y + q.w*q.z, 0.5f - q.x*q.x - q.z*q.z); 905 | } 906 | } 907 | inline void fromObjectToWorldMatrix(const mat4 &m); 908 | 909 | }; 910 | 911 | inline std::ostream& operator<<(std::ostream& strem, const euler& obj) { 912 | strem << "heading=" << obj.heading << " pitch=" << obj.pitch << " bank=" << obj.bank; 913 | return strem; 914 | } 915 | /* --------------------------------------MAT4------------------------------------ */ 916 | 917 | const vec4 one(1.0f, 1.0f, 1.0f, 1.0f); 918 | const vec4 two(2.0f, 2.0f, 2.0f, 2.0f); 919 | class mat4; 920 | mat4 operator*(const mat4& a, const mat4 &b); 921 | 922 | class mat4 { 923 | public: 924 | 925 | union { 926 | struct { 927 | float _11, _12, _13, _14; 928 | float _21, _22, _23, _24; 929 | float _31, _32, _33, _34; 930 | float _41, _42, _43, _44; 931 | }; 932 | float d[16]; 933 | float data[4][4]; 934 | #ifdef _WIN64 935 | __m128 rows[4]; 936 | struct { 937 | __m128 row0, row1, row2, row3; 938 | }; 939 | #endif 940 | struct {// Doesnt this matrix class have a shit ton of names for everything? good thing this doesnt cause slowdown, but it sure looks like crap doesnt it? oh well 941 | vec4 row0_v, row1_v, row2_v, row3_v; 942 | }; 943 | struct { 944 | vec4 rows_v[4]; 945 | }; 946 | }; 947 | mat4() {}// do nothing... 948 | mat4(float m_11, float m_12, float m_13, float m_14, 949 | float m_21, float m_22, float m_23, float m_24, 950 | float m_31, float m_32, float m_33, float m_34, 951 | float m_41, float m_42, float m_43, float m_44) : 952 | _11(m_11), _12(m_12), _13(m_13), _14(m_14), 953 | _21(m_21), _22(m_22), _23(m_23), _24(m_24), 954 | _31(m_31), _32(m_32), _33(m_33), _34(m_34), 955 | _41(m_41), _42(m_42), _43(m_43), _44(m_44) {} 956 | #ifdef _WIN64 957 | mat4(const __m128& nrow0, const __m128& nrow1, const __m128& nrow2, const __m128& nrow3) : row0(nrow0), row1(nrow1), row2(nrow2), row3(nrow3) {} 958 | mat4(const mat4& obj) : row0(obj.row0), row1(obj.row1), row2(obj.row2), row3(obj.row3) {} 959 | #endif 960 | mat4(const vec4& nrow0, const vec4& nrow1, const vec4& nrow2, const vec4& nrow3) : row0_v(nrow0), row1_v(nrow1), row2_v(nrow2), row3_v(nrow3) {} 961 | mat4(const Plane plane) : 962 | _11(plane.a * plane.a), _12(plane.a * plane.b), _13(plane.a * plane.c), _14(plane.a * plane.d), 963 | _21(plane.b * plane.a), _22(plane.b * plane.b), _23(plane.b * plane.c), _24(plane.b * plane.d), 964 | _31(plane.c * plane.a), _32(plane.c * plane.b), _33(plane.c * plane.c), _34(plane.c * plane.d), 965 | _41(plane.d * plane.a), _42(plane.d * plane.b), _43(plane.d * plane.c), _44(plane.d * plane.d) {} 966 | 967 | 968 | 969 | void setupfromeuler(const euler &orientation) { 970 | float sh, ch, sp, cp, sb, cb; 971 | sincosf(sh, ch, orientation.heading); 972 | sincosf(sp, cp, orientation.pitch); 973 | sincosf(sb, cb, orientation.bank); 974 | 975 | row0_v = vec4(ch * cb + sh * sp * sb, -ch * sb + sh * sp * cb, sh * cp, 0.0f); 976 | row1_v = vec4(sb * cp, cb * cp, -sp, 0.0f); 977 | row2_v = vec4(-sh * cb + ch * sp * sb, sb * sh + ch * sp * cb, ch * cp, 0.0f); 978 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 979 | 980 | } 981 | void setupfromquat(const quat &q) {// Setup the matrix to perform a rotation, given the angular displacement in quaternion form. The translation portion is reset. 982 | row0_v = vec4(-(q.y*q.y + q.z*q.z), (q.x*q.y - q.w*q.z), (q.x*q.z + q.w*q.y), 0.0f); 983 | row0_v *= two; 984 | _11 += 1.0f; 985 | row1_v = vec4((q.x*q.y + q.w*q.z), -(q.x*q.x + q.z*q.z), (q.y*q.z - q.w*q.x), 0.0f); 986 | row1_v *= two; 987 | _22 += 1.0f; 988 | row2_v = vec4((q.x*q.z - q.w*q.y), (q.y*q.z + q.w*q.x), -(q.x*q.x + q.y*q.y), 0.0f); 989 | row2_v *= two; 990 | _33 += 1.0f; 991 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 992 | } 993 | 994 | void identity() {// backwards looking, but that is because of little endian 995 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 996 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 997 | row2_v = vec4(0.0f, 0.0f, 1.0f, 0.0f); 998 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 999 | } 1000 | 1001 | void zeroTranslation() { row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); } 1002 | void setupTranslation(const vec3 &d) { 1003 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 1004 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 1005 | row2_v = vec4(0.0f, 0.0f, 1.0f, 0.0f); 1006 | row3_v = vec4(d, 1.0f); 1007 | } 1008 | vec3 getTranslation() const { return vec3(_41, _42, _43); } 1009 | void setupTranslation(float x, float y, float z) { setupTranslation(vec3(x, y, z)); } 1010 | void setTranslation(const vec3 &d) { row3_v = vec4(d, 1.0f); } 1011 | void setTranslation(float x, float y, float z) { setTranslation(vec3(x, y, z)); } 1012 | void clearRotation() { 1013 | _12 = _13 = _14 = _21 = _23 = _24 = _31 = _32 = _34 = 0.0f; 1014 | } 1015 | // The axis of rotation is specified using a 1-based index: 1 => rotate about the x-axis 2 => rotate about the y-axis 3 => rotate about the z-axis 1016 | // theta is the amount of rotation, in radians. The left-hand rule is used to define "positive" rotation. The translation portion is reset. 1017 | void setupRotateX(float theta) { 1018 | float s, c; 1019 | sincosf(s, c, theta);// Get sin and cosine of rotation angle 1020 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 1021 | row1_v = vec4(0.0f, c, s, 0.0f); 1022 | row2_v = vec4(0.0f, -s, c, 0.0f); 1023 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1024 | } 1025 | void setupRotateY(float theta) { 1026 | float s, c; 1027 | sincosf(s, c, theta);// Get sin and cosine of rotation angle 1028 | row0_v = vec4(c, 0.0f, -s, 0.0f); 1029 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 1030 | row2_v = vec4(s, 0.0f, c, 0.0f); 1031 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1032 | } 1033 | void setupRotateZ(float theta) { 1034 | float s, c; 1035 | sincosf(s, c, theta);// Get sin and cosine of rotation angle 1036 | row0_v = vec4(c, s, 0.0f, 0.0f); 1037 | row1_v = vec4(-s, c, 0.0f, 0.0f); 1038 | row2_v = vec4(0.0f, 0.0f, 1.0f, 0.0f); 1039 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1040 | } 1041 | // Setup the matrix to perform a rotation about an arbitrary axis. The axis of rotation must pass through the origin. axis defines the axis of rotation, and must be a unit std::vector. 1042 | // theta is the amount of rotation, in radians. The left-hand rule is used to define "positive" rotation. The translation portion is reset. 1043 | void setupRotate(const vec3 &axis, float theta) { 1044 | float s, c; 1045 | sincosf(s, c, theta);// Get sin and cosine of rotation angle 1046 | float a = 1.0f - c; 1047 | float ax = a * axis.x; 1048 | float ay = a * axis.y; 1049 | float az = a * axis.z; 1050 | 1051 | // Set the matrix elements. There is still a little more 1052 | // opportunity for optimization due to the many common 1053 | // subexpressions. We'll let the compiler handle that... 1054 | 1055 | _11 = ax*axis.x + c; 1056 | _12 = ax*axis.y + axis.z*s; 1057 | _13 = ax*axis.z - axis.y*s; 1058 | _14 = 0; 1059 | 1060 | _21 = ay*axis.x - axis.z*s; 1061 | _22 = ay*axis.y + c; 1062 | _23 = ay*axis.z + axis.x*s; 1063 | _24 = 0; 1064 | 1065 | _31 = az*axis.x + axis.y*s; 1066 | _32 = az*axis.y - axis.x*s; 1067 | _33 = az*axis.z + c; 1068 | _34 = 0; 1069 | // Reset the translation portion 1070 | row3_v.zero(); 1071 | _44 = 1.0f; 1072 | } 1073 | 1074 | 1075 | vec3 getScaling() const { return vec3(_11, _22, _23); } 1076 | void setupScale(const vec3 &s) { setupScale(s.x, s.y, s.z); }// Setup the matrix to perform scale on each axis. For uniform scale by k, use a std::vector of the form vec3(k,k,k) 1077 | void setupScale(float x, float y, float z) { 1078 | row0_v = vec4(x, 0.0f, 0.0f, 0.0f); 1079 | row1_v = vec4(0.0f, y, 0.0f, 0.0f); 1080 | row2_v = vec4(0.0f, 0.0f, z, 0.0f); 1081 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1082 | } 1083 | void setupScale(float unif) { setupScale(unif, unif, unif); } 1084 | void setupScaleAlongAxis(const vec3 &axis, float k) {// Setup the matrix to perform scale along an arbitrary axis. The axis is specified using a unit std::vector. 1085 | float a = k - 1.0f; 1086 | float ax = a * axis.x; 1087 | float ay = a * axis.y; 1088 | float az = a * axis.z; 1089 | // Fill in the matrix elements. We'll do the common subexpression optimization ourselves here, since diagonallyopposite matrix elements are equal 1090 | _11 = ax*axis.x + 1.0f; 1091 | _22 = ay*axis.y + 1.0f; 1092 | _32 = az*axis.z + 1.0f; 1093 | _12 = _21 = ax*axis.y; 1094 | _13 = _31 = ax*axis.z; 1095 | _23 = _32 = ay*axis.z; 1096 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1097 | } 1098 | // The _42pe of shear is specified by the 1-based "axis" index. The effect of transforming a point by the matrix is described by the pseudocode 1099 | void setupShearX(float s, float t) { 1100 | row0_v = vec4(1.0f, s, t, 0.0f); 1101 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 1102 | row2_v = vec4(0.0f, 0.0f, 1.0f, 0.0f); 1103 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1104 | } 1105 | void setupShearY(float s, float t) { 1106 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 1107 | row1_v = vec4(s, 1.0f, t, 0.0f); 1108 | row2_v = vec4(0.0f, 0.0f, 1.0f, 0.0f); 1109 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1110 | } 1111 | void setupShearZ(float s, float t) { 1112 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 1113 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 1114 | row2_v = vec4(s, t, 1.0f, 0.0f); 1115 | row3_v = vec4(0.0f, 0.0f, 0.0f, 1.0f); 1116 | } 1117 | 1118 | 1119 | void setupLookAt(const vec3& eye, const vec3& at, const vec3& up) { 1120 | vec3 zaxis(at - eye); 1121 | zaxis.normalize(); 1122 | vec3 xaxis(Cross(up, zaxis)); 1123 | xaxis.normalize(); 1124 | vec3 yaxis(Cross(zaxis, xaxis)); 1125 | row0_v = vec4(xaxis.x, yaxis.x, zaxis.x, 0.0f); 1126 | row1_v = vec4(xaxis.y, yaxis.y, zaxis.y, 0.0f); 1127 | row2_v = vec4(xaxis.z, yaxis.z, zaxis.z, 0.0f); 1128 | row3_v = vec4(-Dot(xaxis, eye), -Dot(yaxis, eye), -Dot(zaxis, eye), 1.0f); 1129 | } 1130 | 1131 | void setupProject(float fovY, float aspect, float zn, float zf) { 1132 | float yScale(1.0f / tanf(fovY*0.5f)); 1133 | float invfmn(1.0f / (zf - zn)); 1134 | row0_v = vec4(yScale / aspect, 0.0f, 0.0f, 0.0f); 1135 | row1_v = vec4(0.0f, yScale, 0.0f, 0.0f); 1136 | row2_v = vec4(0.0f, 0.0f, zf*invfmn, 1.0f); 1137 | row3_v = vec4(0.0f, 0.0f, -zn*zf*invfmn, 0.0f); 1138 | } 1139 | void setupOrtho(float w, float h, float zn, float zf) { 1140 | row0_v = vec4(2.0f / w, 0.0f, 0.0f, 0.0f); 1141 | row1_v = vec4(0.0f, 2.0f / h, 0.0f, 0.0f); 1142 | row2_v = vec4(0.0f, 0.0f, 1.0f / (zf - zn), 0.0f); 1143 | row3_v = vec4(0.0f, 0.0f, zn / (zn - zf), 1.0f); 1144 | } 1145 | // Setup the matrix to perform a reflection about a plane parallel to a cardinal plane. 1146 | void setupReflectX(float k) { 1147 | row0_v = vec4(-1.0f, 0.0f, 0.0f, 0.0f); 1148 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 1149 | row2_v = vec4(0.0f, 0.0f, 1.0f, 0.0f); 1150 | row3_v = vec4(2.0f * k, 0.0f, 0.0f, 1.0f); 1151 | } 1152 | void setupReflectY(float k) { 1153 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 1154 | row1_v = vec4(0.0f, -1.0f, 0.0f, 0.0f); 1155 | row2_v = vec4(0.0f, 1.0f, 1.0f, 0.0f); 1156 | row3_v = vec4(0.0f, 2.0f * k, 0.0f, 1.0f); 1157 | 1158 | } 1159 | void setupReflectZ(float k) { 1160 | row0_v = vec4(1.0f, 0.0f, 0.0f, 0.0f); 1161 | row1_v = vec4(0.0f, 1.0f, 0.0f, 0.0f); 1162 | row2_v = vec4(0.0f, 0.0f, -1.0f, 0.0f); 1163 | row3_v = vec4(0.0f, 0.0f, 2.0f * k, 1.0f); 1164 | } 1165 | void setupReflect(const vec3 &n) {// Setup the matrix to perform a reflection about an arbitrary plane through the origin. The unit std::vector n is perpendicular to the plane. The translation portion is reset. 1166 | float ax = -2.0f * n.x; 1167 | float ay = -2.0f * n.y; 1168 | float az = -2.0f * n.z; 1169 | // Fill in the matrix elements. We'll do the common subexpression optimization ourselves here, since diagonally opposite matrix elements are equal 1170 | _11 = 1.0f + ax*n.x; 1171 | _22 = 1.0f + ay*n.y; 1172 | _32 = 1.0f + az*n.z; 1173 | _12 = _21 = ax*n.y; 1174 | _13 = _31 = ax*n.z; 1175 | _23 = _32 = ay*n.z; 1176 | row3_v = vec4(1.0f, 0.0f, 0.0f, 1.0f); 1177 | } 1178 | 1179 | inline __m128 _mm_dot_ps(__m128 v1, __m128 v2) { 1180 | __m128 mul0 = _mm_mul_ps(v1, v2); 1181 | __m128 swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1)); 1182 | __m128 add0 = _mm_add_ps(mul0, swp0); 1183 | __m128 swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3)); 1184 | __m128 add1 = _mm_add_ps(add0, swp1); 1185 | return add1; 1186 | } 1187 | void inverse() { 1188 | #ifndef _WIN64 1189 | __m128 row0, row1, row2, row3; 1190 | copy(&row0, row0_v); 1191 | copy(&row1, row1_v); 1192 | copy(&row2, row2_v); 1193 | copy(&row3, row3_v); 1194 | #endif 1195 | __m128 Fac0; 1196 | { 1197 | __m128 Swp0a = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(3, 3, 3, 3)); 1198 | __m128 Swp0b = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(2, 2, 2, 2)); 1199 | __m128 Swp00 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(2, 2, 2, 2)); 1200 | __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); 1201 | __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); 1202 | __m128 Swp03 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(3, 3, 3, 3)); 1203 | Fac0 = _mm_sub_ps(_mm_mul_ps(Swp00, Swp01), _mm_mul_ps(Swp02, Swp03)); 1204 | } 1205 | __m128 Fac1; 1206 | { 1207 | __m128 Swp0a = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(3, 3, 3, 3)); 1208 | __m128 Swp0b = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(1, 1, 1, 1)); 1209 | __m128 Swp00 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(1, 1, 1, 1)); 1210 | __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); 1211 | __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); 1212 | __m128 Swp03 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(3, 3, 3, 3)); 1213 | Fac1 = _mm_sub_ps(_mm_mul_ps(Swp00, Swp01), _mm_mul_ps(Swp02, Swp03)); 1214 | } 1215 | __m128 Fac2; 1216 | { 1217 | __m128 Swp0a = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(2, 2, 2, 2)); 1218 | __m128 Swp0b = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(1, 1, 1, 1)); 1219 | __m128 Swp00 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(1, 1, 1, 1)); 1220 | __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); 1221 | __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); 1222 | __m128 Swp03 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(2, 2, 2, 2)); 1223 | Fac2 = _mm_sub_ps(_mm_mul_ps(Swp00, Swp01), _mm_mul_ps(Swp02, Swp03)); 1224 | } 1225 | __m128 Fac3; 1226 | { 1227 | __m128 Swp0a = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(3, 3, 3, 3)); 1228 | __m128 Swp0b = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(0, 0, 0, 0)); 1229 | __m128 Swp00 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(0, 0, 0, 0)); 1230 | __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); 1231 | __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); 1232 | __m128 Swp03 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(3, 3, 3, 3)); 1233 | Fac3 = _mm_sub_ps(_mm_mul_ps(Swp00, Swp01), _mm_mul_ps(Swp02, Swp03)); 1234 | } 1235 | __m128 Fac4; 1236 | { 1237 | __m128 Swp0a = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(2, 2, 2, 2)); 1238 | __m128 Swp0b = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(0, 0, 0, 0)); 1239 | __m128 Swp00 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(0, 0, 0, 0)); 1240 | __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); 1241 | __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); 1242 | __m128 Swp03 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(2, 2, 2, 2)); 1243 | Fac4 = _mm_sub_ps(_mm_mul_ps(Swp00, Swp01), _mm_mul_ps(Swp02, Swp03)); 1244 | } 1245 | __m128 Fac5; 1246 | { 1247 | __m128 Swp0a = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(1, 1, 1, 1)); 1248 | __m128 Swp0b = _mm_shuffle_ps(row3, row2, _MM_SHUFFLE(0, 0, 0, 0)); 1249 | __m128 Swp00 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(0, 0, 0, 0)); 1250 | __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0)); 1251 | __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0)); 1252 | __m128 Swp03 = _mm_shuffle_ps(row2, row1, _MM_SHUFFLE(1, 1, 1, 1)); 1253 | Fac5 = _mm_sub_ps(_mm_mul_ps(Swp00, Swp01), _mm_mul_ps(Swp02, Swp03)); 1254 | } 1255 | __m128 SignA = _mm_set_ps(1.0f, -1.0f, 1.0f, -1.0f); 1256 | __m128 SignB = _mm_set_ps(-1.0f, 1.0f, -1.0f, 1.0f); 1257 | __m128 Temp0 = _mm_shuffle_ps(row1, row0, _MM_SHUFFLE(0, 0, 0, 0)); 1258 | __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0)); 1259 | __m128 Temp1 = _mm_shuffle_ps(row1, row0, _MM_SHUFFLE(1, 1, 1, 1)); 1260 | __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0)); 1261 | __m128 Temp2 = _mm_shuffle_ps(row1, row0, _MM_SHUFFLE(2, 2, 2, 2)); 1262 | __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0)); 1263 | __m128 Temp3 = _mm_shuffle_ps(row1, row0, _MM_SHUFFLE(3, 3, 3, 3)); 1264 | __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0)); 1265 | __m128 Sub00 = _mm_sub_ps(_mm_mul_ps(Vec1, Fac0), _mm_mul_ps(Vec2, Fac1)); 1266 | __m128 Add00 = _mm_add_ps(Sub00, _mm_mul_ps(Vec3, Fac2)); 1267 | __m128 Inv0 = _mm_mul_ps(SignB, Add00); 1268 | __m128 Sub01 = _mm_sub_ps(_mm_mul_ps(Vec0, Fac0), _mm_mul_ps(Vec2, Fac3)); 1269 | __m128 Add01 = _mm_add_ps(Sub01, _mm_mul_ps(Vec3, Fac4)); 1270 | __m128 Inv1 = _mm_mul_ps(SignA, Add01); 1271 | __m128 Sub02 = _mm_sub_ps(_mm_mul_ps(Vec0, Fac1), _mm_mul_ps(Vec1, Fac3)); 1272 | __m128 Add02 = _mm_add_ps(Sub02, _mm_mul_ps(Vec3, Fac5)); 1273 | __m128 Inv2 = _mm_mul_ps(SignB, Add02); 1274 | __m128 Sub03 = _mm_sub_ps(_mm_mul_ps(Vec0, Fac2), _mm_mul_ps(Vec1, Fac4)); 1275 | __m128 Add03 = _mm_add_ps(Sub03, _mm_mul_ps(Vec2, Fac5)); 1276 | __m128 Inv3 = _mm_mul_ps(SignA, Add03); 1277 | __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0)); 1278 | __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0)); 1279 | __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0)); 1280 | __m128 Det0 = _mm_dot_ps(row0, Row2); 1281 | __m128 onee = _mm_set_ps1(1.0f); 1282 | __m128 Rcp0 = _mm_div_ps(onee, Det0); 1283 | row0 = _mm_mul_ps(Inv0, Rcp0); 1284 | row1 = _mm_mul_ps(Inv1, Rcp0); 1285 | row2 = _mm_mul_ps(Inv2, Rcp0); 1286 | row3 = _mm_mul_ps(Inv3, Rcp0); 1287 | #ifndef _WIN64 1288 | copy(row0_v, &row0); 1289 | copy(row1_v, &row1); 1290 | copy(row2_v, &row2); 1291 | copy(row3_v, &row3); 1292 | #endif 1293 | } 1294 | 1295 | mat4& operator=(const mat4& rhs) { 1296 | row0_v = rhs.row0_v; 1297 | row1_v = rhs.row1_v; 1298 | row2_v = rhs.row2_v; 1299 | row3_v = rhs.row3_v; 1300 | return *this; 1301 | } 1302 | 1303 | void operator*=(const float &b) { 1304 | float inv(1.0f / b); 1305 | *this = mat4(row0_v*inv, row1_v*inv, row2_v*inv, row3_v*inv); 1306 | } 1307 | 1308 | void operator-=(const mat4 &b) { 1309 | row0_v -= b.row0_v; 1310 | row1_v -= b.row1_v; 1311 | row2_v -= b.row2_v; 1312 | row3_v -= b.row3_v; 1313 | } 1314 | void operator+=(const mat4 &b) { 1315 | row0_v += b.row0_v; 1316 | row1_v += b.row1_v; 1317 | row2_v += b.row2_v; 1318 | row3_v += b.row3_v; 1319 | } 1320 | #ifdef _WIN64 1321 | void Transpose() { _MM_TRANSPOSE4_PS(row0, row1, row2, row3); } 1322 | #else 1323 | void Transpose() { 1324 | std::swap(_12, _21); 1325 | std::swap(_13, _31); 1326 | std::swap(_14, _41); 1327 | std::swap(_23, _32); 1328 | std::swap(_24, _42); 1329 | std::swap(_34, _43); 1330 | } 1331 | #endif 1332 | void operator/=(const float &b) { *this *= (1.0f / b); } 1333 | void operator*=(const mat4 &b) { *this = *this * b; } 1334 | float& operator[](size_t i) { return d[i]; } 1335 | float operator[](size_t i) const { return d[i]; } 1336 | }; 1337 | inline float determinant(const mat4& m) { 1338 | return m._11*(m._22*(m._33*m._44 - m._34*m._43) - m._32*(m._23*m._44 + m._24*m._43) + m._42*(m._23 *m._34 - m._24 * m._33)) 1339 | - m._21*(m._12*(m._33*m._44 - m._34*m._43) - m._32*(m._14*m._44 + m._14*m._43) + m._42*(m._13 *m._34 - m._14 * m._33)) 1340 | + m._31*(m._12*(m._23*m._44 - m._24*m._43) - m._22*(m._13*m._44 + m._14*m._43) + m._42*(m._13 *m._24 - m._14 * m._23)) 1341 | - m._41*(m._12*(m._23*m._34 - m._24*m._33) - m._22*(m._13*m._34 + m._14*m._33) + m._32*(m._13 *m._24 - m._14 * m._23)); 1342 | } 1343 | inline mat4 operator - (const mat4 &a, const mat4 &b) { return mat4(a.row0_v - b.row0_v, a.row1_v - b.row1_v, a.row2_v - b.row2_v, a.row3_v - b.row3_v); } 1344 | inline mat4 operator + (const mat4 &a, const mat4 &b) { return mat4(a.row0_v + b.row0_v, a.row1_v + b.row1_v, a.row2_v + b.row2_v, a.row3_v + b.row3_v); } 1345 | inline mat4 operator*(const mat4& a, const float &b) { return mat4(a.row0_v*b, a.row1_v*b, a.row2_v*b, a.row3_v*b); } 1346 | inline mat4 operator/ (const mat4 &m, const float &b) { return mat4(m*(1.0f / b)); } 1347 | #ifdef _WIN64 1348 | inline mat4 operator*(const mat4& a, const mat4 &b) { 1349 | __m128 r0; 1350 | { 1351 | __m128 e0 = _mm_shuffle_ps(a.row0, a.row0, _MM_SHUFFLE(0, 0, 0, 0)); 1352 | __m128 e1 = _mm_shuffle_ps(a.row0, a.row0, _MM_SHUFFLE(1, 1, 1, 1)); 1353 | __m128 e2 = _mm_shuffle_ps(a.row0, a.row0, _MM_SHUFFLE(2, 2, 2, 2)); 1354 | __m128 e3 = _mm_shuffle_ps(a.row0, a.row0, _MM_SHUFFLE(3, 3, 3, 3)); 1355 | r0 = _mm_add_ps(_mm_add_ps(_mm_mul_ps(b.row0, e0), _mm_mul_ps(b.row1, e1)), _mm_add_ps(_mm_mul_ps(b.row2, e2), _mm_mul_ps(b.row3, e3))); 1356 | } 1357 | __m128 r1; 1358 | { 1359 | __m128 e0 = _mm_shuffle_ps(a.row1, a.row1, _MM_SHUFFLE(0, 0, 0, 0)); 1360 | __m128 e1 = _mm_shuffle_ps(a.row1, a.row1, _MM_SHUFFLE(1, 1, 1, 1)); 1361 | __m128 e2 = _mm_shuffle_ps(a.row1, a.row1, _MM_SHUFFLE(2, 2, 2, 2)); 1362 | __m128 e3 = _mm_shuffle_ps(a.row1, a.row1, _MM_SHUFFLE(3, 3, 3, 3)); 1363 | r1 = _mm_add_ps(_mm_add_ps(_mm_mul_ps(b.row0, e0), _mm_mul_ps(b.row1, e1)), _mm_add_ps(_mm_mul_ps(b.row2, e2), _mm_mul_ps(b.row3, e3))); 1364 | } 1365 | __m128 r2; 1366 | { 1367 | __m128 e0 = _mm_shuffle_ps(a.row2, a.row2, _MM_SHUFFLE(0, 0, 0, 0)); 1368 | __m128 e1 = _mm_shuffle_ps(a.row2, a.row2, _MM_SHUFFLE(1, 1, 1, 1)); 1369 | __m128 e2 = _mm_shuffle_ps(a.row2, a.row2, _MM_SHUFFLE(2, 2, 2, 2)); 1370 | __m128 e3 = _mm_shuffle_ps(a.row2, a.row2, _MM_SHUFFLE(3, 3, 3, 3)); 1371 | r2 = _mm_add_ps(_mm_add_ps(_mm_mul_ps(b.row0, e0), _mm_mul_ps(b.row1, e1)), _mm_add_ps(_mm_mul_ps(b.row2, e2), _mm_mul_ps(b.row3, e3))); 1372 | } 1373 | __m128 r3; 1374 | { 1375 | __m128 e0 = _mm_shuffle_ps(a.row3, a.row3, _MM_SHUFFLE(0, 0, 0, 0)); 1376 | __m128 e1 = _mm_shuffle_ps(a.row3, a.row3, _MM_SHUFFLE(1, 1, 1, 1)); 1377 | __m128 e2 = _mm_shuffle_ps(a.row3, a.row3, _MM_SHUFFLE(2, 2, 2, 2)); 1378 | __m128 e3 = _mm_shuffle_ps(a.row3, a.row3, _MM_SHUFFLE(3, 3, 3, 3)); 1379 | r3 = _mm_add_ps(_mm_add_ps(_mm_mul_ps(b.row0, e0), _mm_mul_ps(b.row1, e1)), _mm_add_ps(_mm_mul_ps(b.row2, e2), _mm_mul_ps(b.row3, e3))); 1380 | } 1381 | return mat4(r0, r1, r2, r3); 1382 | 1383 | } 1384 | #else 1385 | inline mat4 operator*(const mat4& a, const mat4 &b) { 1386 | 1387 | return mat4( 1388 | a._11*b._11 + a._12*b._21 + a._13*b._31 + a._14*b._41, 1389 | a._11*b._12 + a._12*b._22 + a._13*b._32 + a._14*b._42, 1390 | a._11*b._13 + a._12*b._23 + a._13*b._33 + a._14*b._43, 1391 | a._11*b._14 + a._12*b._24 + a._13*b._34 + a._14*b._44, 1392 | 1393 | a._21*b._11 + a._22*b._21 + a._23*b._31 + a._24*b._41, 1394 | a._21*b._12 + a._22*b._22 + a._23*b._32 + a._24*b._42, 1395 | a._21*b._13 + a._22*b._23 + a._23*b._33 + a._24*b._43, 1396 | a._21*b._14 + a._22*b._24 + a._23*b._34 + a._24*b._44, 1397 | 1398 | a._31*b._11 + a._32*b._21 + a._33*b._31 + a._34*b._41, 1399 | a._31*b._12 + a._32*b._22 + a._33*b._32 + a._34*b._42, 1400 | a._31*b._13 + a._32*b._23 + a._33*b._33 + a._34*b._43, 1401 | a._31*b._14 + a._32*b._24 + a._33*b._34 + a._34*b._44, 1402 | 1403 | a._41*b._11 + a._42*b._21 + a._43*b._31 + a._44*b._41, 1404 | a._41*b._12 + a._42*b._22 + a._43*b._32 + a._44*b._42, 1405 | a._41*b._13 + a._42*b._23 + a._43*b._33 + a._44*b._43, 1406 | a._41*b._14 + a._42*b._24 + a._43*b._34 + a._44*b._44); 1407 | } 1408 | 1409 | #endif 1410 | 1411 | 1412 | inline mat4 abs(const mat4 &mat) { 1413 | return mat4(abs(mat.row0_v), abs(mat.row1_v), abs(mat.row2_v), abs(mat.row3_v)); 1414 | } 1415 | 1416 | inline std::ostream& operator<<(std::ostream& strem, const mat4& obj) { 1417 | strem << "row0 " << std::endl << obj.row0_v << "row1 " << obj.row1_v << std::endl << "row 2 " << obj.row2_v << std::endl << "row3 " << obj.row3_v << std::endl; 1418 | return strem; 1419 | } 1420 | inline vec4 operator*(const vec4 &p, const mat4 &m) { 1421 | return vec4( 1422 | p.x*m._11 + p.y*m._21 + p.z*m._31 + p.w*m._41, 1423 | p.x*m._12 + p.y*m._22 + p.z*m._32 + p.w*m._42, 1424 | p.x*m._13 + p.y*m._23 + p.z*m._33 + p.w*m._43, 1425 | p.x*m._14 + p.y*m._24 + p.z*m._34 + p.w*m._44); 1426 | } 1427 | inline vec3 operator*(const vec3 &p, const mat4 &m) { 1428 | return vec3( 1429 | p.x*m._11 + p.y*m._21 + p.z*m._31 + m._41, 1430 | p.x*m._12 + p.y*m._22 + p.z*m._32 + m._42, 1431 | p.x*m._13 + p.y*m._23 + p.z*m._33 + m._43); 1432 | } 1433 | inline void operator*=(vec3 &p, const mat4 &m) { 1434 | p = vec3( 1435 | p.x*m._11 + p.y*m._21 + p.z*m._31 + m._41, 1436 | p.x*m._12 + p.y*m._22 + p.z*m._32 + m._42, 1437 | p.x*m._13 + p.y*m._23 + p.z*m._33 + m._43); 1438 | 1439 | } 1440 | inline void operator*=(vec4 &p, const mat4 &m) { 1441 | p = vec4( 1442 | p.x*m._11 + p.y*m._21 + p.z*m._31 + p.w*m._41, 1443 | p.x*m._12 + p.y*m._22 + p.z*m._32 + p.w*m._42, 1444 | p.x*m._13 + p.y*m._23 + p.z*m._33 + p.w*m._43, 1445 | p.x*m._14 + p.y*m._24 + p.z*m._34 + p.w*m._44); 1446 | } 1447 | 1448 | inline void Transform(const vec3& in, vec4& out, const mat4& mat) { out = in; out.w = 1.0f; out *= mat; } 1449 | inline void Transform(const vec4& in, vec4& out, const mat4& mat) { out = in; out *= mat; } 1450 | inline void Transform(const vec3& in, vec3& out, const mat4& mat) { out = in; out *= mat; } 1451 | inline void TransformNormal(const vec3& in, vec4& out, const mat4& mat) { out = in; out.w = 0.0f; out *= mat; } 1452 | inline void TransformNormal(const vec3& in, vec3& out, const mat4& mat) { 1453 | out.x = in.x*mat._11 + in.y*mat._21 + in.z*mat._31; 1454 | out.y = in.x*mat._12 + in.y*mat._22 + in.z*mat._32; 1455 | out.z = in.x*mat._13 + in.y*mat._23 + in.z*mat._33; 1456 | } 1457 | inline void TransformNormal(vec3& inout, const mat4& m) { 1458 | inout = vec3(inout.x*m._11 + inout.y*m._21 + inout.z*m._31, 1459 | inout.x*m._12 + inout.y*m._22 + inout.z*m._32, 1460 | inout.x*m._13 + inout.y*m._23 + inout.z*m._33); 1461 | }; 1462 | inline void TransformNormal(vec4& inout, const mat4& m) { inout.w = 0.0f; inout *= m; } 1463 | 1464 | // returns the screen coords of a 3d coord. The coords will be in terms of pixels, with the top left corner being (0, 0) 1465 | inline vec2 Project(const vec3& worldspacepos, const mat4& view, const mat4& proj, const float screenwidth, const float screenheight) { 1466 | vec4 w(worldspacepos, 1.0f); 1467 | w *= (view*proj); 1468 | w /= w.w; 1469 | return vec2(((w.x + 1.0f) * screenwidth *.5f) + 1.0f, ((1.0f - w.y) * screenheight *.5f) + 1.0f); 1470 | } 1471 | // returns a normalized vector and an origin from a screenspace coord. Since the input is a 2d screen space coord, all the information cannot be retrived, i.e. where exactly does the point exist? It could exist along the ray starting at the origin 1472 | //screenspace should be in terms of pixels with the top left being (0, 0) 1473 | inline void UnProject(const vec2& screenspacepos, const mat4& view, const mat4& proj, const float screenwidth, const float screenheight, vec3& outray, vec3& outorigin) { 1474 | float vx = (2.0f*screenspacepos.x / screenwidth - 1.0f) / proj._11;// Compute picking ray in view space. 1475 | float vy = (-2.0f*screenspacepos.y / screenheight + 1.0f) / proj._22; 1476 | mat4 inverseV(view); 1477 | inverseV.inverse(); 1478 | outorigin = vec3(0.0f, 0.0f, 0.0f); 1479 | outray = vec3(vx, vy, 1.0f); 1480 | outorigin *= inverseV;// this function actually translated the point 1481 | TransformNormal(outray, inverseV);// this function does not translate the vector, it only changes the direction into the new coordinate system 1482 | outray.normalize(); 1483 | } 1484 | inline mat4 GetTexScaleBiasMatrix(float size) {// Calculate a matrix to transform points to texture coordinates 1485 | float fTexOffset = 0.5f + (0.5f / size); 1486 | return mat4(0.5f, 0.0f, 0.0f, 0.0f, 1487 | 0.0f, -0.5f, 0.0f, 0.0f, 1488 | 0.0f, 0.0f, 1.0f, 0.0f, 1489 | fTexOffset, fTexOffset, 0.0f, 1.0f); 1490 | } 1491 | inline mat4 mirrorMatrix(const vec3 &planeNormal, const float planeOffset) { 1492 | return mat4( 1493 | 1 - 2 * planeNormal.x * planeNormal.x, 1494 | -2 * planeNormal.x * planeNormal.y, 1495 | -2 * planeNormal.x * planeNormal.z, 1496 | -2 * planeNormal.x * planeOffset, 1497 | 1498 | -2 * planeNormal.y * planeNormal.x, 1499 | 1 - 2 * planeNormal.y * planeNormal.y, 1500 | -2 * planeNormal.y * planeNormal.z, 1501 | -2 * planeNormal.y * planeOffset, 1502 | 1503 | -2 * planeNormal.z * planeNormal.x, 1504 | -2 * planeNormal.z * planeNormal.y, 1505 | 1 - 2 * planeNormal.z * planeNormal.z, 1506 | -2 * planeNormal.z * planeOffset, 1507 | 1508 | 0, 0, 0, 1); 1509 | } 1510 | 1511 | 1512 | inline void quat::frommatrix(const mat4& pm) { 1513 | float wsqrdminus1 = pm._11 + pm._22 + pm._33; 1514 | float xsqrdminus1 = pm._11 - pm._22 - pm._33; 1515 | float ysqrdminus1 = pm._22 - pm._11 - pm._33; 1516 | float zsqrdminus1 = pm._33 - pm._11 - pm._22; 1517 | int biggestindex = 0; 1518 | float biggest = wsqrdminus1; 1519 | if (xsqrdminus1 > biggest) { 1520 | biggest = xsqrdminus1; 1521 | biggestindex = 1; 1522 | } 1523 | if (ysqrdminus1 > biggest) { 1524 | biggest = ysqrdminus1; 1525 | biggestindex = 2; 1526 | } 1527 | if (zsqrdminus1 > biggest) { 1528 | biggest = zsqrdminus1; 1529 | biggestindex = 3; 1530 | } 1531 | float biggestval = sqrtf(biggest + 1.0f)*.5f; 1532 | float mult = .25f / biggestval; 1533 | switch (biggestindex) { 1534 | case 0: 1535 | w = biggestval; 1536 | x = (pm._23 - pm._32) * mult; 1537 | y = (pm._31 - pm._13) * mult; 1538 | z = (pm._12 - pm._21) * mult; 1539 | break; 1540 | case 1: 1541 | x = biggestval; 1542 | w = (pm._23 - pm._32) * mult; 1543 | y = (pm._12 + pm._21) * mult; 1544 | z = (pm._31 + pm._13) * mult; 1545 | break; 1546 | case 2: 1547 | y = biggestval; 1548 | w = (pm._31 - pm._13) * mult; 1549 | x = (pm._12 + pm._21) * mult; 1550 | z = (pm._23 + pm._32) * mult; 1551 | break; 1552 | case 3: 1553 | z = biggestval; 1554 | w = (pm._13 - pm._21) * mult; 1555 | x = (pm._31 + pm._13) * mult; 1556 | y = (pm._23 + pm._32) * mult; 1557 | break; 1558 | }; 1559 | } 1560 | 1561 | inline void quat::SetupRotation(const euler &orientation) { SetupRotation(orientation.heading, orientation.pitch, orientation.bank); } 1562 | 1563 | inline void euler::fromObjectToWorldMatrix(const mat4 &m) {// The matrix is assumed to be orthogonal. The translation portion is ignored. 1564 | float sp = -m._32;// Extract sin32(pitch) from _32. 1565 | if (fabs(sp) > 9.99999f) {// Check for Gimbel lock 1566 | pitch = PIOVERTWO * sp;// Looking straight up or down 1567 | heading = atan2(-m._23, m._11);// Compute heading, slam bank to zero 1568 | bank = 0.0f; 1569 | } 1570 | else { 1571 | heading = atan2(m._31, m._33); 1572 | pitch = asinf(sp); 1573 | bank = atan2(m._12, m._22); 1574 | } 1575 | } 1576 | 1577 | 1578 | 1579 | inline bool InsideFrustum(const vec3& point, const Plane planes[6]) {// make sure the point is in WORLD SPACE.. as the view frustum is in WORLD SPACE 1580 | for (size_t i(0); i< 6; i++) {// this will test all 6 planes, but will return as early as possible 1581 | if (Dot(point, planes[i]) - planes[i].d <= 0.0f) return false;// early out, if outside of one, outside of all.... 1582 | } 1583 | return true;// inside the frustum. Unfortunaly, all planes must be checked 1584 | } 1585 | inline bool InsideFrustum(const vec3& point, float radiussquared, const Plane planes[6]) {// for spheres. Take note that I use squared Length below.. 1586 | for (size_t i = 0; i<6; i++) { 1587 | if (Dot(point, planes[i]) + planes[i].d <= -radiussquared) return false; 1588 | } 1589 | return true; 1590 | } 1591 | 1592 | inline void ExtractPlanesD3D(Plane* p_planes, const mat4& comboMatrix, bool normalize) { 1593 | // Left clipping plane 1594 | p_planes[0].a = comboMatrix._14 + comboMatrix._11; 1595 | p_planes[0].b = comboMatrix._24 + comboMatrix._21; 1596 | p_planes[0].c = comboMatrix._34 + comboMatrix._31; 1597 | p_planes[0].d = comboMatrix._44 + comboMatrix._41; 1598 | // Right clipping plane 1599 | p_planes[1].a = comboMatrix._14 - comboMatrix._11; 1600 | p_planes[1].b = comboMatrix._24 - comboMatrix._21; 1601 | p_planes[1].c = comboMatrix._34 - comboMatrix._31; 1602 | p_planes[1].d = comboMatrix._44 - comboMatrix._41; 1603 | // Near clipping plane 1604 | p_planes[2].a = comboMatrix._13; 1605 | p_planes[2].b = comboMatrix._23; 1606 | p_planes[2].c = comboMatrix._33; 1607 | p_planes[2].d = comboMatrix._43; 1608 | // Far clipping plane 1609 | p_planes[3].a = comboMatrix._14 - comboMatrix._13; 1610 | p_planes[3].b = comboMatrix._24 - comboMatrix._23; 1611 | p_planes[3].c = comboMatrix._34 - comboMatrix._33; 1612 | p_planes[3].d = comboMatrix._44 - comboMatrix._43; 1613 | // Top clipping plane 1614 | p_planes[4].a = comboMatrix._14 - comboMatrix._12; 1615 | p_planes[4].b = comboMatrix._24 - comboMatrix._22; 1616 | p_planes[4].c = comboMatrix._34 - comboMatrix._32; 1617 | p_planes[4].d = comboMatrix._44 - comboMatrix._42; 1618 | // Bottom clipping plane 1619 | p_planes[5].a = comboMatrix._14 + comboMatrix._12; 1620 | p_planes[5].b = comboMatrix._24 + comboMatrix._22; 1621 | p_planes[5].c = comboMatrix._34 + comboMatrix._32; 1622 | p_planes[5].d = comboMatrix._44 + comboMatrix._42; 1623 | // Normalize the plane equations, if requested 1624 | if (normalize == true) { 1625 | p_planes[0].Normalize(); 1626 | p_planes[1].Normalize(); 1627 | p_planes[2].Normalize(); 1628 | p_planes[3].Normalize(); 1629 | p_planes[4].Normalize(); 1630 | p_planes[5].Normalize(); 1631 | } 1632 | } 1633 | 1634 | /* 1635 | fov must be in radians, dy_pixels is the number of pixels of movment, screen_y_size is the total number of pixels in the y dimension of the screen 1636 | This function is used to find out how many radians of movement has occurned given a specific number of pixels. 1637 | For example, you move your mouse 3 pixels to the left and you want to know how many radians of movement that is, call this function. 1638 | */ 1639 | inline float Screen_y_Pixels_To_Radians(int dy_pixels, float fov, float screen_y_size) { 1640 | return (fov / screen_y_size)*(float)dy_pixels; 1641 | } 1642 | //fov must be in radians, dx_pixels is the number of pixels of movment, screen_x_size is the total number of pixels in the x dimension of the screen. aspect is the aspect of the camera 1643 | inline float Screen_x_Pixels_To_Radians(int dx_pixels, float fov, float screen_x_size, float aspect) { 1644 | return ((fov / screen_x_size)*(float)dx_pixels) / aspect; 1645 | } 1646 | 1647 | 1648 | 1649 | inline float Sphere_RayIntersect(const vec3 center, const float radius, const vec3& rayOrigin, const vec3& rayDir) { 1650 | vec3 l(center - rayOrigin); 1651 | float s(Dot(l, rayDir));// Lengthance 1652 | float lsq(Dot(l, l)); 1653 | if ((s < 0.0f) & (lsq > radius*radius)) return INFINITY;// missed the sphere 1654 | float msq(lsq - s*s); 1655 | if (msq > radius*radius) return INFINITY;// missed the sphere 1656 | return s; 1657 | } 1658 | 1659 | 1660 | 1661 | 1662 | 1663 | 1664 | #endif 1665 | 1666 | 1667 | 1668 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Assimp_Animation_Helper 2 | Assimp animation pre processor 3 | 4 | Its been a long time since I wrote this, but if anyone wants to clean this up, please issue a PR. 5 | -------------------------------------------------------------------------------- /cAnimationController.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "cAnimationController.h" 3 | 4 | void TransformMatrix(mat4& out,const aiMatrix4x4& in){// there is some type of alignment issue with my mat4 and the aimatrix4x4 class, so the copy must be manually 5 | out._11=in.a1; 6 | out._12=in.a2; 7 | out._13=in.a3; 8 | out._14=in.a4; 9 | 10 | out._21=in.b1; 11 | out._22=in.b2; 12 | out._23=in.b3; 13 | out._24=in.b4; 14 | 15 | out._31=in.c1; 16 | out._32=in.c2; 17 | out._33=in.c3; 18 | out._34=in.c4; 19 | 20 | out._41=in.d1; 21 | out._42=in.d2; 22 | out._43=in.d3; 23 | out._44=in.d4; 24 | } 25 | // ------------------------------------------------------------------------------------------------ 26 | // Constructor on a given animation. 27 | cAnimEvaluator::cAnimEvaluator( const aiAnimation* pAnim) { 28 | mLastTime = 0.0; 29 | TicksPerSecond = static_cast(pAnim->mTicksPerSecond != 0.0f ? pAnim->mTicksPerSecond : 100.0f); 30 | Duration = static_cast(pAnim->mDuration); 31 | Name = pAnim->mName.data; 32 | //OUTPUT_DEBUG_MSG("Creating Animation named: "<mNumChannels); 34 | for( unsigned int a = 0; a < pAnim->mNumChannels; a++){ 35 | Channels[a].Name = pAnim->mChannels[a]->mNodeName.data; 36 | for(unsigned int i(0); i< pAnim->mChannels[a]->mNumPositionKeys; i++) Channels[a].mPositionKeys.push_back(pAnim->mChannels[a]->mPositionKeys[i]); 37 | for(unsigned int i(0); i< pAnim->mChannels[a]->mNumRotationKeys; i++) Channels[a].mRotationKeys.push_back(pAnim->mChannels[a]->mRotationKeys[i]); 38 | for(unsigned int i(0); i< pAnim->mChannels[a]->mNumScalingKeys; i++) Channels[a].mScalingKeys.push_back(pAnim->mChannels[a]->mScalingKeys[i]); 39 | } 40 | mLastPositions.resize( pAnim->mNumChannels, std::make_tuple( 0, 0, 0)); 41 | //OUTPUT_DEBUG_MSG("Finished Creating Animation named: "< 0.0) 50 | time = fmod( ptime, Duration); 51 | 52 | float percent = time / Duration; 53 | if(!PlayAnimationForward) percent= (percent-1.0f)*-1.0f;// this will invert the percent so the animation plays backwards 54 | return static_cast(( static_cast(Transforms.size()) * percent)); 55 | } 56 | void cAnimEvaluator::Save(std::ofstream& file){ 57 | uint32_t nsize = static_cast(Name.size()); 58 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the size of the animation name 59 | file.write(Name.c_str(), nsize);// the size of the animation name 60 | file.write(reinterpret_cast(&Duration), sizeof(Duration));// the duration 61 | file.write(reinterpret_cast(&TicksPerSecond), sizeof(TicksPerSecond));// the number of ticks per second 62 | nsize = static_cast(Channels.size());// number of animation channels, 63 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number animation channels 64 | for(size_t j(0); j< Channels.size(); j++){// for each channel 65 | nsize =static_cast(Channels[j].Name.size()); 66 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the size of the name 67 | file.write(Channels[j].Name.c_str(), nsize);// the size of the animation name 68 | 69 | nsize =static_cast(Channels[j].mPositionKeys.size()); 70 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of position keys 71 | for(size_t i(0); i< nsize; i++){// for each channel 72 | file.write(reinterpret_cast(&Channels[j].mPositionKeys[i].mTime), sizeof(Channels[j].mPositionKeys[i].mTime));// pos key 73 | file.write(reinterpret_cast(&Channels[j].mPositionKeys[i].mValue), sizeof(Channels[j].mPositionKeys[i].mValue));// pos key 74 | } 75 | 76 | nsize =static_cast(Channels[j].mRotationKeys.size()); 77 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of position keys 78 | for(size_t i(0); i< nsize; i++){// for each channel 79 | file.write(reinterpret_cast(&Channels[j].mRotationKeys[i].mTime), sizeof(Channels[j].mRotationKeys[i].mTime));// rot key 80 | file.write(reinterpret_cast(&Channels[j].mRotationKeys[i].mValue), sizeof(Channels[j].mRotationKeys[i].mValue));// rot key 81 | } 82 | 83 | nsize =static_cast(Channels[j].mScalingKeys.size()); 84 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of position keys 85 | for(size_t i(0); i< nsize; i++){// for each channel 86 | file.write(reinterpret_cast(&Channels[j].mScalingKeys[i].mTime), sizeof(Channels[j].mScalingKeys[i].mTime));// rot key 87 | file.write(reinterpret_cast(&Channels[j].mScalingKeys[i].mValue), sizeof(Channels[j].mScalingKeys[i].mValue));// rot key 88 | } 89 | 90 | } 91 | } 92 | void cAnimEvaluator::Load(std::ifstream& file){ 93 | uint32_t nsize = 0; 94 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the size of the animation name 95 | char temp[250]; 96 | file.read(temp, nsize);// the size of the animation name 97 | temp[nsize]=0;// null char 98 | Name=temp; 99 | //OUTPUT_DEBUG_MSG("Creating Animation named: "<(&Duration), sizeof(Duration));// the duration 101 | file.read(reinterpret_cast(&TicksPerSecond), sizeof(TicksPerSecond));// the number of ticks per second 102 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number animation channels 103 | Channels.resize(nsize); 104 | for(size_t j(0); j< Channels.size(); j++){// for each channel 105 | nsize =0; 106 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the size of the name 107 | file.read(temp, nsize);// the size of the animation name 108 | temp[nsize]=0;// null char 109 | Channels[j].Name=temp; 110 | 111 | nsize =static_cast(Channels[j].mPositionKeys.size()); 112 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of position keys 113 | Channels[j].mPositionKeys.resize(nsize); 114 | for(size_t i(0); i< nsize; i++){// for each channel 115 | file.read(reinterpret_cast(&Channels[j].mPositionKeys[i].mTime), sizeof(Channels[j].mPositionKeys[i].mTime));// pos key 116 | file.read(reinterpret_cast(&Channels[j].mPositionKeys[i].mValue), sizeof(Channels[j].mPositionKeys[i].mValue));// pos key 117 | } 118 | 119 | nsize =static_cast(Channels[j].mRotationKeys.size()); 120 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of position keys 121 | Channels[j].mRotationKeys.resize(nsize); 122 | for(size_t i(0); i< nsize; i++){// for each channel 123 | file.read(reinterpret_cast(&Channels[j].mRotationKeys[i].mTime), sizeof(Channels[j].mRotationKeys[i].mTime));// pos key 124 | file.read(reinterpret_cast(&Channels[j].mRotationKeys[i].mValue), sizeof(Channels[j].mRotationKeys[i].mValue));// pos key 125 | } 126 | 127 | nsize =static_cast(Channels[j].mScalingKeys.size()); 128 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of position keys 129 | Channels[j].mScalingKeys.resize(nsize); 130 | for(size_t i(0); i< nsize; i++){// for each channel 131 | file.read(reinterpret_cast(&Channels[j].mScalingKeys[i].mTime), sizeof(Channels[j].mScalingKeys[i].mTime));// pos key 132 | file.read(reinterpret_cast(&Channels[j].mScalingKeys[i].mValue), sizeof(Channels[j].mScalingKeys[i].mValue));// pos key 133 | } 134 | } 135 | mLastPositions.resize( Channels.size(), std::make_tuple( 0, 0, 0)); 136 | } 137 | // ------------------------------------------------------------------------------------------------ 138 | // Evaluates the animation tracks for a given time stamp. 139 | void cAnimEvaluator::Evaluate( float pTime, std::map& bones) { 140 | 141 | pTime *= TicksPerSecond; 142 | 143 | float time = 0.0f; 144 | if( Duration > 0.0) 145 | time = fmod( pTime, Duration); 146 | 147 | // calculate the transformations for each animation channel 148 | for( unsigned int a = 0; a < Channels.size(); a++){ 149 | const cAnimationChannel* channel = &Channels[a]; 150 | std::map::iterator bonenode = bones.find(channel->Name); 151 | 152 | if(bonenode == bones.end()) { 153 | OUTPUT_DEBUG_MSG("did not find the bone node "<Name); 154 | continue; 155 | } 156 | 157 | // ******** Position ***** 158 | aiVector3D presentPosition( 0, 0, 0); 159 | if( channel->mPositionKeys.size() > 0){ 160 | // Look for present frame number. Search from last position if time is after the last time, else from beginning 161 | // Should be much quicker than always looking from start for the average use case. 162 | unsigned int frame = (time >= mLastTime) ? std::get<0>(mLastPositions[a]): 0; 163 | while( frame < channel->mPositionKeys.size() - 1){ 164 | if( time < channel->mPositionKeys[frame+1].mTime){ 165 | break; 166 | } 167 | frame++; 168 | } 169 | 170 | // interpolate between this frame's value and next frame's value 171 | unsigned int nextFrame = (frame + 1) % channel->mPositionKeys.size(); 172 | 173 | const aiVectorKey& key = channel->mPositionKeys[frame]; 174 | const aiVectorKey& nextKey = channel->mPositionKeys[nextFrame]; 175 | double diffTime = nextKey.mTime - key.mTime; 176 | if( diffTime < 0.0) 177 | diffTime += Duration; 178 | if( diffTime > 0) { 179 | float factor = float( (time - key.mTime) / diffTime); 180 | presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; 181 | } else { 182 | presentPosition = key.mValue; 183 | } 184 | std::get<0>(mLastPositions[a]) = frame; 185 | } 186 | // ******** Rotation ********* 187 | aiQuaternion presentRotation( 1, 0, 0, 0); 188 | if( channel->mRotationKeys.size() > 0) 189 | { 190 | unsigned int frame = (time >= mLastTime) ? std::get<1>(mLastPositions[a]) : 0; 191 | while( frame < channel->mRotationKeys.size() - 1){ 192 | if( time < channel->mRotationKeys[frame+1].mTime) 193 | break; 194 | frame++; 195 | } 196 | 197 | // interpolate between this frame's value and next frame's value 198 | unsigned int nextFrame = (frame + 1) % channel->mRotationKeys.size() ; 199 | 200 | const aiQuatKey& key = channel->mRotationKeys[frame]; 201 | const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame]; 202 | double diffTime = nextKey.mTime - key.mTime; 203 | if( diffTime < 0.0) diffTime += Duration; 204 | if( diffTime > 0) { 205 | float factor = float( (time - key.mTime) / diffTime); 206 | aiQuaternion::Interpolate( presentRotation, key.mValue, nextKey.mValue, factor); 207 | } else presentRotation = key.mValue; 208 | std::get<1>(mLastPositions[a]) = frame; 209 | } 210 | 211 | // ******** Scaling ********** 212 | aiVector3D presentScaling( 1, 1, 1); 213 | if( channel->mScalingKeys.size() > 0) { 214 | unsigned int frame = (time >= mLastTime) ? std::get<2>(mLastPositions[a]) : 0; 215 | while( frame < channel->mScalingKeys.size() - 1){ 216 | if( time < channel->mScalingKeys[frame+1].mTime) 217 | break; 218 | frame++; 219 | } 220 | 221 | presentScaling = channel->mScalingKeys[frame].mValue; 222 | std::get<2>(mLastPositions[a]) = frame; 223 | } 224 | 225 | aiMatrix4x4 mat = aiMatrix4x4( presentRotation.GetMatrix()); 226 | 227 | mat.a1 *= presentScaling.x; mat.b1 *= presentScaling.x; mat.c1 *= presentScaling.x; 228 | mat.a2 *= presentScaling.y; mat.b2 *= presentScaling.y; mat.c2 *= presentScaling.y; 229 | mat.a3 *= presentScaling.z; mat.b3 *= presentScaling.z; mat.c3 *= presentScaling.z; 230 | mat.a4 = presentPosition.x; mat.b4 = presentPosition.y; mat.c4 = presentPosition.z; 231 | mat.Transpose(); 232 | 233 | TransformMatrix(bonenode->second->LocalTransform, mat); 234 | } 235 | mLastTime = time; 236 | } 237 | 238 | void SceneAnimator::Release(){// this should clean everything up 239 | CurrentAnimIndex = -1; 240 | Animations.clear();// clear all animations 241 | delete Skeleton;// This node will delete all children recursivly 242 | Skeleton = NULL;// make sure to zero it out 243 | } 244 | void SceneAnimator::Init(const aiScene* pScene){// this will build the skeleton based on the scene passed to it and CLEAR EVERYTHING 245 | if(!pScene->HasAnimations()) return; 246 | Release(); 247 | 248 | Skeleton = CreateBoneTree( pScene->mRootNode, NULL); 249 | ExtractAnimations(pScene); 250 | 251 | for (unsigned int i = 0; i < pScene->mNumMeshes;++i){ 252 | const aiMesh* mesh = pScene->mMeshes[i]; 253 | 254 | for (unsigned int n = 0; n < mesh->mNumBones;++n){ 255 | const aiBone* bone = mesh->mBones[n]; 256 | std::map::iterator found = BonesByName.find(bone->mName.data); 257 | if(found != BonesByName.end()){// FOUND IT!!! woohoo, make sure its not already in the bone list 258 | bool skip = false; 259 | for(size_t j(0); j< Bones.size(); j++){ 260 | std::string bname = bone->mName.data; 261 | if(Bones[j]->Name == bname) { 262 | skip = true;// already inserted, skip this so as not to insert the same bone multiple times 263 | break; 264 | } 265 | } 266 | if(!skip){// only insert the bone if it has not already been inserted 267 | std::string tes = found->second->Name; 268 | TransformMatrix(found->second->Offset, bone->mOffsetMatrix); 269 | found->second->Offset.Transpose();// transpoce their matrix to get in the correct format 270 | Bones.push_back(found->second); 271 | BonesToIndex[found->first] = Bones.size()-1; 272 | } 273 | } 274 | } 275 | } 276 | Transforms.resize( Bones.size()); 277 | float timestep = 1.0f/30.0f;// 30 per second 278 | for(size_t i(0); i< Animations.size(); i++){// pre calculate the animations 279 | SetAnimIndex(i); 280 | float dt = 0; 281 | for(float ticks = 0; ticks < Animations[i].Duration; ticks += Animations[i].TicksPerSecond/30.0f){ 282 | dt +=timestep; 283 | Calculate(dt); 284 | Animations[i].Transforms.push_back(std::vector()); 285 | std::vector& trans = Animations[i].Transforms.back(); 286 | for( size_t a = 0; a < Transforms.size(); ++a){ 287 | mat4 rotationmat = Bones[a]->Offset * Bones[a]->GlobalTransform; 288 | trans.push_back(rotationmat); 289 | } 290 | } 291 | } 292 | OUTPUT_DEBUG_MSG("Finished loading animations with "<(Animations.size()); 300 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of animations 301 | for(uint32_t i(0); i< nsize; i++){ 302 | Animations[i].Save(file); 303 | } 304 | 305 | nsize = static_cast(Bones.size()); 306 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of bones 307 | 308 | for(uint32_t i(0); i< Bones.size(); i++){ 309 | nsize = static_cast(Bones[i]->Name.size()); 310 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the size of the bone name 311 | file.write(Bones[i]->Name.c_str(), nsize);// the name of the bone 312 | } 313 | 314 | } 315 | void SceneAnimator::Load(std::ifstream& file){ 316 | Release();// make sure to clear this before writing new data 317 | Skeleton = LoadSkeleton(file, NULL); 318 | uint32_t nsize = 0; 319 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of animations 320 | Animations.resize(nsize); 321 | //OUTPUT_DEBUG_MSG("Extracting Animations . . "); 322 | for(uint32_t i(0); i< nsize; i++){ 323 | Animations[i].Load(file); 324 | } 325 | for(uint32_t i(0); i< Animations.size(); i++){// get all the animation names so I can reference them by name and get the correct id 326 | AnimationNameToId.insert(std::map::value_type(Animations[i].Name, i)); 327 | } 328 | if(Animations.size() >0) CurrentAnimIndex =0;// set it to the first animation if there are any 329 | char bname[250]; 330 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of bones 331 | Bones.resize(nsize); 332 | 333 | for(uint32_t i(0); i< Bones.size(); i++){ 334 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the size of the bone name 335 | file.read(bname, nsize);// the size of the bone name 336 | bname[nsize]=0; 337 | std::map::iterator found = BonesByName.find(bname); 338 | BonesToIndex[found->first] = i; 339 | cBone* tep = found->second; 340 | Bones[i]=tep; 341 | } 342 | 343 | Transforms.resize( Bones.size()); 344 | float timestep = 1.0f/30.0f;// 30 per second 345 | for(size_t i(0); i< Animations.size(); i++){// pre calculate the animations 346 | SetAnimIndex(i); 347 | float dt = 0; 348 | for(float ticks = 0; ticks < Animations[i].Duration; ticks += Animations[i].TicksPerSecond/30.0f){ 349 | dt +=timestep; 350 | Calculate(dt); 351 | Animations[i].Transforms.push_back(std::vector()); 352 | std::vector& trans = Animations[i].Transforms.back(); 353 | for( size_t a = 0; a < Transforms.size(); ++a){ 354 | mat4 rotationmat = Bones[a]->Offset * Bones[a]->GlobalTransform; 355 | trans.push_back(rotationmat); 356 | } 357 | } 358 | } 359 | //OUTPUT_DEBUG_MSG("Finished loading animations with "<mNumAnimations; i++){ 365 | Animations.push_back(cAnimEvaluator(pScene->mAnimations[i]) );// add the animations 366 | } 367 | for(uint32_t i(0); i< Animations.size(); i++){// get all the animation names so I can reference them by name and get the correct id 368 | AnimationNameToId.insert(std::map::value_type(Animations[i].Name, i)); 369 | } 370 | CurrentAnimIndex=0; 371 | SetAnimation("Idle"); 372 | } 373 | bool SceneAnimator::SetAnimation(const std::string& name){ 374 | std::map::iterator itr = AnimationNameToId.find(name); 375 | int32_t oldindex = CurrentAnimIndex; 376 | if(itr !=AnimationNameToId.end()) CurrentAnimIndex = itr->second; 377 | return oldindex != CurrentAnimIndex; 378 | } 379 | bool SceneAnimator::SetAnimIndex( int32_t pAnimIndex){ 380 | if(pAnimIndex >= Animations.size()) return false;// no change, or the animations data is out of bounds 381 | int32_t oldindex = CurrentAnimIndex; 382 | CurrentAnimIndex = pAnimIndex;// only set this after the checks for good data and the object was actually inserted 383 | return oldindex != CurrentAnimIndex; 384 | } 385 | 386 | // ------------------------------------------------------------------------------------------------ 387 | // Calculates the node transformations for the scene. 388 | void SceneAnimator::Calculate(float pTime){ 389 | if( (CurrentAnimIndex < 0) | (CurrentAnimIndex >= Animations.size()) ) return;// invalid animation 390 | 391 | Animations[CurrentAnimIndex].Evaluate( pTime, BonesByName); 392 | UpdateTransforms(Skeleton); 393 | } 394 | 395 | void UQTtoUDQ(vec4* dual, quat q, vec4& tran ) { 396 | dual[0].x = q.x ; 397 | dual[0].y = q.y ; 398 | dual[0].z = q.z ; 399 | dual[0].w = q.w ; 400 | dual[1].x = 0.5f * ( tran[0] * q.w + tran[1] * q.z - tran[2] * q.y ) ; 401 | dual[1].y = 0.5f * (-tran[0] * q.z + tran[1] * q.w + tran[2] * q.x ) ; 402 | dual[1].z = 0.5f * ( tran[0] * q.y - tran[1] * q.x + tran[2] * q.w ) ; 403 | dual[1].w = -0.5f * ( tran[0] * q.x + tran[1] * q.y + tran[2] * q.z ) ; 404 | } 405 | 406 | // ------------------------------------------------------------------------------------------------ 407 | // Calculates the bone matrices for the given mesh. 408 | void SceneAnimator::CalcBoneMatrices(){ 409 | for( size_t a = 0; a < Transforms.size(); ++a){ 410 | Transforms[a] = Bones[a]->Offset * Bones[a]->GlobalTransform; 411 | /* 412 | mat4 rotationmat = Transforms[a]; 413 | quat q; 414 | q.frommatrix(rotationmat); 415 | 416 | vec4 dual[2] ; 417 | UQTtoUDQ( dual, q, Transforms[a].row3_v); 418 | QuatTransforms[a].row0_v =dual[0]; 419 | QuatTransforms[a].row1_v =dual[1]; 420 | */ 421 | } 422 | 423 | } 424 | 425 | // ------------------------------------------------------------------------------------------------ 426 | // Recursively creates an internal node structure matching the current scene and animation. 427 | cBone* SceneAnimator::CreateBoneTree( aiNode* pNode, cBone* pParent){ 428 | cBone* internalNode = new cBone();// create a node 429 | internalNode->Name = pNode->mName.data;// get the name of the bone 430 | internalNode->Parent = pParent; //set the parent, in the case this is theroot node, it will be null 431 | 432 | BonesByName[internalNode->Name] = internalNode;// use the name as a key 433 | TransformMatrix(internalNode->LocalTransform, pNode->mTransformation); 434 | internalNode->LocalTransform.Transpose(); 435 | internalNode->OriginalLocalTransform = internalNode->LocalTransform;// a copy saved 436 | CalculateBoneToWorldTransform(internalNode); 437 | 438 | // continue for all child nodes and assign the created internal nodes as our children 439 | for( unsigned int a = 0; a < pNode->mNumChildren; a++){// recursivly call this function on all children 440 | internalNode->Children.push_back(CreateBoneTree( pNode->mChildren[a], internalNode)); 441 | } 442 | return internalNode; 443 | } 444 | 445 | // ------------------------------------------------------------------------------------------------ 446 | // Recursively updates the internal node transformations from the given matrix array 447 | void SceneAnimator::UpdateTransforms(cBone* pNode) { 448 | CalculateBoneToWorldTransform( pNode);// update global transform as well 449 | for( std::vector::iterator it = pNode->Children.begin(); it != pNode->Children.end(); ++it)// continue for all children 450 | UpdateTransforms( *it); 451 | } 452 | 453 | // ------------------------------------------------------------------------------------------------ 454 | // Calculates the global transformation matrix for the given internal node 455 | void SceneAnimator::CalculateBoneToWorldTransform(cBone* child){ 456 | child->GlobalTransform = child->LocalTransform; 457 | cBone* parent = child->Parent; 458 | while( parent ){// this will climb the nodes up along through the parents concentating all the matrices to get the Object to World transform, or in this case, the Bone To World transform 459 | child->GlobalTransform *= parent->LocalTransform; 460 | parent = parent->Parent;// get the parent of the bone we are working on 461 | } 462 | } 463 | 464 | 465 | void SceneAnimator::SaveSkeleton(std::ofstream& file, cBone* parent){ 466 | uint32_t nsize = static_cast(parent->Name.size()); 467 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of chars 468 | file.write(parent->Name.c_str(), nsize);// the name of the bone 469 | file.write(reinterpret_cast(&parent->Offset), sizeof(parent->Offset));// the bone offsets 470 | file.write(reinterpret_cast(&parent->OriginalLocalTransform), sizeof(parent->OriginalLocalTransform));// original bind pose 471 | nsize = static_cast(parent->Children.size());// number of children 472 | file.write(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of children 473 | for( std::vector::iterator it = parent->Children.begin(); it != parent->Children.end(); ++it)// continue for all children 474 | SaveSkeleton(file, *it); 475 | } 476 | cBone* SceneAnimator::LoadSkeleton(std::ifstream& file, cBone* parent){ 477 | cBone* internalNode = new cBone();// create a node 478 | internalNode->Parent = parent; //set the parent, in the case this is theroot node, it will be null 479 | uint32_t nsize=0; 480 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of chars 481 | char temp[250]; 482 | file.read(temp, nsize);// the name of the bone 483 | temp[nsize]=0; 484 | internalNode->Name = temp; 485 | BonesByName[internalNode->Name] = internalNode;// use the name as a key 486 | file.read(reinterpret_cast(&internalNode->Offset), sizeof(internalNode->Offset));// the bone offsets 487 | file.read(reinterpret_cast(&internalNode->OriginalLocalTransform), sizeof(internalNode->OriginalLocalTransform));// original bind pose 488 | 489 | internalNode->LocalTransform = internalNode->OriginalLocalTransform;// a copy saved 490 | CalculateBoneToWorldTransform(internalNode); 491 | 492 | file.read(reinterpret_cast(&nsize), sizeof(uint32_t));// the number of children 493 | 494 | // continue for all child nodes and assign the created internal nodes as our children 495 | for( unsigned int a = 0; a < nsize && file; a++){// recursivly call this function on all children 496 | internalNode->Children.push_back(LoadSkeleton(file, internalNode)); 497 | } 498 | return internalNode; 499 | 500 | } -------------------------------------------------------------------------------- /cAnimationController.h: -------------------------------------------------------------------------------- 1 | #ifndef AV_SCENEANIMATOR_H 2 | #define AV_SCENEANIMATOR_H 3 | #include "assimp.h" 4 | #include "aiScene.h" 5 | #include "aiPostProcess.h" 6 | #include 7 | #include 8 | #include "MyMath.h" 9 | #include 10 | #include 11 | #include 12 | 13 | class cBone { 14 | public: 15 | 16 | std::string Name; 17 | mat4 Offset, LocalTransform, GlobalTransform, OriginalLocalTransform; 18 | cBone* Parent; 19 | std::vector Children; 20 | 21 | cBone() :Parent(0){} 22 | ~cBone(){ for(size_t i(0); i< Children.size(); i++) delete Children[i]; } 23 | }; 24 | class cAnimationChannel{ 25 | public: 26 | std::string Name; 27 | std::vector mPositionKeys; 28 | std::vector mRotationKeys; 29 | std::vector mScalingKeys; 30 | }; 31 | 32 | class cAnimEvaluator{ 33 | public: 34 | 35 | cAnimEvaluator(): mLastTime(0.0f), TicksPerSecond(0.0f), Duration(0.0f), PlayAnimationForward(true) {} 36 | cAnimEvaluator( const aiAnimation* pAnim); 37 | void Evaluate( float pTime, std::map& bones); 38 | void Save(std::ofstream& file); 39 | void Load(std::ifstream& file); 40 | std::vector& GetTransforms(float dt){ return Transforms[GetFrameIndexAt(dt)]; } 41 | unsigned int GetFrameIndexAt(float time); 42 | 43 | std::string Name; 44 | std::vector Channels; 45 | bool PlayAnimationForward;// play forward == true, play backward == false 46 | float mLastTime, TicksPerSecond, Duration; 47 | std::vector > mLastPositions; 48 | std::vector> Transforms;//, QuatTransforms;/** Array to return transformations results inside. */ 49 | }; 50 | 51 | 52 | class SceneAnimator{ 53 | public: 54 | 55 | SceneAnimator(): Skeleton(0), CurrentAnimIndex(-1) {} 56 | ~SceneAnimator(){ Release(); } 57 | 58 | void Init(const aiScene* pScene);// this must be called to fill the SceneAnimator with valid data 59 | void Release();// frees all memory and initializes everything to a default state 60 | void Save(std::ofstream& file); 61 | void Load(std::ifstream& file); 62 | bool HasSkeleton() const { return !Bones.empty(); }// lets the caller know if there is a skeleton present 63 | // the set animation returns whether the animation changed or is still the same. 64 | bool SetAnimIndex( int32_t pAnimIndex);// this takes an index to set the current animation to 65 | bool SetAnimation(const std::string& name);// this takes a string to set the animation to, i.e. SetAnimation("Idle"); 66 | // the next two functions are good if you want to change the direction of the current animation. You could use a forward walking animation and reverse it to get a walking backwards 67 | void PlayAnimationForward() { Animations[CurrentAnimIndex].PlayAnimationForward = true; } 68 | void PlayAnimationBackward() { Animations[CurrentAnimIndex].PlayAnimationForward = false; } 69 | //this function will adjust the current animations speed by a percentage. So, passing 100, would do nothing, passing 50, would decrease the speed by half, and 150 increase it by 50% 70 | void AdjustAnimationSpeedBy(float percent) { Animations[CurrentAnimIndex].TicksPerSecond*=percent/100.0f; } 71 | //This will set the animation speed 72 | void AdjustAnimationSpeedTo(float tickspersecond) { Animations[CurrentAnimIndex].TicksPerSecond=tickspersecond; } 73 | // get the animationspeed... in ticks per second 74 | float GetAnimationSpeed() const { return Animations[CurrentAnimIndex].TicksPerSecond; } 75 | // get the transforms needed to pass to the vertex shader. This will wrap the dt value passed, so it is safe to pass 50000000 as a valid number 76 | std::vector& GetTransforms(float dt){ return Animations[CurrentAnimIndex].GetTransforms(dt); } 77 | 78 | int32_t GetAnimationIndex() const { return CurrentAnimIndex; } 79 | std::string GetAnimationName() const { return Animations[CurrentAnimIndex].Name; } 80 | //GetBoneIndex will return the index of the bone given its name. The index can be used to index directly into the vector returned from GetTransform 81 | int GetBoneIndex(const std::string& bname){ std::map::iterator found = BonesToIndex.find(bname); if(found!=BonesToIndex.end()) return found->second; else return -1;} 82 | //GetBoneTransform will return the matrix of the bone given its name and the time. be careful with this to make sure and send the correct dt. If the dt is different from what the model is currently at, the transform will be off 83 | mat4 GetBoneTransform(float dt, const std::string& bname) { int bindex=GetBoneIndex(bname); if(bindex == -1) return mat4(); return Animations[CurrentAnimIndex].GetTransforms(dt)[bindex]; } 84 | // same as above, except takes the index 85 | mat4 GetBoneTransform(float dt, unsigned int bindex) { return Animations[CurrentAnimIndex].GetTransforms(dt)[bindex]; } 86 | 87 | std::vector Animations;// a std::vector that holds each animation 88 | int32_t CurrentAnimIndex;/** Current animation index */ 89 | 90 | protected: 91 | 92 | 93 | cBone* Skeleton;/** Root node of the internal scene structure */ 94 | std::map BonesByName;/** Name to node map to quickly find nodes by their name */ 95 | std::map BonesToIndex;/** Name to node map to quickly find nodes by their name */ 96 | std::map AnimationNameToId;// find animations quickly 97 | std::vector Bones;// DO NOT DELETE THESE when the destructor runs... THEY ARE JUST COPIES!! 98 | std::vector Transforms;// temp array of transfrorms 99 | 100 | void SaveSkeleton(std::ofstream& file, cBone* pNode); 101 | cBone* LoadSkeleton(std::ifstream& file, cBone* pNode); 102 | 103 | void UpdateTransforms(cBone* pNode); 104 | void CalculateBoneToWorldTransform(cBone* pInternalNode);/** Calculates the global transformation matrix for the given internal node */ 105 | 106 | void Calculate( float pTime); 107 | void CalcBoneMatrices(); 108 | 109 | void ExtractAnimations(const aiScene* pScene); 110 | cBone* CreateBoneTree( aiNode* pNode, cBone* pParent);// Recursively creates an internal node structure matching the current scene and animation. 111 | 112 | }; 113 | 114 | #endif --------------------------------------------------------------------------------