summaryrefslogtreecommitdiff
path: root/NW4RTools/Util
diff options
context:
space:
mode:
Diffstat (limited to 'NW4RTools/Util')
-rw-r--r--NW4RTools/Util/NVDXT.cs1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/NW4RTools/Util/NVDXT.cs b/NW4RTools/Util/NVDXT.cs
new file mode 100644
index 0000000..fd7d50a
--- /dev/null
+++ b/NW4RTools/Util/NVDXT.cs
@@ -0,0 +1,1037 @@
+// This code is from BrawlLib:
+// http://code.google.com/p/brawltools/source/browse/trunk/BrawlLib/Imaging/NVDXT.cs
+// Modified by Treeki to work within NW4RTools.
+
+
+/* This code was modified from the NVidia Texture Tools source.
+ * http://code.google.com/p/nvidia-texture-tools/
+ */
+
+// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace NW4RTools.Util {
+ unsafe public static class NVDXT {
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ unsafe public struct Vector2 {
+ public float _x;
+ public float _y;
+
+ public Vector2(float x, float y) {
+ _x = x;
+ _y = y;
+ }
+ public Vector2(float s) {
+ _x = s;
+ _y = s;
+ }
+
+ public static Vector2 operator -(Vector2 v) {
+ return new Vector2(-v._x, -v._y);
+ }
+ public static Vector2 operator +(Vector2 v1, Vector2 v2) {
+ return new Vector2(v1._x + v2._x, v1._y + v2._y);
+ }
+ public static Vector2 operator -(Vector2 v1, Vector2 v2) {
+ return new Vector2(v1._x - v2._x, v1._y - v2._y);
+ }
+ public static Vector2 operator -(Vector2 v1, float f) {
+ return new Vector2(v1._x - f, v1._y - f);
+ }
+ public static Vector2 operator *(Vector2 v1, Vector2 v2) {
+ return new Vector2(v1._x * v2._x, v1._y * v2._y);
+ }
+ public static Vector2 operator *(Vector2 v1, float s) {
+ return new Vector2(v1._x * s, v1._y * s);
+ }
+ public static Vector2 operator *(float s, Vector2 v1) {
+ return new Vector2(v1._x * s, v1._y * s);
+ }
+ public static Vector2 operator /(Vector2 v1, Vector2 v2) {
+ return new Vector2(v1._x / v2._x, v1._y / v2._y);
+ }
+ public static Vector2 operator /(Vector2 v1, float s) {
+ return new Vector2(v1._x / s, v1._y / s);
+ }
+
+ public static Vector2 operator +(Vector2 v1, Vector3 v2) {
+ return new Vector2(v1._x + v2._x, v1._y + v2._y);
+ }
+ public static Vector2 operator +(Vector3 v1, Vector2 v2) {
+ return new Vector2(v1._x + v2._x, v1._y + v2._y);
+ }
+
+ public static float Dot(Vector2 v1, Vector2 v2) {
+ return (v1._x * v2._x) + (v1._y * v2._y);
+ }
+ public float Dot(Vector2 v) {
+ return (_x * v._x) + (_y * v._y);
+ }
+
+ public static Vector2 Clamp(Vector2 v1, float min, float max) {
+ v1.Clamp(min, max);
+ return v1;
+ }
+ public void Clamp(float min, float max) {
+ this.Max(min);
+ this.Min(max);
+ }
+
+ public static Vector2 Min(Vector2 v1, Vector2 v2) {
+ return new Vector2(Math.Min(v1._x, v2._x), Math.Min(v1._y, v2._y));
+ }
+ public static Vector2 Min(Vector2 v1, float f) {
+ return new Vector2(Math.Min(v1._x, f), Math.Min(v1._y, f));
+ }
+ public void Min(Vector2 v) {
+ if (_x > v._x)
+ _x = v._x;
+ if (_y > v._y)
+ _y = v._y;
+ }
+ public void Min(float f) {
+ _x = Math.Min(_x, f);
+ _y = Math.Min(_y, f);
+ }
+
+ public static Vector2 Max(Vector2 v1, Vector2 v2) {
+ return new Vector2(Math.Max(v1._x, v2._x), Math.Max(v1._y, v2._y));
+ }
+ public static Vector2 Max(Vector2 v1, float f) {
+ return new Vector2(Math.Max(v1._x, f), Math.Max(v1._y, f));
+ }
+ public void Max(Vector2 v) {
+ if (_x < v._x)
+ _x = v._x;
+ if (_y < v._y)
+ _y = v._y;
+ }
+ public void Max(float f) {
+ _x = Math.Max(_x, f);
+ _y = Math.Max(_y, f);
+ }
+
+ public float DistanceTo(Vector2 v) {
+ Vector2 v1 = this - v;
+ return Vector2.Dot(v1, v1);
+ }
+ public static Vector2 Lerp(Vector2 v1, Vector2 v2, float median) {
+ return (v1 * median) + (v2 * (1.0f - median));
+ }
+
+ public static explicit operator Vector2(Vector3 v) {
+ return new Vector2(v._x, v._y);
+ }
+ public static explicit operator Vector3(Vector2 v) {
+ return new Vector3(v._x, v._y, 0.0f);
+ }
+
+ public static Vector2 Truncate(Vector2 v) {
+ return new Vector2(v._x > 0.0f ? (float)Math.Floor(v._x) : (float)Math.Ceiling(v._x), v._y > 0.0f ? (float)Math.Floor(v._y) : (float)Math.Ceiling(v._y));
+ }
+
+ public override string ToString() {
+ return String.Format("({0},{1})", _x, _y);
+ }
+
+ public bool Contained(Vector2 start, Vector2 end, float expansion) {
+ return Contained(this, start, end, expansion);
+ }
+ public static bool Contained(Vector2 point, Vector2 start, Vector2 end, float expansion) {
+ float* sPtr = (float*)&point;
+ float* s1 = (float*)&start, s2 = (float*)&end;
+ float* temp;
+ for (int i = 0; i < 2; i++) {
+ if (s1[i] > s2[i]) {
+ temp = s1;
+ s1 = s2;
+ s2 = temp;
+ }
+
+ if ((sPtr[i] < (s1[i] - expansion)) || (sPtr[i] > (s2[i] + expansion)))
+ return false;
+ }
+ return true;
+ }
+
+ public float TrueDistance(Vector2 p) {
+ float lenX = Math.Abs(p._x - _x);
+ float lenY = Math.Abs(p._y - _y);
+
+ if (lenX == 0.0f)
+ return lenY; else if (lenY == 0.0f)
+ return lenX;
+ else
+ return (float)(lenX / Math.Cos(Math.Atan(lenY / lenX)));
+ }
+
+ }
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ unsafe public struct Vector3 {
+ public float _x;
+ public float _y;
+ public float _z;
+
+ public Vector3(float x, float y, float z) {
+ _x = x;
+ _y = y;
+ _z = z;
+ }
+ public Vector3(float s) {
+ _x = s;
+ _y = s;
+ _z = s;
+ }
+
+ private const float _colorFactor = 1.0f / 255.0f;
+ /*public static explicit operator Vector3(Color c) {
+ return new Vector3(c.R * _colorFactor, c.G * _colorFactor, c.B * _colorFactor);
+ }
+ public static explicit operator Color(Vector3 v) {
+ return Color.FromArgb((int)(v._x / _colorFactor), (int)(v._y / _colorFactor), (int)(v._z / _colorFactor));
+ }*/
+
+ public static Vector3 operator -(Vector3 v) {
+ return new Vector3(-v._x, -v._y, -v._z);
+ }
+ public static Vector3 operator +(Vector3 v1, Vector3 v2) {
+ return new Vector3(v1._x + v2._x, v1._y + v2._y, v1._z + v2._z);
+ }
+ public static Vector3 operator -(Vector3 v1, Vector3 v2) {
+ return new Vector3(v1._x - v2._x, v1._y - v2._y, v1._z - v2._z);
+ }
+ public static Vector3 operator -(Vector3 v1, float f) {
+ return new Vector3(v1._x - f, v1._y - f, v1._z - f);
+ }
+ public static Vector3 operator *(Vector3 v1, Vector3 v2) {
+ return new Vector3(v1._x * v2._x, v1._y * v2._y, v1._z * v2._z);
+ }
+ public static Vector3 operator *(Vector3 v1, float s) {
+ return new Vector3(v1._x * s, v1._y * s, v1._z * s);
+ }
+ public static Vector3 operator *(float s, Vector3 v1) {
+ return new Vector3(v1._x * s, v1._y * s, v1._z * s);
+ }
+ public static Vector3 operator /(Vector3 v1, Vector3 v2) {
+ return new Vector3(v1._x / v2._x, v1._y / v2._y, v1._z / v2._z);
+ }
+ public static Vector3 operator /(Vector3 v1, float s) {
+ return new Vector3(v1._x / s, v1._y / s, v1._z / s);
+ }
+
+ public static bool operator ==(Vector3 v1, Vector3 v2) {
+ return (v1._x == v2._x) && (v1._y == v2._y) && (v1._z == v2._z);
+ }
+ public static bool operator !=(Vector3 v1, Vector3 v2) {
+ return (v1._x != v2._x) || (v1._y != v2._y) || (v1._z != v2._z);
+ }
+
+ public void Add(Vector3* v) {
+ _x += v->_x;
+ _y += v->_y;
+ _z += v->_z;
+ }
+ public void Add(float v) {
+ _x += v;
+ _y += v;
+ _z += v;
+ }
+ public void Sub(Vector3* v) {
+ _x -= v->_x;
+ _y -= v->_y;
+ _z -= v->_z;
+ }
+ public void Sub(float v) {
+ _x -= v;
+ _y -= v;
+ _z -= v;
+ }
+ public void Multiply(Vector3* v) {
+ _x *= v->_x;
+ _y *= v->_y;
+ _z *= v->_z;
+ }
+ public void Multiply(float v) {
+ _x *= v;
+ _y *= v;
+ _z *= v;
+ }
+
+ public static float* Mult(float* v1, float* v2) {
+ v1[0] = v1[0] * v2[0];
+ v1[1] = v1[1] * v2[1];
+ v1[2] = v1[2] * v2[2];
+ return v1;
+ }
+ public static float* Mult(float* v1, float v2) {
+ v1[0] = v1[0] * v2;
+ v1[1] = v1[1] * v2;
+ v1[2] = v1[2] * v2;
+ return v1;
+ }
+ public static float* Add(float* v1, float* v2) {
+ v1[0] = v1[0] + v2[0];
+ v1[1] = v1[1] + v2[1];
+ v1[2] = v1[2] + v2[2];
+ return v1;
+ }
+ public static float* Add(float* v1, float v2) {
+ v1[0] = v1[0] + v2;
+ v1[1] = v1[1] + v2;
+ v1[2] = v1[2] + v2;
+ return v1;
+ }
+ public static float* Sub(float* v1, float* v2) {
+ v1[0] = v1[0] - v2[0];
+ v1[1] = v1[1] - v2[1];
+ v1[2] = v1[2] - v2[2];
+ return v1;
+ }
+ public static float* Sub(float* v1, float v2) {
+ v1[0] = v1[0] - v2;
+ v1[1] = v1[1] - v2;
+ v1[2] = v1[2] - v2;
+ return v1;
+ }
+
+ //public static float* Mult(float* v1, float* v2) { v1[0] = v1[0] * v2[0]; v1[1] = v1[1] * v2[1]; v1[2] = v1[2] * v2[2]; return v1; }
+ //public static float* Mult(float* v1, float v2) { v1[0] *= v2; v1[1] *= v2; v1[2] *= v2; return v1; }
+ //public static float* Add(float* v1, float* v2) { v1[0] += v2[0]; v1[1] += v2[1]; v1[2] += v2[2]; return v1; }
+ //public static float* Add(float* v1, float v2) { v1[0] += v2; v1[1] += v2; v1[2] += v2; return v1; }
+ //public static float* Sub(float* v1, float* v2) { v1[0] -= v2[0]; v1[1] -= v2[1]; v1[2] -= v2[2]; return v1; }
+ //public static float* Sub(float* v1, float v2) { v1[0] -= v2; v1[1] -= v2; v1[2] -= v2; return v1; }
+
+ public static float Dot(Vector3 v1, Vector3 v2) {
+ return (v1._x * v2._x) + (v1._y * v2._y) + (v1._z * v2._z);
+ }
+ public float Dot(Vector3 v) {
+ return (_x * v._x) + (_y * v._y) + (_z * v._z);
+ }
+ public float Dot(Vector3* v) {
+ return (_x * v->_x) + (_y * v->_y) + (_z * v->_z);
+ }
+ public float Dot() {
+ return (_x * _x) + (_y * _y) + (_z * _z);
+ }
+
+ public static Vector3 Clamp(Vector3 v1, float min, float max) {
+ v1.Clamp(min, max);
+ return v1;
+ }
+ public void Clamp(float min, float max) {
+ this.Max(min);
+ this.Min(max);
+ }
+
+ public static Vector3 Min(Vector3 v1, Vector3 v2) {
+ return new Vector3(Math.Min(v1._x, v2._x), Math.Min(v1._y, v2._y), Math.Min(v1._z, v2._z));
+ }
+ public static Vector3 Min(Vector3 v1, float f) {
+ return new Vector3(Math.Min(v1._x, f), Math.Min(v1._y, f), Math.Min(v1._z, f));
+ }
+ public void Min(Vector3 v) {
+ _x = Math.Min(_x, v._x);
+ _y = Math.Min(_y, v._y);
+ _z = Math.Min(_z, v._z);
+ }
+ public void Min(Vector3* v) {
+ if (v->_x < _x)
+ _x = v->_x;
+ if (v->_y < _y)
+ _y = v->_y;
+ if (v->_z < _z)
+ _z = v->_z;
+ }
+ public void Min(float f) {
+ _x = Math.Min(_x, f);
+ _y = Math.Min(_y, f);
+ _z = Math.Min(_z, f);
+ }
+
+ public static Vector3 Max(Vector3 v1, Vector3 v2) {
+ return new Vector3(Math.Max(v1._x, v2._x), Math.Max(v1._y, v2._y), Math.Max(v1._z, v2._z));
+ }
+ public static Vector3 Max(Vector3 v1, Vector3* v2) {
+ return new Vector3(Math.Max(v1._x, v2->_x), Math.Max(v1._y, v2->_y), Math.Max(v1._z, v2->_z));
+ }
+ public static Vector3 Max(Vector3 v1, float f) {
+ return new Vector3(Math.Max(v1._x, f), Math.Max(v1._y, f), Math.Max(v1._z, f));
+ }
+ public void Max(Vector3 v) {
+ _x = Math.Max(_x, v._x);
+ _y = Math.Max(_y, v._y);
+ _z = Math.Max(_z, v._z);
+ }
+ public void Max(Vector3* v) {
+ if (v->_x > _x)
+ _x = v->_x;
+ if (v->_y > _y)
+ _y = v->_y;
+ if (v->_z > _z)
+ _z = v->_z;
+ }
+ public void Max(float f) {
+ _x = Math.Max(_x, f);
+ _y = Math.Max(_y, f);
+ _z = Math.Max(_z, f);
+ }
+
+ public float DistanceTo(Vector3 v) {
+ return (v - this).Dot();
+ }
+ public static Vector3 Lerp(Vector3 v1, Vector3 v2, float median) {
+ return (v1 * (1.0f - median)) + (v2 * median);
+ }
+ public static Vector3 Floor(Vector3 v) {
+ return new Vector3((int)v._x, (int)v._y, (int)v._z);
+ }
+
+ public Vector3 Cross(Vector3 v) {
+ return new Vector3(_y * v._z - v._y * _z, _z * v._x - v._z * _x, _x * v._y - v._x * _y);
+ }
+
+ public static Vector3 Truncate(Vector3 v) {
+ return new Vector3(v._x > 0.0f ? (float)Math.Floor(v._x) : (float)Math.Ceiling(v._x), v._y > 0.0f ? (float)Math.Floor(v._y) : (float)Math.Ceiling(v._z), v._z > 0.0f ? (float)Math.Floor(v._z) : (float)Math.Ceiling(v._z));
+ }
+
+ public override string ToString() {
+ return String.Format("({0},{1},{2})", _x, _y, _z);
+ }
+
+ public bool Contained(Vector3 start, Vector3 end, float expansion) {
+ return Contained(this, start, end, expansion);
+ }
+ unsafe public static bool Contained(Vector3 point, Vector3 start, Vector3 end, float expansion) {
+ float* sPtr = (float*)&point;
+ float* s1 = (float*)&start, s2 = (float*)&end;
+ float* temp;
+ for (int i = 0; i < 3; i++) {
+ if (s1[i] > s2[i]) {
+ temp = s1;
+ s1 = s2;
+ s2 = temp;
+ }
+
+ if ((sPtr[i] < (s1[i] - expansion)) || (sPtr[i] > (s2[i] + expansion)))
+ return false;
+ }
+ return true;
+ }
+
+ public static Vector3 IntersectZ(Vector3 ray1, Vector3 ray2, float z) {
+ float a = ray2._z - ray1._z;
+
+ float tanX = (ray1._y - ray2._y) / a;
+ float tanY = (ray2._x - ray1._x) / a;
+
+ a = z - ray1._z;
+ return new Vector3(tanY * a + ray1._x, -tanX * a + ray1._y, z);
+ }
+
+ public float TrueDistance(Vector3 p) {
+ return (float)Math.Sqrt((p - this).Dot());
+ }
+ public float TrueDistance() {
+ return (float)Math.Sqrt(Dot());
+ }
+
+ public Vector3 Normalize() {
+ return this / TrueDistance();
+ }
+ public Vector3 Normalize(Vector3 origin) {
+ return (this - origin).Normalize();
+ }
+
+ public Vector3 GetAngles() {
+ return new Vector3((float)Math.Atan2(_y, -_z), (float)Math.Atan2(-_z, _x), (float)Math.Atan2(_y, _x));
+ }
+ public Vector3 GetAngles(Vector3 origin) {
+ return (this - origin).GetAngles();
+ }
+
+ public Vector3 LookatAngles() {
+ return new Vector3((float)Math.Atan2(_y, Math.Sqrt(_x * _x + _z * _z)), (float)Math.Atan2(-_x, -_z), 0.0f);
+ }
+ public Vector3 LookatAngles(Vector3 origin) {
+ return (this - origin).LookatAngles();
+ }
+
+ public float AngleX() {
+ return (float)Math.Atan2(_y, -_z);
+ }
+ public float AngleY() {
+ return (float)Math.Atan2(-_z, _x);
+ }
+ public float AngleZ() {
+ return (float)Math.Atan2(_y, _x);
+ }
+
+ public override int GetHashCode() {
+ fixed (Vector3* p = &this) {
+ int* p2 = (int*)p;
+ return p2[0] ^ p2[1] ^ p2[2];
+ }
+ }
+ public override bool Equals(object obj) {
+ if (obj is Vector3)
+ return this == (Vector3)obj;
+ return false;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ unsafe public struct ARGBPixel {
+ private const float ColorFactor = 1.0f / 255.0f;
+
+ public byte B, G, R, A;
+
+ public ARGBPixel(byte a, byte r, byte g, byte b) {
+ A = a;
+ R = r;
+ G = g;
+ B = b;
+ }
+ public ARGBPixel(byte intensity) {
+ A = 255;
+ R = intensity;
+ G = intensity;
+ B = intensity;
+ }
+
+ /*public int DistanceTo(Color c) {
+ int val = A - c.A;
+ int dist = val * val;
+ val = R - c.R;
+ dist += val * val;
+ val = G - c.G;
+ dist += val * val;
+ val = B - c.B;
+ dist += val * val;
+ return dist;
+ }*/
+ public int DistanceTo(ARGBPixel p) {
+ int val = A - p.A;
+ int dist = val * val;
+ val = R - p.R;
+ dist += val * val;
+ val = G - p.G;
+ dist += val * val;
+ val = B - p.B;
+ return dist + val;
+ }
+ public float Luminance() {
+ return (0.299f * R) + (0.587f * G) + (0.114f * B);
+ }
+ public bool IsGreyscale() {
+ return (R == G) && (G == B);
+ }
+ public int Greyscale() {
+ return (R + G + B) / 3;
+ }
+
+ public static explicit operator ARGBPixel(int val) {
+ return *((ARGBPixel*)&val);
+ }
+ public static explicit operator int(ARGBPixel p) {
+ return *((int*)&p);
+ }
+ public static explicit operator ARGBPixel(uint val) {
+ return *((ARGBPixel*)&val);
+ }
+ public static explicit operator uint(ARGBPixel p) {
+ return *((uint*)&p);
+ }
+ /*public static explicit operator ARGBPixel(Color val) {
+ return (ARGBPixel)val.ToArgb();
+ }
+ public static explicit operator Color(ARGBPixel p) {
+ return Color.FromArgb((int)p);
+ }*/
+ public static explicit operator Vector3(ARGBPixel p) {
+ return new Vector3(p.R * ColorFactor, p.G * ColorFactor, p.B * ColorFactor);
+ }
+
+ public ARGBPixel Min(ARGBPixel p) {
+ return new ARGBPixel(Math.Min(A, p.A), Math.Min(R, p.R), Math.Min(G, p.G), Math.Min(B, p.B));
+ }
+ public ARGBPixel Max(ARGBPixel p) {
+ return new ARGBPixel(Math.Max(A, p.A), Math.Max(R, p.R), Math.Max(G, p.G), Math.Max(B, p.B));
+ }
+
+ public static bool operator ==(ARGBPixel p1, ARGBPixel p2) {
+ return *((uint*)(&p1)) == *((uint*)(&p2));
+ }
+ public static bool operator !=(ARGBPixel p1, ARGBPixel p2) {
+ return *((uint*)(&p1)) != *((uint*)(&p2));
+ }
+
+ public override string ToString() {
+ return String.Format("A:{0:X2} R:{1:X2} G:{2:X2} B:{3:X2}", A, R, G, B);
+ }
+ public override int GetHashCode() {
+ return (int)this;
+ }
+ public override bool Equals(object obj) {
+ if (obj is ARGBPixel)
+ return (ARGBPixel)obj == this;
+ return false;
+ }
+
+ unsafe internal ARGBPixel Inverse() {
+ return new ARGBPixel(A, (byte)(255 - R), (byte)(255 - G), (byte)(255 - B));
+ }
+ unsafe internal ARGBPixel Lighten(int amount) {
+ return new ARGBPixel(A, (byte)Math.Min(R + amount, 255), (byte)Math.Min(G + amount, 255), (byte)Math.Min(B + amount, 255));
+ }
+ unsafe internal ARGBPixel Darken(int amount) {
+ return new ARGBPixel(A, (byte)Math.Max(R - amount, 0), (byte)Math.Max(G - amount, 0), (byte)Math.Max(B - amount, 0));
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ unsafe public struct CMPRBlock {
+ public UInt16 Color0, Color1;
+ public UInt32 Lookup;
+ }
+
+ private static CMPRBlock compressDXT1(ARGBPixel* pBlock) {
+ float* pointData = stackalloc float[48];
+ Vector3* points = (Vector3*)pointData;
+
+ extractColorBlockRGB(pBlock, points);
+
+ // find min and max colors
+ Vector3 maxColor, minColor;
+ findMinMaxColorsBox(points, 16, &maxColor, &minColor);
+
+ selectDiagonal(points, 16, &maxColor, &minColor);
+
+ insetBBox(&maxColor, &minColor);
+
+ ushort color0 = roundAndExpand(&maxColor);
+ ushort color1 = roundAndExpand(&minColor);
+
+ if (color0 < color1) {
+ Vector3 t = maxColor;
+ maxColor = minColor;
+ minColor = t;
+
+ ushort swap = color0;
+ color0 = color1;
+ color1 = swap;
+ }
+
+ CMPRBlock block = new CMPRBlock();
+ block.Color0 = color0;
+ block.Color1 = color1;
+ block.Lookup = computeIndices4(points, &maxColor, &minColor);
+
+
+ optimizeEndPoints4(points, &block);
+
+ return block;
+
+ }
+
+ public static CMPRBlock compressDXT1a(ARGBPixel* img, int imgX, int imgY, int imgW, int imgH) {
+ uint* pData = stackalloc uint[16];
+ ARGBPixel* pBlock = (ARGBPixel*)pData;
+
+ bool hasAlpha = false;
+ bool isSingle = true;
+
+ ARGBPixel p;
+ ARGBPixel* sPtr = img + (imgX + (imgY * imgW));
+ int index = 0;
+ for (int y = 0; y < 4; y++)
+ for (int x = 0; x < 4; x++) {
+ p = sPtr[x + (y * imgW)];
+ pBlock[index++] = p;
+ if (p != pBlock[0])
+ isSingle = false;
+ if (p.A < 128)
+ hasAlpha = true;
+ }
+
+ if (isSingle)
+ return optimalCompressDXT1a(sPtr[0]);
+
+ if (!hasAlpha)
+ return compressDXT1(pBlock);
+
+ // @@ Handle single RGB, with varying alpha? We need tables for single color compressor in 3 color mode.
+ //else if (rgba.isSingleColorNoAlpha()) { ... }
+
+ float* pointData = stackalloc float[48];
+ Vector3* points = (Vector3*)pointData;
+
+ // read block
+ //Vector3 block[16];
+ int num = extractColorBlockRGBA(pBlock, points);
+
+ // find min and max colors
+ Vector3 maxColor, minColor;
+ findMinMaxColorsBox(points, num, &maxColor, &minColor);
+
+ selectDiagonal(points, num, &maxColor, &minColor);
+
+ insetBBox(&maxColor, &minColor);
+
+ ushort color0 = roundAndExpand(&maxColor);
+ ushort color1 = roundAndExpand(&minColor);
+
+ if (color0 < color1) {
+ Vector3 t = maxColor;
+ maxColor = minColor;
+ minColor = t;
+
+ ushort swap = color0;
+ color0 = color1;
+ color1 = swap;
+ }
+
+ CMPRBlock block = new CMPRBlock();
+ block.Color0 = color1;
+ block.Color1 = color0;
+ block.Lookup = computeIndices3(pBlock, &maxColor, &minColor);
+
+ // optimizeEndPoints(block, dxtBlock);
+
+ return block;
+ }
+
+
+ private static CMPRBlock optimalCompressDXT1(ARGBPixel c) {
+ CMPRBlock block = new CMPRBlock();
+
+ uint indices = 0xAAAAAAAA;
+
+ block.Color0 = (ushort)((OMatch5[c.R, 0] << 11) | (OMatch6[c.G, 0] << 5) | OMatch5[c.B, 0]);
+ block.Color1 = (ushort)((OMatch5[c.R, 1] << 11) | (OMatch6[c.G, 1] << 5) | OMatch5[c.B, 1]);
+
+ if (block.Color0 < block.Color1) {
+ ushort swap = block.Color0;
+ block.Color0 = block.Color1;
+ block.Color1 = swap;
+ indices ^= 0x55555555;
+ }
+ block.Lookup = indices;
+ return block;
+ }
+ public static CMPRBlock optimalCompressDXT1a(ARGBPixel rgba) {
+ if (rgba.A < 128) {
+ CMPRBlock block = new CMPRBlock();
+ block.Color0 = 0;
+ block.Color1 = 0;
+ block.Lookup = 0xFFFFFFFF;
+ return block;
+ } else {
+ return optimalCompressDXT1(rgba);
+ }
+ }
+
+ private static int extractColorBlockRGBA(ARGBPixel* colors, Vector3* points) {
+ int num = 0;
+
+ for (int i = 0; i < 16; i++) {
+ ARGBPixel p = colors[i];
+ if (p.A > 127)
+ points[num++] = new Vector3(p.R, p.G, p.B);
+ }
+
+ return num;
+ }
+
+ private static void extractColorBlockRGB(ARGBPixel* colors, Vector3* points) {
+ for (int i = 0; i < 16; i++) {
+ ARGBPixel p = colors[i];
+ points[i] = new Vector3(p.R, p.G, p.B);
+ }
+ }
+
+ private static void findMinMaxColorsBox(Vector3* points, int num, Vector3* maxColor, Vector3* minColor) {
+ *maxColor = new Vector3();
+ *minColor = new Vector3(255.0f);
+
+ for (uint i = 0; i < num; i++) {
+ maxColor->Max(&points[i]);
+ minColor->Min(&points[i]);
+ }
+ }
+
+ private static void selectDiagonal(Vector3* points, int num, Vector3* maxColor, Vector3* minColor) {
+ Vector3 center = (*maxColor + *minColor) * 0.5f;
+ Vector3 t;
+ Vector2* tp = (Vector2*)&t;
+
+ Vector2 covariance = new Vector2();
+ for (uint i = 0; i < num; i++) {
+ t = points[i] - center;
+ covariance += *tp * t._z;
+ }
+
+ float x0 = maxColor->_x;
+ float y0 = maxColor->_y;
+ float x1 = minColor->_x;
+ float y1 = minColor->_y;
+
+ if (covariance._x < 0) {
+ float swap = x0;
+ x0 = x1;
+ x1 = swap;
+ }
+
+ if (covariance._y < 0) {
+ float swap = y0;
+ y0 = y1;
+ y1 = swap;
+ }
+
+ maxColor->_x = x0;
+ maxColor->_y = y0;
+
+ minColor->_x = x1;
+ minColor->_y = y1;
+ }
+
+ private static void insetBBox(Vector3* maxColor, Vector3* minColor) {
+ Vector3 inset = (*maxColor - *minColor) / 16.0f - (8.0f / 255.0f) / 16.0f;
+
+ maxColor->Sub(&inset);
+ maxColor->Clamp(0.0f, 255.0f);
+
+ minColor->Add(&inset);
+ minColor->Clamp(0.0f, 255.0f);
+ }
+
+ private static ushort roundAndExpand(Vector3* v) {
+ uint r = (uint)(Math.Min(Math.Max(v->_x * (31.0f / 255.0f), 0.0f), 31.0f) + 0.5f);
+ uint g = (uint)(Math.Min(Math.Max(v->_y * (63.0f / 255.0f), 0.0f), 63.0f) + 0.5f);
+ uint b = (uint)(Math.Min(Math.Max(v->_z * (31.0f / 255.0f), 0.0f), 31.0f) + 0.5f);
+
+
+ ushort w = (ushort)((r << 11) | (g << 5) | b);
+
+ r = (r << 3) | (r >> 2);
+ g = (g << 2) | (g >> 4);
+ b = (b << 3) | (b >> 2);
+ *v = new Vector3(r, g, b);
+
+ return w;
+ }
+
+ private static uint computeIndices3(ARGBPixel* colors, Vector3* maxColor, Vector3* minColor) {
+ float* pData = stackalloc float[9];
+ Vector3* palette = (Vector3*)pData;
+
+ palette[0] = *minColor;
+ palette[1] = *maxColor;
+ palette[2] = (palette[0] + palette[1]) * 0.5f;
+
+ uint indices = 0;
+ for (int i = 0; i < 16; i++) {
+ ARGBPixel p = colors[i];
+ Vector3 color = new Vector3(p.R, p.G, p.B);
+
+ float d0 = colorDistance(&palette[0], &color);
+ float d1 = colorDistance(&palette[1], &color);
+ float d2 = colorDistance(&palette[2], &color);
+
+ uint index;
+ if (p.A < 128)
+ index = 3; else if (d0 < d1 && d0 < d2)
+ index = 0; else if (d1 < d2)
+ index = 1;
+ else
+ index = 2;
+
+ indices <<= 2;
+ indices |= index;
+ }
+
+ return indices;
+ }
+ private static uint computeIndices4(Vector3* points, Vector3* maxColor, Vector3* minColor) {
+ float* pData = stackalloc float[12];
+ Vector3* palette = (Vector3*)pData;
+
+ palette[0] = *maxColor;
+ palette[1] = *minColor;
+ palette[2] = Vector3.Lerp(palette[0], palette[1], 1.0f / 3.0f);
+ palette[3] = Vector3.Lerp(palette[0], palette[1], 2.0f / 3.0f);
+
+ uint indices = 0;
+ for (int i = 0; i < 16; i++) {
+ Vector3 color = points[i];
+
+ float d0 = colorDistance(&palette[0], &color);
+ float d1 = colorDistance(&palette[1], &color);
+ float d2 = colorDistance(&palette[2], &color);
+ float d3 = colorDistance(&palette[3], &color);
+
+ indices <<= 2;
+
+ if (d3 < d2 && d3 < d1 && d3 < d0)
+ indices |= 3; else if (d2 < d1 && d2 < d0)
+ indices |= 2; else if (d1 < d0)
+ indices |= 1;
+
+ //uint b0 = (d0 > d3) ? (uint)1 : 0;
+ //uint b1 = (d1 > d2) ? (uint)1 : 0;
+ //uint b2 = (d0 > d2) ? (uint)1 : 0;
+ //uint b3 = (d1 > d3) ? (uint)1 : 0;
+ //uint b4 = (d2 > d3) ? (uint)1 : 0;
+
+ //uint x0 = b1 & b2;
+ //uint x1 = b0 & b3;
+ //uint x2 = b0 & b4;
+
+ //indices <<= 2;
+ //indices |= x2 | ((x0 | x1) << 1);
+ }
+
+ return indices;
+ }
+
+ private static void optimizeEndPoints4(Vector3* points, CMPRBlock* block) {
+ float alpha2_sum = 0.0f;
+ float beta2_sum = 0.0f;
+ float alphabeta_sum = 0.0f;
+ Vector3 alphax_sum = new Vector3();
+ Vector3 betax_sum = new Vector3();
+ uint indices = block->Lookup;
+
+ for (int i = 0, bi = 30; i < 16; ++i,bi -= 2) {
+ uint bits = indices >> bi;
+
+ float beta = bits & 1;
+ if ((bits & 2) != 0)
+ beta = (1 + beta) / 3.0f;
+ float alpha = 1.0f - beta;
+
+ alpha2_sum += alpha * alpha;
+ beta2_sum += beta * beta;
+ alphabeta_sum += alpha * beta;
+ alphax_sum += alpha * points[i];
+ betax_sum += beta * points[i];
+ }
+
+ float denom = alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum;
+ if (Math.Abs(denom) <= 0.0001f)
+ return;
+
+ float factor = 1.0f / denom;
+
+ Vector3 a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor;
+ Vector3 b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor;
+
+ a.Clamp(0.0f, 255.0f);
+ b.Clamp(0.0f, 255.0f);
+
+ ushort color0 = roundAndExpand(&a);
+ ushort color1 = roundAndExpand(&b);
+
+ if (color0 < color1) {
+ Vector3 t = a;
+ a = b;
+ b = t;
+
+ ushort swap = color0;
+ color0 = color1;
+ color1 = swap;
+ }
+
+ //CMPRBlock block = new CMPRBlock();
+ block->Color0 = color0;
+ block->Color1 = color1;
+ block->Lookup = computeIndices4(points, &a, &b);
+ }
+
+ private static float colorDistance(Vector3* c0, Vector3* c1) {
+ Vector3 v = *c0 - *c1;
+ return Vector3.Dot(v, v);
+ }
+
+ #region OptTables
+ public static readonly byte[,] OMatch5 = new byte[256, 2] { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x01 }, { 0x00, 0x01 }, { 0x01, 0x00 }, { 0x01, 0x00 }, { 0x01, 0x00 }, { 0x01, 0x01 }, { 0x01, 0x01 }, { 0x01, 0x01 },
+ { 0x01, 0x02 }, { 0x00, 0x04 }, { 0x02, 0x01 }, { 0x02, 0x01 }, { 0x02, 0x01 }, { 0x02, 0x02 }, { 0x02, 0x02 }, { 0x02, 0x02 }, { 0x02, 0x03 }, { 0x01, 0x05 },
+ { 0x03, 0x02 }, { 0x03, 0x02 }, { 0x04, 0x00 }, { 0x03, 0x03 }, { 0x03, 0x03 }, { 0x03, 0x03 }, { 0x03, 0x04 }, { 0x03, 0x04 }, { 0x03, 0x04 }, { 0x03, 0x05 },
+ { 0x04, 0x03 }, { 0x04, 0x03 }, { 0x05, 0x02 }, { 0x04, 0x04 }, { 0x04, 0x04 }, { 0x04, 0x05 }, { 0x04, 0x05 }, { 0x05, 0x04 }, { 0x05, 0x04 }, { 0x05, 0x04 },
+ { 0x06, 0x03 }, { 0x05, 0x05 }, { 0x05, 0x05 }, { 0x05, 0x06 }, { 0x04, 0x08 }, { 0x06, 0x05 }, { 0x06, 0x05 }, { 0x06, 0x05 }, { 0x06, 0x06 }, { 0x06, 0x06 },
+ { 0x06, 0x06 }, { 0x06, 0x07 }, { 0x05, 0x09 }, { 0x07, 0x06 }, { 0x07, 0x06 }, { 0x08, 0x04 }, { 0x07, 0x07 }, { 0x07, 0x07 }, { 0x07, 0x07 }, { 0x07, 0x08 },
+ { 0x07, 0x08 }, { 0x07, 0x08 }, { 0x07, 0x09 }, { 0x08, 0x07 }, { 0x08, 0x07 }, { 0x09, 0x06 }, { 0x08, 0x08 }, { 0x08, 0x08 }, { 0x08, 0x09 }, { 0x08, 0x09 },
+ { 0x09, 0x08 }, { 0x09, 0x08 }, { 0x09, 0x08 }, { 0x0A, 0x07 }, { 0x09, 0x09 }, { 0x09, 0x09 }, { 0x09, 0x0A }, { 0x08, 0x0C }, { 0x0A, 0x09 }, { 0x0A, 0x09 },
+ { 0x0A, 0x09 }, { 0x0A, 0x0A }, { 0x0A, 0x0A }, { 0x0A, 0x0A }, { 0x0A, 0x0B }, { 0x09, 0x0D }, { 0x0B, 0x0A }, { 0x0B, 0x0A }, { 0x0C, 0x08 }, { 0x0B, 0x0B },
+ { 0x0B, 0x0B }, { 0x0B, 0x0B }, { 0x0B, 0x0C }, { 0x0B, 0x0C }, { 0x0B, 0x0C }, { 0x0B, 0x0D }, { 0x0C, 0x0B }, { 0x0C, 0x0B }, { 0x0D, 0x0A }, { 0x0C, 0x0C },
+ { 0x0C, 0x0C }, { 0x0C, 0x0D }, { 0x0C, 0x0D }, { 0x0D, 0x0C }, { 0x0D, 0x0C }, { 0x0D, 0x0C }, { 0x0E, 0x0B }, { 0x0D, 0x0D }, { 0x0D, 0x0D }, { 0x0D, 0x0E },
+ { 0x0C, 0x10 }, { 0x0E, 0x0D }, { 0x0E, 0x0D }, { 0x0E, 0x0D }, { 0x0E, 0x0E }, { 0x0E, 0x0E }, { 0x0E, 0x0E }, { 0x0E, 0x0F }, { 0x0D, 0x11 }, { 0x0F, 0x0E },
+ { 0x0F, 0x0E }, { 0x10, 0x0C }, { 0x0F, 0x0F }, { 0x0F, 0x0F }, { 0x0F, 0x0F }, { 0x0F, 0x10 }, { 0x0F, 0x10 }, { 0x0F, 0x10 }, { 0x0F, 0x11 }, { 0x10, 0x0F },
+ { 0x10, 0x0F }, { 0x11, 0x0E }, { 0x10, 0x10 }, { 0x10, 0x10 }, { 0x10, 0x11 }, { 0x10, 0x11 }, { 0x11, 0x10 }, { 0x11, 0x10 }, { 0x11, 0x10 }, { 0x12, 0x0F },
+ { 0x11, 0x11 }, { 0x11, 0x11 }, { 0x11, 0x12 }, { 0x10, 0x14 }, { 0x12, 0x11 }, { 0x12, 0x11 }, { 0x12, 0x11 }, { 0x12, 0x12 }, { 0x12, 0x12 }, { 0x12, 0x12 },
+ { 0x12, 0x13 }, { 0x11, 0x15 }, { 0x13, 0x12 }, { 0x13, 0x12 }, { 0x14, 0x10 }, { 0x13, 0x13 }, { 0x13, 0x13 }, { 0x13, 0x13 }, { 0x13, 0x14 }, { 0x13, 0x14 },
+ { 0x13, 0x14 }, { 0x13, 0x15 }, { 0x14, 0x13 }, { 0x14, 0x13 }, { 0x15, 0x12 }, { 0x14, 0x14 }, { 0x14, 0x14 }, { 0x14, 0x15 }, { 0x14, 0x15 }, { 0x15, 0x14 },
+ { 0x15, 0x14 }, { 0x15, 0x14 }, { 0x16, 0x13 }, { 0x15, 0x15 }, { 0x15, 0x15 }, { 0x15, 0x16 }, { 0x14, 0x18 }, { 0x16, 0x15 }, { 0x16, 0x15 }, { 0x16, 0x15 },
+ { 0x16, 0x16 }, { 0x16, 0x16 }, { 0x16, 0x16 }, { 0x16, 0x17 }, { 0x15, 0x19 }, { 0x17, 0x16 }, { 0x17, 0x16 }, { 0x18, 0x14 }, { 0x17, 0x17 }, { 0x17, 0x17 },
+ { 0x17, 0x17 }, { 0x17, 0x18 }, { 0x17, 0x18 }, { 0x17, 0x18 }, { 0x17, 0x19 }, { 0x18, 0x17 }, { 0x18, 0x17 }, { 0x19, 0x16 }, { 0x18, 0x18 }, { 0x18, 0x18 },
+ { 0x18, 0x19 }, { 0x18, 0x19 }, { 0x19, 0x18 }, { 0x19, 0x18 }, { 0x19, 0x18 }, { 0x1A, 0x17 }, { 0x19, 0x19 }, { 0x19, 0x19 }, { 0x19, 0x1A }, { 0x18, 0x1C },
+ { 0x1A, 0x19 }, { 0x1A, 0x19 }, { 0x1A, 0x19 }, { 0x1A, 0x1A }, { 0x1A, 0x1A }, { 0x1A, 0x1A }, { 0x1A, 0x1B }, { 0x19, 0x1D }, { 0x1B, 0x1A }, { 0x1B, 0x1A },
+ { 0x1C, 0x18 }, { 0x1B, 0x1B }, { 0x1B, 0x1B }, { 0x1B, 0x1B }, { 0x1B, 0x1C }, { 0x1B, 0x1C }, { 0x1B, 0x1C }, { 0x1B, 0x1D }, { 0x1C, 0x1B }, { 0x1C, 0x1B },
+ { 0x1D, 0x1A }, { 0x1C, 0x1C }, { 0x1C, 0x1C }, { 0x1C, 0x1D }, { 0x1C, 0x1D }, { 0x1D, 0x1C }, { 0x1D, 0x1C }, { 0x1D, 0x1C }, { 0x1E, 0x1B }, { 0x1D, 0x1D },
+ { 0x1D, 0x1D }, { 0x1D, 0x1E }, { 0x1D, 0x1E }, { 0x1E, 0x1D }, { 0x1E, 0x1D }, { 0x1E, 0x1D }, { 0x1E, 0x1E }, { 0x1E, 0x1E }, { 0x1E, 0x1E }, { 0x1E, 0x1F },
+ { 0x1E, 0x1F }, { 0x1F, 0x1E }, { 0x1F, 0x1E }, { 0x1F, 0x1E }, { 0x1F, 0x1F }, { 0x1F, 0x1F } };
+
+
+ public static readonly byte[,] OMatch6 = new byte[256, 2] { { 0x00, 0x00 }, { 0x00, 0x01 }, { 0x01, 0x00 }, { 0x01, 0x01 }, { 0x01, 0x01 }, { 0x01, 0x02 }, { 0x02, 0x01 }, { 0x02, 0x02 }, { 0x02, 0x02 }, { 0x02, 0x03 },
+ { 0x03, 0x02 }, { 0x03, 0x03 }, { 0x03, 0x03 }, { 0x03, 0x04 }, { 0x04, 0x03 }, { 0x04, 0x04 }, { 0x04, 0x04 }, { 0x04, 0x05 }, { 0x05, 0x04 }, { 0x05, 0x05 },
+ { 0x05, 0x05 }, { 0x05, 0x06 }, { 0x06, 0x05 }, { 0x00, 0x11 }, { 0x06, 0x06 }, { 0x06, 0x07 }, { 0x07, 0x06 }, { 0x02, 0x10 }, { 0x07, 0x07 }, { 0x07, 0x08 },
+ { 0x08, 0x07 }, { 0x03, 0x11 }, { 0x08, 0x08 }, { 0x08, 0x09 }, { 0x09, 0x08 }, { 0x05, 0x10 }, { 0x09, 0x09 }, { 0x09, 0x0A }, { 0x0A, 0x09 }, { 0x06, 0x11 },
+ { 0x0A, 0x0A }, { 0x0A, 0x0B }, { 0x0B, 0x0A }, { 0x08, 0x10 }, { 0x0B, 0x0B }, { 0x0B, 0x0C }, { 0x0C, 0x0B }, { 0x09, 0x11 }, { 0x0C, 0x0C }, { 0x0C, 0x0D },
+ { 0x0D, 0x0C }, { 0x0B, 0x10 }, { 0x0D, 0x0D }, { 0x0D, 0x0E }, { 0x0E, 0x0D }, { 0x0C, 0x11 }, { 0x0E, 0x0E }, { 0x0E, 0x0F }, { 0x0F, 0x0E }, { 0x0E, 0x10 },
+ { 0x0F, 0x0F }, { 0x0F, 0x10 }, { 0x10, 0x0E }, { 0x10, 0x0F }, { 0x11, 0x0E }, { 0x10, 0x10 }, { 0x10, 0x11 }, { 0x11, 0x10 }, { 0x12, 0x0F }, { 0x11, 0x11 },
+ { 0x11, 0x12 }, { 0x12, 0x11 }, { 0x14, 0x0E }, { 0x12, 0x12 }, { 0x12, 0x13 }, { 0x13, 0x12 }, { 0x15, 0x0F }, { 0x13, 0x13 }, { 0x13, 0x14 }, { 0x14, 0x13 },
+ { 0x17, 0x0E }, { 0x14, 0x14 }, { 0x14, 0x15 }, { 0x15, 0x14 }, { 0x18, 0x0F }, { 0x15, 0x15 }, { 0x15, 0x16 }, { 0x16, 0x15 }, { 0x1A, 0x0E }, { 0x16, 0x16 },
+ { 0x16, 0x17 }, { 0x17, 0x16 }, { 0x1B, 0x0F }, { 0x17, 0x17 }, { 0x17, 0x18 }, { 0x18, 0x17 }, { 0x13, 0x21 }, { 0x18, 0x18 }, { 0x18, 0x19 }, { 0x19, 0x18 },
+ { 0x15, 0x20 }, { 0x19, 0x19 }, { 0x19, 0x1A }, { 0x1A, 0x19 }, { 0x16, 0x21 }, { 0x1A, 0x1A }, { 0x1A, 0x1B }, { 0x1B, 0x1A }, { 0x18, 0x20 }, { 0x1B, 0x1B },
+ { 0x1B, 0x1C }, { 0x1C, 0x1B }, { 0x19, 0x21 }, { 0x1C, 0x1C }, { 0x1C, 0x1D }, { 0x1D, 0x1C }, { 0x1B, 0x20 }, { 0x1D, 0x1D }, { 0x1D, 0x1E }, { 0x1E, 0x1D },
+ { 0x1C, 0x21 }, { 0x1E, 0x1E }, { 0x1E, 0x1F }, { 0x1F, 0x1E }, { 0x1E, 0x20 }, { 0x1F, 0x1F }, { 0x1F, 0x20 }, { 0x20, 0x1E }, { 0x20, 0x1F }, { 0x21, 0x1E },
+ { 0x20, 0x20 }, { 0x20, 0x21 }, { 0x21, 0x20 }, { 0x22, 0x1F }, { 0x21, 0x21 }, { 0x21, 0x22 }, { 0x22, 0x21 }, { 0x24, 0x1E }, { 0x22, 0x22 }, { 0x22, 0x23 },
+ { 0x23, 0x22 }, { 0x25, 0x1F }, { 0x23, 0x23 }, { 0x23, 0x24 }, { 0x24, 0x23 }, { 0x27, 0x1E }, { 0x24, 0x24 }, { 0x24, 0x25 }, { 0x25, 0x24 }, { 0x28, 0x1F },
+ { 0x25, 0x25 }, { 0x25, 0x26 }, { 0x26, 0x25 }, { 0x2A, 0x1E }, { 0x26, 0x26 }, { 0x26, 0x27 }, { 0x27, 0x26 }, { 0x2B, 0x1F }, { 0x27, 0x27 }, { 0x27, 0x28 },
+ { 0x28, 0x27 }, { 0x23, 0x31 }, { 0x28, 0x28 }, { 0x28, 0x29 }, { 0x29, 0x28 }, { 0x25, 0x30 }, { 0x29, 0x29 }, { 0x29, 0x2A }, { 0x2A, 0x29 }, { 0x26, 0x31 },
+ { 0x2A, 0x2A }, { 0x2A, 0x2B }, { 0x2B, 0x2A }, { 0x28, 0x30 }, { 0x2B, 0x2B }, { 0x2B, 0x2C }, { 0x2C, 0x2B }, { 0x29, 0x31 }, { 0x2C, 0x2C }, { 0x2C, 0x2D },
+ { 0x2D, 0x2C }, { 0x2B, 0x30 }, { 0x2D, 0x2D }, { 0x2D, 0x2E }, { 0x2E, 0x2D }, { 0x2C, 0x31 }, { 0x2E, 0x2E }, { 0x2E, 0x2F }, { 0x2F, 0x2E }, { 0x2E, 0x30 },
+ { 0x2F, 0x2F }, { 0x2F, 0x30 }, { 0x30, 0x2E }, { 0x30, 0x2F }, { 0x31, 0x2E }, { 0x30, 0x30 }, { 0x30, 0x31 }, { 0x31, 0x30 }, { 0x32, 0x2F }, { 0x31, 0x31 },
+ { 0x31, 0x32 }, { 0x32, 0x31 }, { 0x34, 0x2E }, { 0x32, 0x32 }, { 0x32, 0x33 }, { 0x33, 0x32 }, { 0x35, 0x2F }, { 0x33, 0x33 }, { 0x33, 0x34 }, { 0x34, 0x33 },
+ { 0x37, 0x2E }, { 0x34, 0x34 }, { 0x34, 0x35 }, { 0x35, 0x34 }, { 0x38, 0x2F }, { 0x35, 0x35 }, { 0x35, 0x36 }, { 0x36, 0x35 }, { 0x3A, 0x2E }, { 0x36, 0x36 },
+ { 0x36, 0x37 }, { 0x37, 0x36 }, { 0x3B, 0x2F }, { 0x37, 0x37 }, { 0x37, 0x38 }, { 0x38, 0x37 }, { 0x3D, 0x2E }, { 0x38, 0x38 }, { 0x38, 0x39 }, { 0x39, 0x38 },
+ { 0x3E, 0x2F }, { 0x39, 0x39 }, { 0x39, 0x3A }, { 0x3A, 0x39 }, { 0x3A, 0x3A }, { 0x3A, 0x3A }, { 0x3A, 0x3B }, { 0x3B, 0x3A }, { 0x3B, 0x3B }, { 0x3B, 0x3B },
+ { 0x3B, 0x3C }, { 0x3C, 0x3B }, { 0x3C, 0x3C }, { 0x3C, 0x3C }, { 0x3C, 0x3D }, { 0x3D, 0x3C }, { 0x3D, 0x3D }, { 0x3D, 0x3D }, { 0x3D, 0x3E }, { 0x3E, 0x3D },
+ { 0x3E, 0x3E }, { 0x3E, 0x3E }, { 0x3E, 0x3F }, { 0x3F, 0x3E }, { 0x3F, 0x3F }, { 0x3F, 0x3F } };
+
+ #endregion
+ }
+}