public uint Dimmer(int brightness, byte voxel) { return(Values[voxel % Count][BasicTools.Clamp(brightness, 0, 3)]); }
public Colorizer(uint[] palette) { Count = palette.Length; Reducer = new PaletteReducer(palette); Primary = new byte[] { Reducer.ReduceIndex(0xFF0000FF), Reducer.ReduceIndex(0xFFFF00FF), Reducer.ReduceIndex(0x00FF00FF), Reducer.ReduceIndex(0x00FFFFFF), Reducer.ReduceIndex(0x0000FFFF), Reducer.ReduceIndex(0xFF00FFFF) }; Grays = new byte[] { Reducer.ReduceIndex(0xFF000000), Reducer.ReduceIndex(0xFF444444), Reducer.ReduceIndex(0xFF888888), Reducer.ReduceIndex(0xFFCCCCCC), Reducer.ReduceIndex(0xFFFFFFFF) }; //int THRESHOLD = 64;//0.011; // threshold controls the "stark-ness" of color changes; must not be negative. byte[] paletteMapping = new byte[1 << 16]; uint[] reverse = new uint[Count]; Ramps = BasicTools.Fill((byte)0, Count, 4); Values = BasicTools.Fill(0u, Count, 4); uint[] lumas = new uint[Count], cws = new uint[Count], cms = new uint[Count]; uint yLim = 63, cwLim = 31, cmLim = 31; int shift1 = 6, shift2 = 11; uint color; int r, g, b; int cw, cm; for (int i = 1; i < Count; i++) { color = palette[i]; if ((color & 0x80000000) == 0) { color |= 0xFF000000; } r = (int)(color & 0xFF); g = (int)(color >> 8 & 0xFF); b = (int)(color >> 16 & 0xFF); cw = r - b; cm = g - b; paletteMapping[ reverse[i] = (lumas[i] = (uint)(r * 3 + g * 4 + b) >> 5) | (cws[i] = (uint)cw + 255 >> 4) << shift1 | (cms[i] = (uint)cm + 255 >> 4) << shift2] = (byte)i; } for (int icm = 0; icm <= cmLim; icm++) { for (int icw = 0; icw <= cwLim; icw++) { for (int iy = 0; iy <= yLim; iy++) { int c2 = icm << shift2 | icw << shift1 | iy; if (paletteMapping[c2] == 0) { double dist = double.PositiveInfinity; for (int i = 1; i < Count; i++) { if (Math.Abs(lumas[i] - (int)iy) < 28 && dist > (dist = Math.Min(dist, DifferenceWarmMild((int)lumas[i], (int)cws[i], (int)cms[i], iy, icw, icm)))) { paletteMapping[c2] = (byte)i; } } } } } } //float adj; float cwf, cmf; //int idx2; for (int i = 1; i < Count; i++) { uint rev = reverse[i]; int y = (int)(rev & yLim), match = i, yBright = y * 9 / 2, yDim = y * 3, yDark = y, luma, warm, mild; cwf = (cw = (int)cws[i] - 16) / 30f; cmf = (cm = (int)cms[i] - 16) / 30f; //Console.WriteLine("i={0:D3}: y={1:D3}, cw={2:D3}, cm={3:D3}", i, y, cw, cm); //values[i][0] = values[i][1] = values[i][3] = Values[i][2] = palette[i]; luma = yDim; //warm = ((cw * 395 + 31) / 32 - 192) / 16; //mild = ((cm * 395 + 31) / 32 - 192) / 16; warm = cw * 5 / 3; mild = cm * 5 / 3; r = (luma + warm * 5 - mild * 4); g = (luma - warm * 3 + mild * 4); b = (luma - warm * 3 - mild * 4); Values[i][1] = (uint)( BasicTools.Clamp(r, 0, 255) | BasicTools.Clamp(g, 0, 255) << 8 | BasicTools.Clamp(b, 0, 255) << 16) | 0xFF000000U; luma = yBright; //warm = ((cw * 333 + 31) / 32 - 162) / 16; //mild = ((cm * 333 + 31) / 32 - 162) / 16; warm = cw * 5 / 3; mild = cm * 5 / 3; r = (luma + warm * 5 - mild * 4); g = (luma - warm * 3 + mild * 4); b = (luma - warm * 3 - mild * 4); Values[i][3] = (uint)( BasicTools.Clamp(r, 0, 255) | BasicTools.Clamp(g, 0, 255) << 8 | BasicTools.Clamp(b, 0, 255) << 16) | 0xFF000000U; luma = yDark; //warm = ((cw * 215) / 16 - 208) / 16; //mild = ((cm * 215) / 16 - 208) / 16; warm = cw * 3 / 2; mild = cm * 3 / 2; r = (luma + warm * 5 - mild * 4); g = (luma - warm * 3 + mild * 4); b = (luma - warm * 3 - mild * 4); Values[i][0] = (uint)( BasicTools.Clamp(r, 0, 255) | BasicTools.Clamp(g, 0, 255) << 8 | BasicTools.Clamp(b, 0, 255) << 16) | 0xFF000000U; //Console.WriteLine("{0:D}:{1:X8},{2:X8},{3:X8},{4:X8}", i, Values[i][0], Values[i][1], Values[i][2], Values[i][3]); //// This seems like a much simpler approach than the large comment below it. //// The downside is that in some small palettes, the lighter or darker variants may be the same as the original, or both //// darker variants could be the same. Ramps[i][0] = Reducer.ReduceIndex(Values[i][0]); Ramps[i][1] = Reducer.ReduceIndex(Values[i][1]); Ramps[i][2] = (byte)i; Ramps[i][3] = Reducer.ReduceIndex(Values[i][3]); //Ramps[i][2] = (byte)i; //Ramps[i][3] = Grays[4];//15; //0xFFFFFFFF, white //Ramps[i][1] = Grays[0];//0x010101FF, black //Ramps[i][0] = Grays[0];//0x010101FF, black //for (int yy = y + 2, rr = (int)rev + 2; yy <= yLim; yy++, rr++) //{ // if ((idx2 = paletteMapping[rr] & 255) != i && DifferenceWarmMild((int)lumas[idx2], (int)cws[idx2], (int)cms[idx2], y, cw, cm) > THRESHOLD) // { // Ramps[i][3] = paletteMapping[rr]; // break; // } // adj = 1f + ((yLim + 1) * 0.5f - yy) / 1024f; // cwf = BasicTools.Clamp(cwf * adj, -0.5f, 0.5f); // cmf = BasicTools.Clamp(cmf * adj, -0.5f, 0.5f); // rr = yy // | (cw = (int)((cwf + 0.5f) * cwLim)) << shift1 // | (cm = (int)((cmf + 0.5f) * cmLim)) << shift2; //} //cwf = ((cw = (int)cws[i]) - 16) * 11f / 32f; //cmf = ((cm = (int)cms[i]) - 16) * 11f / 32f; //for (int yy = y - 2, rr = (int)rev - 2; yy > 0; rr--) //{ // if ((idx2 = paletteMapping[rr] & 255) != i && DifferenceWarmMild((int)lumas[idx2], (int)cws[idx2], (int)cms[idx2], y, cw, cm) > THRESHOLD) // { // Ramps[i][1] = paletteMapping[rr]; // rev = (uint)rr; // y = yy; // match = paletteMapping[rr] & 255; // break; // } // adj = 1f + (yy - (yLim + 1) * 0.5f) / 1024f; // cwf = BasicTools.Clamp(cwf * adj, -0.5f, 0.5f); // cmf = BasicTools.Clamp(cmf * adj, -0.5f, 0.5f); // rr = yy // | (cw = (int)((cwf + 0.5f) * cwLim)) << shift1 // | (cm = (int)((cmf + 0.5f) * cmLim)) << shift2; // if (--yy == 0) // { // match = -1; // } //} //if (match >= 0) //{ // cwf = ((cw = (int)cws[match]) - 16) / 30f; // cmf = ((cm = (int)cms[match]) - 16) / 30f; // for (int yy = y - 3, rr = (int)rev - 3; yy > 0; yy--, rr--) // { // if ((idx2 = paletteMapping[rr] & 255) != match && DifferenceWarmMild((int)lumas[idx2], (int)cws[idx2], (int)cms[idx2], y, cw, cm) > THRESHOLD) // { // Ramps[i][0] = paletteMapping[rr]; // break; // } // adj = 1f + (yy - (yLim + 1) * 0.5f) / 1024f; // cwf = BasicTools.Clamp(cwf * adj, -0.5f, 0.5f); // cmf = BasicTools.Clamp(cmf * adj, -0.5f, 0.5f); // rr = yy // | (cw = (int)((cwf + 0.5f) * cwLim)) << shift1 // | (cm = (int)((cmf + 0.5f) * cmLim)) << shift2; // } //} } }