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 | }
|
---|