source: OniSplit/Imaging/Dxt1.cs

Last change on this file was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 3.4 KB
Line 
1using System;
2
3namespace 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}
Note: See TracBrowser for help on using the repository browser.