| 1 | using System; | 
 
 
 
 
 | 2 |  | 
 
 
 
 
 | 3 | namespace Oni.Imaging | 
 
 
 
 
 | 4 | { | 
 
 
 
 
 | 5 | internal static class Dxt1 | 
 
 
 
 
 | 6 | { | 
 
 
 
 
 | 7 | public static Surface Decompress(Surface src, SurfaceFormat dstFormat) | 
 
 
 
 
 | 8 | { | 
 
 
 
 
 | 9 | var dst = new Surface(src.Width, src.Height, dstFormat); | 
 
 
 
 
 | 10 | var colors = new Color[4]; | 
 
 
 
 
 | 11 | int srcOffset = 0; | 
 
 
 
 
 | 12 |  | 
 
 
 
 
 | 13 | for (int y = 0; y < dst.Height; y += 4) | 
 
 
 
 
 | 14 | { | 
 
 
 
 
 | 15 | for (int x = 0; x < dst.Width; x += 4) | 
 
 
 
 
 | 16 | { | 
 
 
 
 
 | 17 | colors[0] = Color.ReadBgr565(src.Data, srcOffset); | 
 
 
 
 
 | 18 | srcOffset += 2; | 
 
 
 
 
 | 19 |  | 
 
 
 
 
 | 20 | colors[1] = Color.ReadBgr565(src.Data, srcOffset); | 
 
 
 
 
 | 21 | srcOffset += 2; | 
 
 
 
 
 | 22 |  | 
 
 
 
 
 | 23 | if (colors[0].ToBgr565() > colors[1].ToBgr565()) | 
 
 
 
 
 | 24 | { | 
 
 
 
 
 | 25 | colors[2] = Color.Lerp(colors[0], colors[1], 1.0f / 3.0f); | 
 
 
 
 
 | 26 | colors[3] = Color.Lerp(colors[0], colors[1], 2.0f / 3.0f); | 
 
 
 
 
 | 27 | } | 
 
 
 
 
 | 28 | else | 
 
 
 
 
 | 29 | { | 
 
 
 
 
 | 30 | colors[2] = Color.Lerp(colors[0], colors[1], 0.5f); | 
 
 
 
 
 | 31 | colors[3] = Color.Transparent; | 
 
 
 
 
 | 32 | } | 
 
 
 
 
 | 33 |  | 
 
 
 
 
 | 34 | for (int y2 = 0; y2 < 4; y2++) | 
 
 
 
 
 | 35 | { | 
 
 
 
 
 | 36 | int packedLookup = src.Data[srcOffset++]; | 
 
 
 
 
 | 37 |  | 
 
 
 
 
 | 38 | for (int x2 = 0; x2 < 4; x2++) | 
 
 
 
 
 | 39 | { | 
 
 
 
 
 | 40 | dst[x + x2, y + y2] = colors[packedLookup & 3]; | 
 
 
 
 
 | 41 | packedLookup >>= 2; | 
 
 
 
 
 | 42 | } | 
 
 
 
 
 | 43 | } | 
 
 
 
 
 | 44 | } | 
 
 
 
 
 | 45 | } | 
 
 
 
 
 | 46 |  | 
 
 
 
 
 | 47 | return dst; | 
 
 
 
 
 | 48 | } | 
 
 
 
 
 | 49 |  | 
 
 
 
 
 | 50 | public static Surface Compress(Surface src) | 
 
 
 
 
 | 51 | { | 
 
 
 
 
 | 52 | var dst = new Surface(Utils.Align4(src.Width), Utils.Align4(src.Height), SurfaceFormat.DXT1); | 
 
 
 
 
 | 53 |  | 
 
 
 
 
 | 54 | var block = new Vector3[16]; | 
 
 
 
 
 | 55 | var colors = new Vector3[4]; | 
 
 
 
 
 | 56 | var lookup = new int[16]; | 
 
 
 
 
 | 57 | int dstOffset = 0; | 
 
 
 
 
 | 58 | int height = dst.Height; | 
 
 
 
 
 | 59 | int width = dst.Width; | 
 
 
 
 
 | 60 |  | 
 
 
 
 
 | 61 | for (int y = 0; y < height; y += 4) | 
 
 
 
 
 | 62 | { | 
 
 
 
 
 | 63 | for (int x = 0; x < width; x += 4) | 
 
 
 
 
 | 64 | { | 
 
 
 
 
 | 65 | for (int by = 0; by < 4; by++) | 
 
 
 
 
 | 66 | { | 
 
 
 
 
 | 67 | for (int bx = 0; bx < 4; bx++) | 
 
 
 
 
 | 68 | block[by * 4 + bx] = src[x + bx, y + by].ToVector3(); | 
 
 
 
 
 | 69 | } | 
 
 
 
 
 | 70 |  | 
 
 
 
 
 | 71 | CompressBlock(block, lookup, colors); | 
 
 
 
 
 | 72 |  | 
 
 
 
 
 | 73 | Color.WriteBgr565(new Color(colors[0]), dst.Data, dstOffset); | 
 
 
 
 
 | 74 | dstOffset += 2; | 
 
 
 
 
 | 75 |  | 
 
 
 
 
 | 76 | Color.WriteBgr565(new Color(colors[1]), dst.Data, dstOffset); | 
 
 
 
 
 | 77 | dstOffset += 2; | 
 
 
 
 
 | 78 |  | 
 
 
 
 
 | 79 | for (int by = 0; by < 4; by++) | 
 
 
 
 
 | 80 | { | 
 
 
 
 
 | 81 | int packedLookup = 0; | 
 
 
 
 
 | 82 |  | 
 
 
 
 
 | 83 | for (int bx = 3; bx >= 0; bx--) | 
 
 
 
 
 | 84 | packedLookup = (packedLookup << 2) | lookup[by * 4 + bx]; | 
 
 
 
 
 | 85 |  | 
 
 
 
 
 | 86 | dst.Data[dstOffset++] = (byte)packedLookup; | 
 
 
 
 
 | 87 | } | 
 
 
 
 
 | 88 | } | 
 
 
 
 
 | 89 | } | 
 
 
 
 
 | 90 |  | 
 
 
 
 
 | 91 | return dst; | 
 
 
 
 
 | 92 | } | 
 
 
 
 
 | 93 |  | 
 
 
 
 
 | 94 | private static void CompressBlock(Vector3[] block, int[] lookup, Vector3[] colors) | 
 
 
 
 
 | 95 | { | 
 
 
 
 
 | 96 | colors[0] = block[0]; | 
 
 
 
 
 | 97 | colors[1] = block[0]; | 
 
 
 
 
 | 98 |  | 
 
 
 
 
 | 99 | for (int i = 1; i < block.Length; i++) | 
 
 
 
 
 | 100 | { | 
 
 
 
 
 | 101 | colors[0] = Vector3.Min(colors[0], block[i]); | 
 
 
 
 
 | 102 | colors[1] = Vector3.Max(colors[1], block[i]); | 
 
 
 
 
 | 103 | } | 
 
 
 
 
 | 104 |  | 
 
 
 
 
 | 105 | int maxColor; | 
 
 
 
 
 | 106 |  | 
 
 
 
 
 | 107 | if (new Color(colors[0]).ToBgr565() > new Color(colors[1]).ToBgr565()) | 
 
 
 
 
 | 108 | { | 
 
 
 
 
 | 109 | colors[2] = Vector3.Lerp(colors[0], colors[1], 1.0f / 3.0f); | 
 
 
 
 
 | 110 | colors[3] = Vector3.Lerp(colors[0], colors[1], 2.0f / 3.0f); | 
 
 
 
 
 | 111 | maxColor = 4; | 
 
 
 
 
 | 112 | } | 
 
 
 
 
 | 113 | else | 
 
 
 
 
 | 114 | { | 
 
 
 
 
 | 115 | colors[2] = Vector3.Lerp(colors[0], colors[1], 0.5f); | 
 
 
 
 
 | 116 | maxColor = 3; | 
 
 
 
 
 | 117 | } | 
 
 
 
 
 | 118 |  | 
 
 
 
 
 | 119 | for (int i = 0; i < block.Length; i++) | 
 
 
 
 
 | 120 | { | 
 
 
 
 
 | 121 | lookup[i] = LookupNearest(colors, block[i], maxColor); | 
 
 
 
 
 | 122 | } | 
 
 
 
 
 | 123 | } | 
 
 
 
 
 | 124 |  | 
 
 
 
 
 | 125 | private static int LookupNearest(Vector3[] colors, Vector3 pixel, int maxColor) | 
 
 
 
 
 | 126 | { | 
 
 
 
 
 | 127 | int index = 0; | 
 
 
 
 
 | 128 | float ds = Vector3.DistanceSquared(pixel, colors[0]); | 
 
 
 
 
 | 129 |  | 
 
 
 
 
 | 130 | for (int i = 1; i < maxColor; i++) | 
 
 
 
 
 | 131 | { | 
 
 
 
 
 | 132 | float newDs = Vector3.DistanceSquared(pixel, colors[i]); | 
 
 
 
 
 | 133 |  | 
 
 
 
 
 | 134 | if (newDs < ds) | 
 
 
 
 
 | 135 | { | 
 
 
 
 
 | 136 | ds = newDs; | 
 
 
 
 
 | 137 | index = i; | 
 
 
 
 
 | 138 | } | 
 
 
 
 
 | 139 | } | 
 
 
 
 
 | 140 |  | 
 
 
 
 
 | 141 | return index; | 
 
 
 
 
 | 142 | } | 
 
 
 
 
 | 143 | } | 
 
 
 
 
 | 144 | } |