diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 525bad0..2a6e5a7 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMakeList.txt : CMake project for Red Alert +# CMakeList.txt : CMake project for Red Alert cmake_minimum_required (VERSION 3.8) project(RedAlert ASM CXX C) diff --git a/code/REDALERT/HOUSECOLOR.H b/code/REDALERT/HOUSECOLOR.H new file mode 100644 index 0000000..fb81f31 --- /dev/null +++ b/code/REDALERT/HOUSECOLOR.H @@ -0,0 +1,58 @@ +// HOUSECOLOR.H +// + +#include "vectormath.h" + +struct HouseColorHD { + HouseColorHD(float3 lowerbounds, + float3 upperbounds, + float fudge, + float3 hsvshift, + float3 inputlevels, + float2 outputlevels, + float3 overallinputlevels, + float2 overalloutputlevels, + float3 radarmapcolor) + { + this->LowerBounds = lowerbounds; + this->UpperBounds = upperbounds; + this->Fudge = fudge; + this->HSVShift = hsvshift; + this->InputLevels = inputlevels; + this->OutputLevels = outputlevels; + this->OverallInputLevels = overallinputlevels; + this->OverallOutputLevels = overalloutputlevels; + this->RadarMapColor = radarmapcolor; + } + + float3 LowerBounds; + float3 UpperBounds; + float Fudge; + float3 HSVShift; + float3 InputLevels; + float2 OutputLevels; + float3 OverallInputLevels; + float2 OverallOutputLevels; + float3 RadarMapColor; +}; + +// This data has been sourced from the TD Original Skirmish Color mod by Pokey +// +static HouseColorHD *houseColors[8] = { + // Spain + new HouseColorHD(float3(0.26f, 1.0f, 1.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.777f,-0.196, -0.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.737255, 0.627451, 0.239216) ), + // Greece + new HouseColorHD(float3(0.264706f, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.310000f,-0.211000, 0.005000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0980f, 0.3922, 0.9216)), + // USSR + new HouseColorHD(float3(0.264706f, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.689000f,0.382000, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.756863f, 0.0, 0.015686)), + // England + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.911f,-0.381, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.184314, 0.67451, 0.141176)), + // Ukraine + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.726,0.119, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.772549, 0.380392, 0.07451)), + // Germany + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.713,-0.621, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.6421568, 0.4784698, 0.4784698)), + // France + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.119,-0.233, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.1151961, 0.6911765, 0.4031861)), + // Turkey + new HouseColorHD(float3(0.26, 1.0f, 0.0f), float3(0.0f, 1.0f, 0.22f), 0, float3(0.685,-0.151, 0.000000), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.0f, 1.0f, 1.0f), float2(0.0f, 1.0f), float3(0.5784314, 0.1155861, 0.05387352)), +}; \ No newline at end of file diff --git a/code/REDALERT/IMGUTIL.H b/code/REDALERT/IMGUTIL.H new file mode 100644 index 0000000..98f35ea --- /dev/null +++ b/code/REDALERT/IMGUTIL.H @@ -0,0 +1,206 @@ +// IMGUTIL.H +// + +#ifdef _DEBUG +#pragma optimize( "", on ) +#endif + +// SRGB -> Linear color space conversion. +inline float ByteToLinear(byte p) { + float v; + v = ((float)p) / 255.0f; + v = (double)v >= 0.0404499992728233 ? (float)pow((200.0 * (double)v + 11.0) / 211.0, 2.40000009536743) : (float)((double)v * 25.0 / 323.0); + return v; +} + +inline float ToSRGB(float v) +{ + return (double)v >= 0.0031308 ? (float)((pow((double)v, 0.416666656732559) * 211.0 - 11.0) / 200.0) : (float)((double)v * 323.0 / 25.0); +} + +inline float PixelToHue(float R, float G, float B) { + if (R == G && G == B) + return 0; // 0 makes as good an UNDEFINED value as any + + float r = (float)R / 255.0f; + float g = (float)G / 255.0f; + float b = (float)B / 255.0f; + + float max, min; + float delta; + float hue = 0.0f; + + max = r; min = r; + + if (g > max) max = g; + if (b > max) max = b; + + if (g < min) min = g; + if (b < min) min = b; + + delta = max - min; + + if (r == max) { + hue = (g - b) / delta; + } + else if (g == max) { + hue = 2 + (b - r) / delta; + } + else if (b == max) { + hue = 4 + (r - g) / delta; + } + hue *= 60; + + if (hue < 0.0f) { + hue += 360.0f; + } + return hue; +} + +struct Turple { + Turple() { + memset(this, 0, sizeof(Turple)); + } + Turple(float Item1, float Item2, float Item3) { + this->Item1 = Item1; + this->Item2 = Item2; + this->Item3 = Item3; + this->Item4 = -1; + } + Turple(float Item1, float Item2, float Item3, float Item4) { + this->Item1 = Item1; + this->Item2 = Item2; + this->Item3 = Item3; + this->Item4 = Item4; + } + float Item1; + float Item2; + float Item3; + float Item4; +}; + + +float step(float a, float x) +{ + return x >= a; +} + +inline float4 lerp(float4 a, float4 b, float w) +{ + float4 l; + l.x = a.x + w * (b.x - a.x); + l.y = a.y + w * (b.y - a.y); + l.z = a.z + w * (b.z - a.z); + l.w = a.w + w * (b.w - a.w); + return l; +} + +inline float3 lerp(float3 a, float3 b, float w) +{ + float3 l; + l.x = a.x + w * (b.x - a.x); + l.y = a.y + w * (b.y - a.y); + l.z = a.z + w * (b.z - a.z); + return l; +} + +inline float3 frac(float3 v) +{ + float3 f; + f.x = v.x - floor(v.x); + f.y = v.y - floor(v.y); + f.z = v.z - floor(v.z); + return f; +} + +inline float frac(float v) +{ + return v - floor(v); +} + +inline float lerp(float a, float b, float w) +{ + return a + w * (b - a); +} + + +inline float3 clamp(float3 x, float a, float b) +{ + float3 r; + r.x = max(a, min(b, x.x)); + r.y = max(a, min(b, x.y)); + r.z = max(a, min(b, x.z)); + return r; +} + +inline float saturate(float x) +{ + return max(0, min(1, x)); +} + +inline void RenderTeamPalette(byte* pixel, HouseColorHD &teamColor) { + float linear1 = ByteToLinear(pixel[2]); + float linear2 = ByteToLinear(pixel[1]); + float linear3 = ByteToLinear(pixel[0]); + float num1 = linear1; + float num2 = linear2; + float num3 = (float)linear3; + Turple valueTuple1 = Turple(0.0f, -0.3333333, 0.6666667, -1 ); + Turple valueTuple2; + + if ((double)num2 >= (double)num3) + valueTuple2 = Turple( num2, num3, valueTuple1.Item1, valueTuple1.Item2 ); + else + valueTuple2 = Turple( num3, num2, valueTuple1.Item4, valueTuple1.Item3 ); + + Turple valueTuple3; + if ((double)num1 >= (double)valueTuple2.Item1) + valueTuple3 = Turple(num1, valueTuple2.Item2, valueTuple2.Item3, valueTuple2.Item1); + else + valueTuple3 = Turple(valueTuple2.Item1, valueTuple2.Item2, valueTuple2.Item4, num1); + double num4 = (double)valueTuple3.Item1 - (double)min(valueTuple3.Item4, valueTuple3.Item2); + float num5 = 1E-10f; + float num6 = (float)num4; + float num7 = num5; + float num8 = abs(valueTuple3.Item3 + (float)(((double)valueTuple3.Item4 - (double)valueTuple3.Item2) / (6.0 * (double)num6 + (double)num7))); + float num9 = num6 / (valueTuple3.Item1 + num7); + double num10 = (double)valueTuple3.Item1; + float num11 = num8; + float num12 = num9; + float num13 = (float)num10; + float num14 = PixelToHue(teamColor.LowerBounds.x, teamColor.LowerBounds.y, teamColor.LowerBounds.z) / 360; + float num15 = PixelToHue(teamColor.UpperBounds.x, teamColor.UpperBounds.y, teamColor.UpperBounds.z) / 360; + + if ((double)num11 >= (double)num14 && (double)num15 >= (double)num11) + { + float num16 = (float)((double)num11 / ((double)num15 - (double)num14) * ((double)num15 + (double)teamColor.Fudge - ((double)num14 - (double)teamColor.Fudge))) + teamColor.HSVShift.x; + float t = num12 + teamColor.HSVShift.y; + float num17 = num13 + teamColor.HSVShift.z; + Turple valueTuple4 = Turple(1.0f, 0.6666667, 0.3333333, 3); + Turple valueTuple5 = Turple(abs(frac(num16 + valueTuple4.Item1) * 6 - valueTuple4.Item4), abs(frac(num16 + valueTuple4.Item2) * 6 - valueTuple4.Item4), abs(frac(num16 + valueTuple4.Item3) * 6 - valueTuple4.Item4)); + float num18 = num17 * lerp(valueTuple4.Item1, saturate(valueTuple5.Item1 - valueTuple4.Item1), t); + float num19 = num17 * lerp(valueTuple4.Item1, saturate(valueTuple5.Item2 - valueTuple4.Item1), t); + float num20 = num17 * lerp(valueTuple4.Item1, saturate(valueTuple5.Item3 - valueTuple4.Item1), t); + Turple valueTuple6 = Turple(min(1, max(0.0f, num18 - teamColor.InputLevels.x) / (teamColor.InputLevels.z - teamColor.InputLevels.x)), min(1, max(0.0f, num19 - teamColor.InputLevels.x) / (teamColor.InputLevels.z - teamColor.InputLevels.x)), min(1, max(0.0f, num20 - teamColor.InputLevels.x) / (teamColor.InputLevels.z - teamColor.InputLevels.x))); + valueTuple6.Item1 = (float)pow((double)valueTuple6.Item1, (double)teamColor.InputLevels.y); + valueTuple6.Item2 = (float)pow((double)valueTuple6.Item2, (double)teamColor.InputLevels.y); + valueTuple6.Item3 = (float)pow((double)valueTuple6.Item3, (double)teamColor.InputLevels.y); + num1 = lerp(teamColor.OutputLevels.x, teamColor.OutputLevels.y, valueTuple6.Item1); + num2 = lerp(teamColor.OutputLevels.x, teamColor.OutputLevels.y, valueTuple6.Item2); + num3 = lerp(teamColor.OutputLevels.x, teamColor.OutputLevels.y, valueTuple6.Item3); + } + + Turple valueTuple7 = Turple(min(1, max(0.0f, num1 - teamColor.OverallInputLevels.x) / (teamColor.OverallInputLevels.z - teamColor.OverallInputLevels.x)), min(1, max(0.0f, num2 - teamColor.OverallInputLevels.x) / (teamColor.OverallInputLevels.z - teamColor.OverallInputLevels.x)), min(1, max(0.0f, num3 - teamColor.OverallInputLevels.x) / (teamColor.OverallInputLevels.z - teamColor.OverallInputLevels.x))); + valueTuple7.Item1 = (float)pow((double)valueTuple7.Item1, (double)teamColor.OverallInputLevels.y); + valueTuple7.Item2 = (float)pow((double)valueTuple7.Item2, (double)teamColor.OverallInputLevels.y); + valueTuple7.Item3 = (float)pow((double)valueTuple7.Item3, (double)teamColor.OverallInputLevels.y); + float v1 = lerp(teamColor.OverallOutputLevels.x, teamColor.OverallOutputLevels.y, valueTuple7.Item1); + float v2 = lerp(teamColor.OverallOutputLevels.x, teamColor.OverallOutputLevels.y, valueTuple7.Item2); + float v3 = lerp(teamColor.OverallOutputLevels.x, teamColor.OverallOutputLevels.y, valueTuple7.Item3); + pixel[2] = (byte)((double)ToSRGB(v1) * (double)255.0f); + pixel[1] = (byte)((double)ToSRGB(v2) * (double)255.0f); + pixel[0] = (byte)((double)ToSRGB(v3) * (double)255.0f); +} +#ifdef _DEBUG +#pragma optimize( "", off ) +#endif \ No newline at end of file diff --git a/code/REDALERT/WINSTUB.CPP b/code/REDALERT/WINSTUB.CPP index e6dd6ef..049e45f 100644 --- a/code/REDALERT/WINSTUB.CPP +++ b/code/REDALERT/WINSTUB.CPP @@ -63,6 +63,8 @@ #include #include +#include "HOUSECOLOR.H" +#include "IMGUTIL.H" GLuint backbuffer_texture = -1; //byte* backbuffer_data; @@ -109,28 +111,7 @@ static int64_t generateHashValue(const char* fname, const int size) { return hash; } -static void OffsetRemap(unsigned char remap[3]) { - int r = remap[0] << 2; - int g = remap[1] << 2; - int b = remap[2] << 2; - - // normalize by color instead of saturating to white - //if ((r | g | b) > 255) { - // int max; - // - // max = r > g ? r : g; - // max = max > b ? max : b; - // r = r * 255 / max; - // g = g * 255 / max; - // b = b * 255 / max; - //} - - remap[0] = r; - remap[1] = g; - remap[2] = b; -} - -static bool Image_loadHDImage(Image_t *image, const char* name, int houseid, int animid, int64_t hash, unsigned char remap[3]) { +static bool Image_loadHDImage(Image_t *image, const char* name, int houseid, int animid, int64_t hash, int houseId) { ILuint ImageName; ilGenImages(1, &ImageName); ilBindImage(ImageName); @@ -151,18 +132,9 @@ static bool Image_loadHDImage(Image_t *image, const char* name, int houseid, int Bpp = ilGetInteger(IL_IMAGE_BPP); ILubyte* Data = ilGetData(); - if (Bpp == 4 && (remap[0] + remap[1] + remap[2]) > 0) { - OffsetRemap(remap); - + if (Bpp == 4 && houseId != -1) { for (int i = 0; i < Width * Height; i++) { - if (Data[(i * 4) + 1] > Data[(i * 4) + 0] && Data[(i * 4) + 1] > Data[(i * 4) + 2]) { - float g = (Data[(i * 4) + 1] / 255.0f); - for (int c = 0; c < 3; c++) { - float f = ((remap[2 - c]) / 255.0f) * min(g, 1); - f = f * 255.0f; - Data[(i * 4) + c] = ((unsigned int) f); //((unsigned char)(f * 255.0f)) << 2; //((unsigned char)f) << 2; - } - } + RenderTeamPalette(&Data[i * 4], *houseColors[houseId]); } } @@ -226,7 +198,7 @@ Image_t* Image_LoadImage(const char* name, bool loadAnims, bool loadHouseColor) if (!loadAnims) { unsigned char remap[3] = { 0, 0, 0 }; - if (!Image_loadHDImage(image, name, 0, 0, hash, remap)) { + if (!Image_loadHDImage(image, name, 0, 0, hash, -1)) { delete image; return NULL; } @@ -240,7 +212,7 @@ Image_t* Image_LoadImage(const char* name, bool loadAnims, bool loadHouseColor) remap[0] = palette[(p * 3) + 0]; remap[1] = palette[(p * 3) + 1]; remap[2] = palette[(p * 3) + 2]; - if (!Image_loadHDImage(image, name, i, 0, hash, remap)) { + if (!Image_loadHDImage(image, name, i, 0, hash, i)) { delete image; return NULL; } diff --git a/code/REDALERT/vectormath.h b/code/REDALERT/vectormath.h new file mode 100644 index 0000000..3c5c405 --- /dev/null +++ b/code/REDALERT/vectormath.h @@ -0,0 +1,2020 @@ +//-------------------------------------------------------------------------------------- +// Copyright 2013 Intel Corporation +// All Rights Reserved +// +// Permission is granted to use, copy, distribute and prepare derivative works of this +// software for any purpose and without fee, provided, that the above copyright notice +// and this statement appear in all copies. Intel makes no representations about the +// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS." +// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY, +// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, +// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not +// assume any responsibility for any errors which may appear in this software nor any +// responsibility to update it. +//-------------------------------------------------------------------------------------- + +#ifndef __CPUTMath_h__ +#define __CPUTMath_h__ +#include + +/* + * Constants + */ +static const float kEpsilon = 0.00001f; +static const float kPi = 3.14159265358979323846f; +static const float k2Pi = kPi*2.0f; +static const float kPiDiv2 = kPi/2.0f; +static const float kInvPi = 1.0f/kPi; +static const float kDegToRad = (kPi/180.0f); +static const float kRadToDeg = (180.0f/kPi); +static inline float DegToRad( float fDeg ) { return fDeg * kDegToRad; } +static inline float RadToDeg( float fRad ) { return fRad * kRadToDeg; } + +template +static inline void Swap(T &a, T &b) +{ + T t = b; + b = a; + a = t; +} + +static inline double InvSqrt(const double x) +{ + return 1.0 / sqrt(x); +} + +struct float2; +struct float3; +struct float4; + +/**************************************\ +float2 +\**************************************/ +struct float2 +{ + union + { + struct + { + float x; + float y; + }; + float f[2]; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float2() {} + explicit float2(float f) : x(f), y(f) { } + explicit float2(float _x, float _y) : x(_x), y(_y) { } + explicit float2(float* f) : x(f[0]), y(f[1]) { } + float2(const float2 &v) : x(v.x), y(v.y) { } + const float2 &operator=(const float2 &v) + { + x = v.x; + y = v.y; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + float2 operator+(const float2 &r) const + { + return float2(x+r.x, y+r.y); + } + const float2 &operator+=(const float2 &r) + { + x += r.x; + y += r.y; + return *this; + } + float2 operator-(const float2 &r) const + { + return float2(x-r.x, y-r.y); + } + const float2 &operator-=(const float2 &r) + { + x -= r.x; + y -= r.y; + return *this; + } + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float2 operator+(float f) const + { + return float2(x+f, y+f); + } + const float2 &operator+=(float f) + { + x += f; + y += f; + return *this; + } + float2 operator-(float f) const + { + return float2(x-f, y-f); + } + const float2 &operator-=(float f) + { + x -= f; + y -= f; + return *this; + } + float2 operator*(float f) const + { + return float2(x*f, y*f); + } + const float2 &operator*=(float f) + { + x *= f; + y *= f; + return *this; + } + float2 operator/(float f) const + { + return float2(x/f, y/f); + } + const float2 &operator/=(float f) + { + x /= f; + y /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float2 &r) const + { + return (x==r.x && y == r.y); + } + bool operator!=(const float2 &r) const + { + return !(*this == r); + } + + // Hadd + float hadd(void) const + { + return x + y; + } + + // Length + float lengthSq(void) const + { + return x*x + y*y; + } + float length(void) const + { + return sqrtf(lengthSq()); + } + void normalize(void) + { + *this /= length(); + } +}; + +inline float dot2(const float2 &l, const float2 &r) +{ + return l.x*r.x + l.y*r.y; +} + +inline float2 normalize(const float2 &v) +{ + float length = v.length(); + return v / length; +} + + + + + + + + +/**************************************\ +float3 +\**************************************/ +struct float3 +{ + union + { + struct + { + float x; + float y; + float z; + }; + float f[3]; + }; + + static const float3 Left; + static const float3 Right; + static const float3 Up; + static const float3 Down; + static const float3 Forward; + static const float3 Backward; + static const float3 ZeroF; + + /***************************************\ + | Constructors | + \***************************************/ + float3() {} + explicit float3(float f) : x(f), y(f), z(f) { } + explicit float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) { } + explicit float3(float* f) : x(f[0]), y(f[1]), z(f[2]) { } + float3(const float3 &v) : x(v.x), y(v.y), z(v.z) { } + float3(const float4 &v); + const float3 &operator=(const float3 &v) + { + x = v.x; + y = v.y; + z = v.z; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + float3 operator+(const float3 &r) const + { + return float3(x+r.x, y+r.y, z+r.z); + } + const float3 &operator+=(const float3 &r) + { + x += r.x; + y += r.y; + z += r.z; + return *this; + } + float3 operator-(const float3 &r) const + { + return float3(x-r.x, y-r.y, z-r.z); + } + float operator[](const int index) const { + return (&x)[index]; + } + + + float operator*(const float3 &a) const + { + return x * a.x + y * a.y + z * a.z; + } + + float Dot(const float3 &a) const + { + return x * a.x + y * a.y + z * a.z; + } + + static float Dot(const float3 &a, const float3 &b) + { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + + + float &operator[](const int index) { + return (&x)[index]; + } + const float3 &operator-=(const float3 &r) + { + x -= r.x; + y -= r.y; + z -= r.z; + return *this; + } + + float NormalizeFast() + { + float sqrLength, invLength; + + sqrLength = x * x + y * y + z * z; + invLength = InvSqrt(sqrLength); + x *= invLength; + y *= invLength; + z *= invLength; + return invLength * sqrLength; + } + + float3 operator*(float3 &r) + { + return float3(x*r.x, y*r.y, z*r.z); + } + + + float3 operator*(const float a) const { + return float3(x * a, y * a, z * a); + } + + friend float3 operator*(const float a, const float3 b) { + return float3(b.x * a, b.y * a, b.z * a); + } + + const float3 &operator*=(const float3 &r) + { + x *= r.x; + y *= r.y; + z *= r.z; + return *this; + } + float3 &operator*=(float3 &r) + { + x *= r.x; + y *= r.y; + z *= r.z; + return *this; + } + bool Compare(const float3 &a) const { + return ((x == a.x) && (y == a.y) && (z == a.z)); + } + + bool Compare(const float3 &a, const float epsilon) const { + if (fabs(x - a.x) > epsilon) { + return false; + } + + if (fabs(y - a.y) > epsilon) { + return false; + } + + if (fabs(z - a.z) > epsilon) { + return false; + } + + return true; + } + float3 operator/(const float3 &r) const + { + return float3(x/r.x, y/r.y, z/r.z); + } + const float3 &operator/=(const float3 &r) + { + x /= r.x; + y /= r.y; + z /= r.z; + return *this; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float3 operator+(float f) const + { + return float3(x+f, y+f, z+f); + } + const float3 &operator+=(float f) + { + x += f; + y += f; + z += f; + return *this; + } + float3 operator-(float f) const + { + return float3(x-f, y-f, z-f); + } + const float3 &operator-=(float f) + { + x -= f; + y -= f; + z -= f; + return *this; + } + + + const float3 &operator*=(float f) + { + x *= f; + y *= f; + z *= f; + return *this; + } + float3 operator/(float f) const + { + return float3(x/f, y/f, z/f); + } + const float3 &operator/=(float f) + { + x /= f; + y /= f; + z /= f; + return *this; + } + + void Zero() + { + x = 0; + y = 0; + z = 0; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float3 &r) const + { + return x==r.x &&y == r.y &&z == r.z; + } + bool operator!=(const float3 &r) const + { + return !(*this == r); + } + + // Hadd + float hadd(void) const + { + return x + y + z; + } + + // Length + float lengthSq(void) const + { + return x*x + y*y + z*z; + } + float length(void) const + { + return sqrtf(lengthSq()); + } + + float3 normalize(void) + { + return (*this /= length()); + } + + float NormalizeSelf() { + float sqrLength, invLength; + + sqrLength = x * x + y * y + z * z; + invLength = InvSqrt(sqrLength); + x *= invLength; + y *= invLength; + z *= invLength; + return invLength * sqrLength; + } + float3 Cross(const float3 &a) const + { + return float3(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x); + } + + float3 &Cross(const float3 &a, const float3 &b) + { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + + return *this; + } +}; + +inline float dot3(const float3 &l, const float3 &r) +{ + return l.x*r.x + l.y*r.y + l.z*r.z; +} +inline float3 cross3(const float3 &l, const float3 &r) +{ + return float3( l.y*r.z-l.z*r.y, + l.z*r.x-l.x*r.z, + l.x*r.y-l.y*r.x); +} +inline float3 normalize(const float3 &v) +{ + float length = v.length(); + return v / length; +} + +inline float3 abs3( const float3 &l ) +{ + float3 tmp; + tmp.x = fabs(l.x); + tmp.y = fabs(l.y); + tmp.z = fabs(l.z); + return tmp; +} + + +/**************************************\ +float4 +\**************************************/ +__declspec(align(16)) struct float4 +{ + union + { + struct + { + float x; + float y; + float z; + float w; + }; + float f[4]; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float4() {} + explicit float4(float f) : x(f), y(f), z(f), w(f) { } + explicit float4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } + explicit float4(float* f) : x(f[0]), y(f[1]), z(f[2]), w(f[3]) { } + float4(const float4 &v) : x(v.x), y(v.y), z(v.z), w(v.w) { } + float4(const float3 &v, float _w) : x(v.x), y(v.y), z(v.z), w(_w) { } + const float4 &operator=(const float4 &v) + { + x = v.x; + y = v.y; + z = v.z; + w = v.w; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + float4 operator+(const float4 &r) const + { + return float4(x+r.x, y+r.y, z+r.z, w+r.w); + } + const float4 &operator+=(const float4 &r) + { + x += r.x; + y += r.y; + z += r.z; + w += r.w; + return *this; + } + float4 operator-(const float4 &r) const + { + return float4(x-r.x, y-r.y, z-r.z, w-r.w); + } + const float4 &operator-=(const float4 &r) + { + x -= r.x; + y -= r.y; + z -= r.z; + w -= r.w; + return *this; + } + float4 operator*(const float4 &r) const + { + return float4(x*r.x, y*r.y, z*r.z, w*r.w); + } + const float4 &operator*=(const float4 &r) + { + x *= r.x; + y *= r.y; + z *= r.z; + w *= r.w; + return *this; + } + float4 operator/(const float4 &r) const + { + return float4(x/r.x, y/r.y, z/r.z, w/r.w); + } + const float4 &operator/=(const float4 &r) + { + x /= r.x; + y /= r.y; + z /= r.z; + w /= r.w; + return *this; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float4 operator+(float f) const + { + return float4(x+f, y+f, z+f, w+f); + } + const float4 &operator+=(float f) + { + x += f; + y += f; + z += f; + return *this; + } + float4 operator-(float f) const + { + return float4(x-f, y-f, z-f, w-f); + } + const float4 &operator-=(float f) + { + x -= f; + y -= f; + z -= f; + w -= f; + return *this; + } + float4 operator*(float f) const + { + return float4(x*f, y*f, z*f, w*f); + } + const float4 &operator*=(float f) + { + x *= f; + y *= f; + z *= f; + w *= f; + return *this; + } + float4 operator/(float f) const + { + return float4(x/f, y/f, z/f, w/f); + } + const float4 &operator/=(float f) + { + x /= f; + y /= f; + z /= f; + w /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float4 &r) const + { + return x==r.x && y == r.y && z == r.z && w == r.w; + } + bool operator!=(const float4 &r) const + { + return !(*this == r); + } + + // Hadd + float hadd(void) const + { + return x + y + z + w; + } + + // Length + float lengthSq(void) const + { + return x*x + y*y + z*z + w*w; + } + float length(void) const + { + return sqrtf(lengthSq()); + } + void normalize(void) + { + *this /= length(); + } +}; + +inline float dot4(const float4 &l, const float4 &r) +{ + return l.x*r.x + l.y*r.y + l.z*r.z + l.w*r.w; +} +inline float4 normalize(const float4 &v) +{ + float length = v.length(); + return v / length; +} + +inline float3::float3(const float4 &v) : x(v.x), y(v.y), z(v.z) { } + + +/**************************************\ +float3x3 +\**************************************/ +struct float4x4; +struct float3x3 +{ + struct + { + float3 r0; + float3 r1; + float3 r2; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float3x3() {} + explicit float3x3(float f) : r0(f), r1(f), r2(f) { } + explicit float3x3(float* f) : r0(f+0), r1(f+3), r2(f+6) { } + float3x3(const float3 &_r0, const float3 &_r1, const float3 &_r2) : r0(_r0), r1(_r1), r2(_r2) { } + float3x3(float _m00, float _m01, float _m02, + float _m10, float _m11, float _m12, + float _m20, float _m21, float _m22) + : r0(_m00,_m01,_m02) + , r1(_m10,_m11,_m12) + , r2(_m20,_m21,_m22) + { + } + float3x3(const float4x4 &m); + const float3x3 &operator=(const float3x3 &m) + { + r0 = m.r0; + r1 = m.r1; + r2 = m.r2; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + + #define MTX3_INDEX(f,r,c) ((f)[(r*3)+c]) + inline float3x3 operator*(const float3x3 &r) const + { + float3x3 m(1,0,0,0,1,0,0,0,1); + + const float* left = (const float*)&this->r0; + const float* right = (const float*)&r.r0; + float* result = (float*)&m; + + int ii, jj, kk; + for(ii=0; ii<3; ++ii) /* row */ + { + for(jj=0; jj<3; ++jj) /* column */ + { + float sum = MTX3_INDEX(left,ii,0)*MTX3_INDEX(right,0,jj); + for(kk=1; kk<3; ++kk) + { + sum += (MTX3_INDEX(left,ii,kk)*MTX3_INDEX(right,kk,jj)); + } + MTX3_INDEX(result,ii,jj) = sum; + } + } + return m; + } + #undef MTX3_INDEX + + inline float3 operator*(const float3 &v) const + { + float3 a; + + a.x = (r0*v); + a.y = (r1*v); + a.z = (r2*v); + + return a; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float3x3 operator+(float f) const + { + return float3x3(r0+f, r1+f, r2+f); + } + + float3 const &operator[](int index) const { + //assert( ( index >= 0 ) && ( index < 3 ) ); + return (&r0)[index]; + } + + float3 &operator[](int index) { + //assert( ( index >= 0 ) && ( index < 3 ) ); + return (&r0)[index]; + } + + const float3x3 &operator+=(float f) + { + r0 += f; + r1 += f; + r2 += f; + return *this; + } + + + friend float3 operator*(const float3 &vec, const float3x3 &mat) { + return mat * vec; + } + + friend float3x3 operator*(const float a, const float3x3 &mat) { + return mat * a; + } + + friend float3 &operator*=(float3 &vec, const float3x3 &mat) { + float x = mat[0].x * vec.x + mat[1].x * vec.y + mat[2].x * vec.z; + float y = mat[0].y * vec.x + mat[1].y * vec.y + mat[2].y * vec.z; + vec.z = mat[0].z * vec.x + mat[1].z * vec.y + mat[2].z * vec.z; + vec.x = x; + vec.y = y; + return vec; + } + + float3x3 &operator*=(const float3x3 &a) { + int i, j; + const float *m2Ptr; + float *m1Ptr, dst[3]; + + m1Ptr = reinterpret_cast(this); + m2Ptr = reinterpret_cast(&a); + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + dst[j] = m1Ptr[0] * m2Ptr[0 * 3 + j] + + m1Ptr[1] * m2Ptr[1 * 3 + j] + + m1Ptr[2] * m2Ptr[2 * 3 + j]; + } + m1Ptr[0] = dst[0]; m1Ptr[1] = dst[1]; m1Ptr[2] = dst[2]; + m1Ptr += 3; + } + return *this; + } + + float3x3 operator-(float f) const + { + return float3x3(r0-f, r1-f, r2-f); + } + bool Compare(const float3x3 &a) const { + if (r0.Compare(a[0]) && + r1.Compare(a[1]) && + r2.Compare(a[2])) { + return true; + } + return false; + } + + bool Compare(const float3x3 &a, const float epsilon) const { + if (r0.Compare(a[0], epsilon) && + r1.Compare(a[1], epsilon) && + r2.Compare(a[2], epsilon)) { + return true; + } + return false; + } + + const float3x3 &operator-=(float f) + { + r0 -= f; + r1 -= f; + r2 -= f; + return *this; + } + float3x3 operator*(float f) const + { + return float3x3(r0*f, r1*f, r2*f); + } + const float3x3 &operator*=(float f) + { + r0 *= f; + r1 *= f; + r2 *= f; + return *this; + } + float3x3 operator/(float f) const + { + return float3x3(r0/f, r1/f, r2/f); + } + const float3x3 &operator/=(float f) + { + r0 /= f; + r1 /= f; + r2 /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float3x3 &r) const + { + return r0 == r.r0 && r1 == r.r1 && r2 == r.r2; + } + bool operator!=(const float3x3 &r) const + { + return !(*this == r); + } + + float determinant() const + { + float f0 = r0.x * (r1.y*r2.z-r2.y*r1.z); + float f1 = r0.y * -(r1.x*r2.z-r2.x*r1.z); + float f2 = r0.z * (r1.x*r2.y-r2.x*r1.y); + + return f0 + f1 + f2; + } + + void transpose(void) + { + Swap(r0.y, r1.x); + Swap(r0.z, r2.x); + Swap(r1.z, r2.y); + } + + void invert(void) + { + float det = determinant(); + float3x3 inv; + + inv.r0.x = (r1.y*r2.z) - (r1.z*r2.y); + inv.r0.y = -((r1.x*r2.z) - (r1.z*r2.x)); + inv.r0.z = (r1.x*r2.y) - (r1.y*r2.x); + + inv.r1.x = -((r0.y*r2.z) - (r0.z*r2.y)); + inv.r1.y = (r0.x*r2.z) - (r0.z*r2.x); + inv.r1.z = -((r0.x*r2.y) - (r0.y*r2.x)); + + inv.r2.x = (r0.y*r1.z) - (r0.z*r1.y); + inv.r2.y = -((r0.x*r1.z) - (r0.z*r1.x)); + inv.r2.z = (r0.x*r1.y) - (r0.y*r1.x); + + inv.transpose(); + inv /= det; + + *this = inv; + } +}; +inline float3x3 float3x3Identity(void) +{ + return float3x3(1,0,0, + 0,1,0, + 0,0,1); +} +inline float determinant(const float3x3&m) +{ + return m.determinant(); +} + +inline float3x3 transpose(const float3x3 &m) +{ + float3x3 ret = m; + ret.transpose(); + return ret; +} + +inline float3x3 inverse(const float3x3 &m) +{ + float3x3 ret = m; + ret.invert(); + return ret; +} + +inline float3x3 float3x3RotationX(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float3x3 m( 1.0f, 0.0f, 0.0f, + 0.0f, c, s, + 0.0f, -s, c ); + return m; +} +inline float3x3 float3x3RotationY(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float3x3 m( c, 0.0f, -s, + 0.0f, 1.0f, 0.0f, + s, 0.0f, c ); + return m; +} +inline float3x3 float3x3RotationZ(float rad) +{ + + float c = cosf( rad ); + float s = sinf( rad ); + float3x3 m( c, s, 0.0f, + -s, c, 0.0f, + 0.0f, 0.0f, 1.0f ); + return m; +} + +inline float3x3 float3x3RotationAxis(const float3 &axis, float rad ) +{ + float3 normAxis = normalize(axis); + float c = cosf(rad); + float s = sinf(rad); + float t = 1 - c; + + float x = normAxis.x; + float y = normAxis.y; + float z = normAxis.z; + + float3x3 m; + + m.r0.x = (t * x * x) + c; + m.r0.y = (t * x * y) + s * z; + m.r0.z = (t * x * z) - s * y; + + m.r1.x = (t * x * y) - (s * z); + m.r1.y = (t * y * y) + c; + m.r1.z = (t * y * z) + (s * x); + + m.r2.x = (t * x * z) + (s * y); + m.r2.y = (t * y * z) - (s * x); + m.r2.z = (t * z * z) + c; + + return m; +} + +inline float3x3 float3x3Scale(float x, float y, float z) +{ + return float3x3(x,0,0, + 0,y,0, + 0,0,z); +} + +/**************************************\ +float4x4 +\**************************************/ +struct float4x4 +{ + struct + { + float4 r0; + float4 r1; + float4 r2; + float4 r3; + }; + + /***************************************\ + | Constructors | + \***************************************/ + float4x4() {} + explicit float4x4(float f) : r0(f), r1(f), r2(f), r3(f) { } + explicit float4x4(float* f) : r0(f+0), r1(f+4), r2(f+8), r3(f+12) { } + float4x4(const float4 &_r0, const float4 &_r1, const float4 &_r2, const float4 &_r3) : r0(_r0), r1(_r1), r2(_r2), r3(_r3) { } + float4x4(float _m00, float _m01, float _m02, float _m03, + float _m10, float _m11, float _m12, float _m13, + float _m20, float _m21, float _m22, float _m23, + float _m30, float _m31, float _m32, float _m33) + : r0(_m00,_m01,_m02,_m03) + , r1(_m10,_m11,_m12,_m13) + , r2(_m20,_m21,_m22,_m23) + , r3(_m30,_m31,_m32,_m33) + { + } + float4x4(const float3x3 &m) + : r0(m.r0, 0.0f) + , r1(m.r1, 0.0f) + , r2(m.r2, 0.0f) + , r3(0.0f, 0.0f, 0.0f, 1.0f) + { + } + const float4x4 &operator=(const float4x4 &m) + { + r0 = m.r0; + r1 = m.r1; + r2 = m.r2; + r3 = m.r3; + return *this; + } + + /***************************************\ + | Basic math operations | + \***************************************/ + + #define MTX4_INDEX(f,r,c) ((f)[(r*4)+c]) + inline float4x4 operator*(const float4x4 &r) const + { + float4x4 m(1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1); + + const float* right = (const float*)&this->r0; + const float* left = (const float*)&r.r0; + float* result = (float*)&m; + + int ii, jj, kk; + for(ii=0; ii<4; ++ii) /* row */ + { + for(jj=0; jj<4; ++jj) /* column */ + { + float sum = MTX4_INDEX(left,ii,0)*MTX4_INDEX(right,0,jj); + for(kk=1; kk<4; ++kk) + { + sum += (MTX4_INDEX(left,ii,kk)*MTX4_INDEX(right,kk,jj)); + } + MTX4_INDEX(result,ii,jj) = sum; + } + } + return m; + } + #undef MTX4_INDEX + + inline float4 operator*(const float4 &v) const + { + float4 a; + + a.x = (r0*v).hadd(); + a.y = (r1*v).hadd(); + a.z = (r2*v).hadd(); + a.w = (r3*v).hadd(); + + return a; + } + + /***************************************\ + | Basic math operations with scalars | + \***************************************/ + float4x4 operator+(float f) const + { + return float4x4(r0+f, r1+f, r2+f, r3+f); + } + const float4x4 &operator+=(float f) + { + r0 += f; + r1 += f; + r2 += f; + r3 += f; + return *this; + } + float4x4 operator-(float f) const + { + return float4x4(r0-f, r1-f, r2-f, r3-f); + } + const float4x4 &operator-=(float f) + { + r0 -= f; + r1 -= f; + r2 -= f; + r3 -= f; + return *this; + } + float4x4 operator*(float f) const + { + return float4x4(r0*f, r1*f, r2*f, r3*f); + } + const float4x4 &operator*=(float f) + { + r0 *= f; + r1 *= f; + r2 *= f; + r3 *= f; + return *this; + } + float4x4 operator/(float f) const + { + return float4x4(r0/f, r1/f, r2/f, r3/f); + } + const float4x4 &operator/=(float f) + { + r0 /= f; + r1 /= f; + r2 /= f; + r3 /= f; + return *this; + } + + /***************************************\ + | Other math | + \***************************************/ + // Equality + bool operator==(const float4x4 &r) const + { + return r0 == r.r0 && r1 == r.r1 && r2 == r.r2 && r3 == r.r3; + } + bool operator!=(const float4x4 &r) const + { + return !(*this == r); + } + + float determinant() const + { + float det = 0.0f; + + float3x3 a( r1.y,r1.z,r1.w, + r2.y,r2.z,r2.w, + r3.y,r3.z,r3.w); + + float3x3 b( r1.x,r1.z,r1.w, + r2.x,r2.z,r2.w, + r3.x,r3.z,r3.w); + + float3x3 c( r1.x,r1.y,r1.w, + r2.x,r2.y,r2.w, + r3.x,r3.y,r3.w); + + float3x3 d( r1.x,r1.y,r1.z, + r2.x,r2.y,r2.z, + r3.x,r3.y,r3.z); + + + det += r0.x * a.determinant(); + + det -= r0.y * b.determinant(); + + det += r0.z * c.determinant(); + + det -= r0.w * d.determinant(); + + return det; + } + + void transpose(void) + { + Swap(r0.y, r1.x); + Swap(r0.z, r2.x); + Swap(r0.w, r3.x); + Swap(r1.z, r2.y); + Swap(r1.w, r3.y); + Swap(r2.w, r3.z); + } + + void invert(void) + { + float4x4 ret; + float recip; + + /* temp matrices */ + + /* row 1 */ + float3x3 a( r1.y,r1.z,r1.w, + r2.y,r2.z,r2.w, + r3.y,r3.z,r3.w); + + float3x3 b( r1.x,r1.z,r1.w, + r2.x,r2.z,r2.w, + r3.x,r3.z,r3.w); + + float3x3 c( r1.x,r1.y,r1.w, + r2.x,r2.y,r2.w, + r3.x,r3.y,r3.w); + + float3x3 d( r1.x,r1.y,r1.z, + r2.x,r2.y,r2.z, + r3.x,r3.y,r3.z); + + /* row 2 */ + float3x3 e( r0.y,r0.z,r0.w, + r2.y,r2.z,r2.w, + r3.y,r3.z,r3.w); + + float3x3 f( r0.x,r0.z,r0.w, + r2.x,r2.z,r2.w, + r3.x,r3.z,r3.w); + + float3x3 g( r0.x,r0.y,r0.w, + r2.x,r2.y,r2.w, + r3.x,r3.y,r3.w); + + float3x3 h( r0.x,r0.y,r0.z, + r2.x,r2.y,r2.z, + r3.x,r3.y,r3.z); + + + /* row 3 */ + float3x3 i( r0.y,r0.z,r0.w, + r1.y,r1.z,r1.w, + r3.y,r3.z,r3.w); + + float3x3 j( r0.x,r0.z,r0.w, + r1.x,r1.z,r1.w, + r3.x,r3.z,r3.w); + + float3x3 k( r0.x,r0.y,r0.w, + r1.x,r1.y,r1.w, + r3.x,r3.y,r3.w); + + float3x3 l( r0.x,r0.y,r0.z, + r1.x,r1.y,r1.z, + r3.x,r3.y,r3.z); + + + /* row 4 */ + float3x3 m( r0.y, r0.z, r0.w, + r1.y, r1.z, r1.w, + r2.y, r2.z, r2.w); + + float3x3 n( r0.x, r0.z, r0.w, + r1.x, r1.z, r1.w, + r2.x, r2.z, r2.w); + + float3x3 o( r0.x,r0.y,r0.w, + r1.x,r1.y,r1.w, + r2.x,r2.y,r2.w); + + float3x3 p( r0.x,r0.y,r0.z, + r1.x,r1.y,r1.z, + r2.x,r2.y,r2.z); + + /* row 1 */ + ret.r0.x = a.determinant(); + + ret.r0.y = -b.determinant(); + + ret.r0.z = c.determinant(); + + ret.r0.w = -d.determinant(); + + /* row 2 */ + ret.r1.x = -e.determinant(); + + ret.r1.y = f.determinant(); + + ret.r1.z = -g.determinant(); + + ret.r1.w = h.determinant(); + + /* row 3 */ + ret.r2.x = i.determinant(); + + ret.r2.y = -j.determinant(); + + ret.r2.z = k.determinant(); + + ret.r2.w = -l.determinant(); + + /* row 4 */ + ret.r3.x = -m.determinant(); + + ret.r3.y = n.determinant(); + + ret.r3.z = -o.determinant(); + + ret.r3.w = p.determinant(); + + ret.transpose(); + recip = 1.0f/determinant(); + ret *= recip; + + *this = ret; + } + + // Axis access + float3 getXAxis(void) const + { + return r0; + } + float3 getYAxis(void) const + { + return r1; + } + float3 getZAxis(void) const + { + return r2; + } + float3 getPosition(void) const + { + return float3(r3); + } + + void orthonormalize(void) + { + float3 x = getXAxis(); + float3 y = getYAxis(); + float3 z; + + x.normalize(); + z = normalize(cross3(x, y)); + y = normalize(cross3(z, x)); + + r0 = float4(x, 0.0f); + r1 = float4(y, 0.0f); + r2 = float4(z, 0.0f); + } +}; + +inline float3x3::float3x3(const float4x4 &m) + : r0(m.r0) + , r1(m.r1) + , r2(m.r2) +{ +} +inline float determinant(const float4x4&m) +{ + return m.determinant(); +} +inline float4x4 float4x4Identity(void) +{ + return float4x4(1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1); +} +inline float4x4 transpose(const float4x4 &m) +{ + float4x4 ret = m; + ret.transpose(); + return ret; +} + +inline float4x4 inverse(const float4x4 &m) +{ + float4x4 ret = m; + ret.invert(); + return ret; +} + +inline float4x4 float4x4RotationX(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float4x4 m( 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, c, s, 0.0f, + 0.0f, -s, c, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + return m; +} +inline float4x4 float4x4RotationY(float rad) +{ + float c = cosf( rad ); + float s = sinf( rad ); + float4x4 m( c, 0.0f, -s, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + s, 0.0f, c, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + return m; +} +inline float4x4 float4x4RotationZ(float rad) +{ + + float c = cosf( rad ); + float s = sinf( rad ); + float4x4 m( c, s, 0.0f, 0.0f, + -s, c, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + return m; +} + +inline float4x4 float4x4RotationAxis(const float3 &axis, float rad ) +{ + float3 normAxis = normalize(axis); + float c = cosf(rad); + float s = sinf(rad); + float t = 1 - c; + + float x = normAxis.x; + float y = normAxis.y; + float z = normAxis.z; + + float4x4 m = float4x4Identity(); + + m.r0.x = (t * x * x) + c; + m.r0.y = (t * x * y) + s * z; + m.r0.z = (t * x * z) - s * y; + + m.r1.x = (t * x * y) - (s * z); + m.r1.y = (t * y * y) + c; + m.r1.z = (t * y * z) + (s * x); + + m.r2.x = (t * x * z) + (s * y); + m.r2.y = (t * y * z) - (s * x); + m.r2.z = (t * z * z) + c; + + return m; +} + +inline float4x4 float4x4Scale(float x, float y, float z) +{ + return float4x4(x,0,0,0, + 0,y,0,0, + 0,0,z,0, + 0,0,0,1); +} + +inline float4x4 float4x4Translation(float x, float y, float z) +{ + float4x4 m = float4x4Identity(); + m.r3.x = x; + m.r3.y = y; + m.r3.z = z; + return m; +} +inline float4x4 float4x4Translation(const float3 &v) +{ + return float4x4Translation(v.x, v.y, v.z); +} + +inline float4x4 float4x4PerspectiveFovLH(float fov, float aspect, float nearPlane, float farPlane) +{ + float width = tanf(fov * 0.5f); + float height = width / aspect; + float diff = farPlane-nearPlane; + float div = farPlane / diff; + + float4x4 m( + 1.0f/width, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f/height, 0.0f, 0.0f, + 0.0f, 0.0f, div, 1.0f, + 0.0f, 0.0f, -nearPlane*div, 0.0f + ); + return m; +} +inline float4x4 float4x4PerspectiveFovRH(float fov, float aspect, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + float f = tanf(kPiDiv2 - (fov/2.0f)); + float diff = nearPlane-farPlane; + float div = farPlane / diff; + + m.r0.x = f/aspect; + m.r1.y = f; + m.r2.z = div; + m.r2.w = -1; + m.r3.z = nearPlane * div; + m.r3.w = 0; + return m; +} +inline float4x4 float4x4PerspectiveLH(float width, float height, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + m.r0.x = 2*nearPlane/width; + m.r1.y = 2*nearPlane/height; + m.r2.z = farPlane/(farPlane-nearPlane); + m.r2.w = 1; + m.r3.z = nearPlane*farPlane/(nearPlane-farPlane); + m.r3.w = 0; + return m; +} +inline float4x4 float4x4PerspectiveRH(float width, float height, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + m.r0.x = 2*nearPlane/width; + m.r1.y = 2*nearPlane/height; + m.r2.z = farPlane/(nearPlane-farPlane); + m.r2.w = -1; + m.r3.z = nearPlane*farPlane/(nearPlane-farPlane); + m.r3.w = 0; + return m; +} +inline float4x4 float4x4OrthographicOffCenterLH(float left, float right, float top, float bottom, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + + float diff = farPlane-nearPlane; + + m.r0.x = 2.0f/(right-left); + m.r1.y = 2.0f/(top-bottom); + m.r2.z = 1.0f/diff; + m.r3.x = -((left+right)/(right-left)); + m.r3.y = -((top+bottom)/(top-bottom)); + m.r3.z = -nearPlane/diff; + + return m; +} +inline float4x4 float4x4OrthographicOffCenterRH(float left, float right, float top, float bottom, float nearPlane, float farPlane) +{ + float4x4 m = float4x4Identity(); + float diff = nearPlane-farPlane; + + m.r0.x = 2.0f/(right-left); + m.r1.y = 2.0f/(top-bottom); + m.r2.z = 1.0f/diff; + m.r3.x = -((left+right)/(right-left)); + m.r3.y = -((top+bottom)/(top-bottom)); + m.r3.z = nearPlane/diff; + + return m; +} +inline float4x4 float4x4OrthographicLH(float width, float height, float nearPlane, float farPlane) +{ + float halfWidth = width/2.0f; + float halfHeight = height/2.0f; + + return float4x4OrthographicOffCenterLH(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); +} +inline float4x4 float4x4OrthographicRH(float width, float height, float nearPlane, float farPlane) +{ + float halfWidth = width/2.0f; + float halfHeight = height/2.0f; + + return float4x4OrthographicOffCenterRH(-halfWidth, halfWidth, halfHeight, -halfHeight, nearPlane, farPlane); +} + +/**************************************\ +Quaternion +\**************************************/ +struct quaternion : public float4 +{ + + /***************************************\ + | Constructors | + \***************************************/ + quaternion() {} + explicit quaternion(float f) : float4(f) { } + explicit quaternion(float _x, float _y, float _z, float _w) : float4(_x,_y,_z,_w) { } + explicit quaternion(float* f) : float4(f) { } + quaternion(const quaternion &v) : float4(v) { } + quaternion(const float3 &v, float _w) + { + float3 norm = ::normalize(v); + float a = _w*0.5f; + float s = sinf(a); + x = norm.x*s; + y = norm.y*s; + z = norm.z*s; + w = cosf(a); + } + const quaternion &operator=(const quaternion &v) + { + x = v.x; + y = v.y; + z = v.z; + w = v.w; + return *this; + } + + /* Methods */ + float3 getXAxis(void) const + { + float3 ret( 1-2*(y*y+z*z), + 2*(x*y+w*z), + 2*(x*z-y*w)); + return ret; + } + float3 getYAxis(void) const + { + float3 ret( 2*(x*y-z*w), + 1-2*(x*x+z*z), + 2*(y*z+x*w)); + return ret; + } + float3 getZAxis(void) const + { + float3 ret( 2*(x*z+y*w), + 2*(y*z-x*w), + 1-2*(x*x+y*y)); + return ret; + } + + float3x3 getMatrix(void) const + { + quaternion q = *this; + q.normalize(); + float xx = q.x * q.x; + float yy = q.y * q.y; + float zz = q.z * q.z; + + float xy = q.x * q.y; + float zw = q.z * q.w; + float xz = q.x * q.z; + float yw = q.y * q.w; + float yz = q.y * q.z; + float xw = q.x * q.w; + + float3x3 ret(1 - 2*(yy+zz), 2*(xy+zw), 2*(xz-yw), + 2*(xy-zw), 1 - 2*(xx+zz), 2*(yz+xw), + 2*(xz+yw), 2*(yz-xw), 1 - 2*(xx+yy) ); + return ret; + } + + quaternion conjugate(void) const + { + return quaternion(-x, -y, -z, w); + } + quaternion inverse(void) const + { + // Note: Only normalized quaternions are supportted at the moment + quaternion q = *this; + q.normalize(); + return q.conjugate(); + } +}; + +inline quaternion quaternionMultiply(const quaternion &l, const quaternion &r) +{ + quaternion q( r.w*l.x + r.x*l.w + r.y*l.z - r.z*l.y, + r.w*l.y + r.y*l.w + r.z*l.x - r.x*l.z, + r.w*l.z + r.z*l.w + r.x*l.y - r.y*l.x, + r.w*l.w - r.x*l.x - r.y*l.y - r.z*l.z ); + return q; +} + +inline quaternion quaternionIdentity(void) +{ + return quaternion(0.0f, 0.0f, 0.0f, 1.0f); +} + +inline float3 Min( float3 &v0, float3 &v1 ) +{ + float3 result; + result.x = v0.x < v1.x ? v0.x : v1.x; + result.y = v0.y < v1.y ? v0.y : v1.y; + result.z = v0.z < v1.z ? v0.z : v1.z; + return result; +} + +inline float3 Max( float3 &v0, float3 &v1 ) +{ + float3 result; + result.x = v0.x > v1.x ? v0.x : v1.x; + result.y = v0.y > v1.y ? v0.y : v1.y; + result.z = v0.z > v1.z ? v0.z : v1.z; + return result; +} + +inline float4 Min( float4 &v0, float4 &v1 ) +{ + float4 result; + result.x = v0.x < v1.x ? v0.x : v1.x; + result.y = v0.y < v1.y ? v0.y : v1.y; + result.z = v0.z < v1.z ? v0.z : v1.z; + result.w = v0.w < v1.w ? v0.w : v1.w; + return result; +} + +inline float4 Max( float4 &v0, float4 &v1 ) +{ + float4 result; + result.x = v0.x > v1.x ? v0.x : v1.x; + result.y = v0.y > v1.y ? v0.y : v1.y; + result.z = v0.z > v1.z ? v0.z : v1.z; + result.w = v0.w > v1.w ? v0.w : v1.w; + return result; +} + +inline float4 operator*(const float4 &v, const float4x4 &m) +{ + float4 result; + + result = m.r0 * v.x; + result += m.r1 * v.y; + result += m.r2 * v.z; + result += m.r3 * v.w; + + return result; +} + +/* +============================ +CreateLookAtMatrix +============================ +*/ +inline float4x4 CreateLookAtMatrix(float3 cameraPosition, float3 cameraTarget, float3 cameraUpVector) +{ + float3 vector3_1 = (cameraPosition - cameraTarget).normalize(); + float3 vector3_2; + + vector3_2.Cross(cameraUpVector, vector3_1); + vector3_2.NormalizeSelf(); + + float3 vector1; + vector1.Cross(vector3_1, vector3_2); + + float4x4 matrix; + matrix.r0.x = vector3_2.x; + matrix.r0.y = vector1.x; + matrix.r0.z = vector3_1.x; + matrix.r0.w = 0.0f; + matrix.r1.x = vector3_2.y; + matrix.r1.y = vector1.y; + matrix.r1.z = vector3_1.y; + matrix.r1.w = 0.0f; + matrix.r2.x = vector3_2.z; + matrix.r2.y = vector1.z; + matrix.r2.z = vector3_1.z; + matrix.r2.w = 0.0f; + matrix.r3.x = -float3::Dot(vector3_2, cameraPosition); + matrix.r3.y = -float3::Dot(vector1, cameraPosition); + matrix.r3.z = -float3::Dot(vector3_1, cameraPosition); + matrix.r3.w = 1.0f; + + return matrix; +} + +__inline float3 abs(const float3 xyz) +{ + float3 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z)); + return result; +} + + +__inline float4 abs(const float4 xyz) +{ + float4 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z), fabs(xyz.w)); + return result; +} + +__inline float3 fabs(const float3 xyz) +{ + float3 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z)); + return result; +} + + +__inline float4 fabs(const float4 xyz) +{ + float4 result(fabs(xyz.x), fabs(xyz.y), fabs(xyz.z), fabs(xyz.w)); + return result; +} + +static const float Identity[16] = { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 +}; + +__inline void _math_matrix_rotate(float4x4 &matrix, float angle, float x, float y, float z) +{ + float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c; + float m[16]; + bool optimized; + #define M_PI 3.14159265358979323846 + s = sinf(angle * M_PI / 180.0); + c = cosf(angle * M_PI / 180.0); + + memcpy(m, Identity, sizeof(Identity)); + optimized = false; + +#define M(row,col) m[col*4+row] + + if (x == 0.0F) { + if (y == 0.0F) { + if (z != 0.0F) { + optimized = true; + /* rotate only around z-axis */ + M(0, 0) = c; + M(1, 1) = c; + if (z < 0.0F) { + M(0, 1) = s; + M(1, 0) = -s; + } + else { + M(0, 1) = -s; + M(1, 0) = s; + } + } + } + else if (z == 0.0F) { + optimized = true; + /* rotate only around y-axis */ + M(0, 0) = c; + M(2, 2) = c; + if (y < 0.0F) { + M(0, 2) = -s; + M(2, 0) = s; + } + else { + M(0, 2) = s; + M(2, 0) = -s; + } + } + } + else if (y == 0.0F) { + if (z == 0.0F) { + optimized = true; + /* rotate only around x-axis */ + M(1, 1) = c; + M(2, 2) = c; + if (x < 0.0F) { + M(1, 2) = s; + M(2, 1) = -s; + } + else { + M(1, 2) = -s; + M(2, 1) = s; + } + } + } + + if (!optimized) { + const float mag = sqrtf(x * x + y * y + z * z); + + if (mag <= 1.0e-4F) { + /* no rotation, leave mat as-is */ + return; + } + + x /= mag; + y /= mag; + z /= mag; + + + /* + * Arbitrary axis rotation matrix. + * + * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied + * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation + * (which is about the X-axis), and the two composite transforms + * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary + * from the arbitrary axis to the X-axis then back. They are + * all elementary rotations. + * + * Rz' is a rotation about the Z-axis, to bring the axis vector + * into the x-z plane. Then Ry' is applied, rotating about the + * Y-axis to bring the axis vector parallel with the X-axis. The + * rotation about the X-axis is then performed. Ry and Rz are + * simply the respective inverse transforms to bring the arbitrary + * axis back to its original orientation. The first transforms + * Rz' and Ry' are considered inverses, since the data from the + * arbitrary axis gives you info on how to get to it, not how + * to get away from it, and an inverse must be applied. + * + * The basic calculation used is to recognize that the arbitrary + * axis vector (x, y, z), since it is of unit length, actually + * represents the sines and cosines of the angles to rotate the + * X-axis to the same orientation, with theta being the angle about + * Z and phi the angle about Y (in the order described above) + * as follows: + * + * cos ( theta ) = x / sqrt ( 1 - z^2 ) + * sin ( theta ) = y / sqrt ( 1 - z^2 ) + * + * cos ( phi ) = sqrt ( 1 - z^2 ) + * sin ( phi ) = z + * + * Note that cos ( phi ) can further be inserted to the above + * formulas: + * + * cos ( theta ) = x / cos ( phi ) + * sin ( theta ) = y / sin ( phi ) + * + * ...etc. Because of those relations and the standard trigonometric + * relations, it is pssible to reduce the transforms down to what + * is used below. It may be that any primary axis chosen will give the + * same results (modulo a sign convention) using thie method. + * + * Particularly nice is to notice that all divisions that might + * have caused trouble when parallel to certain planes or + * axis go away with care paid to reducing the expressions. + * After checking, it does perform correctly under all cases, since + * in all the cases of division where the denominator would have + * been zero, the numerator would have been zero as well, giving + * the expected result. + */ + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * s; + ys = y * s; + zs = z * s; + one_c = 1.0F - c; + + /* We already hold the identity-matrix so we can skip some statements */ + M(0, 0) = (one_c * xx) + c; + M(0, 1) = (one_c * xy) - zs; + M(0, 2) = (one_c * zx) + ys; + /* M(0,3) = 0.0F; */ + + M(1, 0) = (one_c * xy) + zs; + M(1, 1) = (one_c * yy) + c; + M(1, 2) = (one_c * yz) - xs; + /* M(1,3) = 0.0F; */ + + M(2, 0) = (one_c * zx) - ys; + M(2, 1) = (one_c * yz) + xs; + M(2, 2) = (one_c * zz) + c; + /* M(2,3) = 0.0F; */ + + /* + M(3,0) = 0.0F; + M(3,1) = 0.0F; + M(3,2) = 0.0F; + M(3,3) = 1.0F; + */ + } +#undef M + float4x4 _internalMatrix(&m[0]); + //_internalMatrix.r[0] = XMVectorSet(m[0], m[1], m[2], m[3]); + //_internalMatrix.r[1] = XMVectorSet(m[4], m[5], m[6], m[7]); + //_internalMatrix.r[2] = XMVectorSet(m[8], m[9], m[10], m[11]); + //_internalMatrix.r[3] = XMVectorSet(m[12], m[13], m[14], m[15]); + float4x4 temp = matrix * _internalMatrix; + matrix = temp; + + //matmul4(mat, mat, m); + //matrix_multf(mat, m, MAT_FLAG_ROTATION); +} + +static void glhFrustumf2(float *matrix, float left, float right, float bottom, float top, float znear, float zfar) +{ + float temp, temp2, temp3, temp4; + temp = 2.0 * znear; + temp2 = right - left; + temp3 = top - bottom; + temp4 = zfar - znear; + matrix[0] = temp / temp2; + matrix[1] = 0.0; + matrix[2] = 0.0; + matrix[3] = 0.0; + matrix[4] = 0.0; + matrix[5] = temp / temp3; + matrix[6] = 0.0; + matrix[7] = 0.0; + matrix[8] = (right + left) / temp2; + matrix[9] = (top + bottom) / temp3; + matrix[10] = (-zfar - znear) / temp4; + matrix[11] = -1.0; + matrix[12] = 0.0; + matrix[13] = 0.0; + matrix[14] = (-temp * zfar) / temp4; + matrix[15] = 0.0; +} + + +static void glhPerspectivef2(float *matrix, float fovyInDegrees, float aspectRatio, float znear, float zfar) +{ + float ymax, xmax; + float temp, temp2, temp3, temp4; + ymax = znear * tanf(fovyInDegrees * M_PI / 360.0); + //ymin = -ymax; + //xmin = -ymax * aspectRatio; + xmax = ymax * aspectRatio; + glhFrustumf2(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); +} + +#endif // #ifndef __CPUTMath_h__ \ No newline at end of file