public void decode(ColorR5G6B5 colorOrig0, ColorR5G6B5 colorOrig1, UInt32 indices) { var color0 = colors[0] = colorOrig0; var color1 = colors[1] = colorOrig1; // Select color2 and color3 following the COMPRESSED_RGB_S3TC_DXT1_EXT spec // // https://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt // if (colorOrig0.value >= colorOrig1.value) { colors[2] = new Image.Color( (2f * color0.r + color1.r) / 3f, (2f * color0.g + color1.g) / 3f, (2f * color0.b + color1.b) / 3f); colors[3] = new Image.Color( (color0.r + 2f * color1.r) / 3f, (color0.g + 2f * color1.g) / 3f, (color0.b + 2f * color1.b) / 3f); } else { colors[2] = new Image.Color( (color0.r + color1.r) / 2f, (color0.g + color1.g) / 2f, (color0.b + color1.b) / 2f); colors[3] = Image.Color.Black; } // Decode from bitarray for(int i = 0; i < 16; i++) { var index = (byte)(indices & 0x3); pixels[i] = colors[index]; indices = indices >> 2; } }
public void decode(ColorR5G6B5 colorOrig0, ColorR5G6B5 colorOrig1, UInt32 indices) { var color0 = colors[0] = colorOrig0; var color1 = colors[1] = colorOrig1; // Select color2 and color3 following the COMPRESSED_RGB_S3TC_DXT1_EXT spec // // https://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt // if (colorOrig0.value >= colorOrig1.value) { colors[2] = new Image.Color( (2f * color0.r + color1.r) / 3f, (2f * color0.g + color1.g) / 3f, (2f * color0.b + color1.b) / 3f); colors[3] = new Image.Color( (color0.r + 2f * color1.r) / 3f, (color0.g + 2f * color1.g) / 3f, (color0.b + 2f * color1.b) / 3f); } else { colors[2] = new Image.Color( (color0.r + color1.r) / 2f, (color0.g + color1.g) / 2f, (color0.b + color1.b) / 2f); colors[3] = Image.Color.Black; } // Decode from bitarray for (int i = 0; i < 16; i++) { var index = (byte)(indices & 0x3); pixels[i] = colors[index]; indices = indices >> 2; } }
public void encode() { // The idea is to get the most distant complementary colors in a simple way // A simple algorithm with an O(n) function cost var nearRed = pixels[0]; var nearGreen = pixels[0]; var nearBlue = pixels[0]; var nearYellow = pixels[0]; var nearCyan = pixels[0]; var nearMarge = pixels[0]; var nearWhite = pixels[0]; var nearBlack = pixels[0]; var distRed = startDistance; var distGreen = startDistance; var distBlue = startDistance; var distYellow = startDistance; var distCyan = startDistance; var distMarge = startDistance; var distWhite = startDistance; var distBlack = startDistance; var newDistance = startDistance; // First we will check the closest color to each axis foreach (var color in pixels) { newDistance = Image.Color.Red.distance(color); if (newDistance < distRed) { nearRed = color; distRed = newDistance; } newDistance = Image.Color.Green.distance(color); if (newDistance < distGreen) { nearGreen = color; distGreen = newDistance; } newDistance = Image.Color.Blue.distance(color); if (newDistance < distBlue) { nearBlue = color; distBlue = newDistance; } newDistance = Image.Color.Yellow.distance(color); if (newDistance < distYellow) { nearYellow = color; distYellow = newDistance; } newDistance = Image.Color.Cyan.distance(color); if (newDistance < distCyan) { nearCyan = color; distCyan = newDistance;; } newDistance = Image.Color.Margenta.distance(color); if (newDistance < distMarge) { nearMarge = color; distMarge = newDistance; } newDistance = Image.Color.White.distance(color); if (newDistance < distWhite) { nearWhite = color; distWhite = newDistance; } newDistance = Image.Color.Black.distance(color); if (newDistance < distBlack) { nearBlack = color; distBlack = newDistance; } } // Get the most distant complementary colors var lastDistance = nearRed.distance(nearCyan); colors[0] = nearRed; colors[1] = nearCyan; newDistance = nearBlue.distance(nearYellow); if (lastDistance < newDistance) { colors[0] = nearBlue; colors[1] = nearYellow; lastDistance = newDistance; } newDistance = nearGreen.distance(nearMarge); if (lastDistance < newDistance) { colors[0] = nearGreen; colors[1] = nearMarge; } newDistance = nearWhite.distance(nearBlack); if (lastDistance < newDistance) { colors[0] = nearWhite; colors[1] = nearBlack; } // By default make color0 bigger than color1, so we get // more interpolation values ColorR5G6B5 color_0_R5G6B5 = colors[0]; ColorR5G6B5 color_1_R5G6B5 = colors[1]; // Compare the R5G6B5 colors if (color_0_R5G6B5.value < color_1_R5G6B5.value) { colors[1] = color_1_R5G6B5; colors[0] = color_0_R5G6B5; } else { colors[0] = color_0_R5G6B5; colors[1] = color_1_R5G6B5; } // Calculate the colors after the selection colors[2] = new Image.Color( (2f * colors[0].r + colors[1].r) / 3f, (2f * colors[0].g + colors[1].g) / 3f, (2f * colors[0].b + colors[1].b) / 3f); colors[3] = new Image.Color( (colors[0].r + 2f * colors[1].r) / 3f, (colors[0].g + 2f * colors[1].g) / 3f, (colors[0].b + 2f * colors[1].b) / 3f); // For each pixel in the texel block for (int i = 0; i < 16; i++) { // Select the closer color from the 4 colors var currentColor = pixels[i]; lastDistance = currentColor.distance(colors[0]); uint candidateColor = 0; for (uint j = 1; j < 4; j++) { newDistance = currentColor.distance(colors[j]); if (newDistance < lastDistance) { lastDistance = newDistance; candidateColor = j; } } // Save it in the index array indices |= ((candidateColor & 0x3) << (i * 2)); } }