/// <summary>
    ///  Creates and saves a palette image from the unique colors in another image.
    ///  
    ///  The palette image structure:
    /// 
    ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the third mix color
    ///  |__|__|__|__|__|__|__|__ 
    ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the second mix color
    ///  |__|__|__|__|__|__|__|__ 
    ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the first mix color
    ///  |__|__|__|__|__|__|__|__ 
    /// 
    ///  Each horizontal square has a fixed Red component: 0/15 to 15/15.
    ///  The blue component increases from 0 to 1 horizontally over a square.
    ///  The green component increases from 0 to 1 vertically over a square.
    /// 
    ///  The palette image is used in the shaders to convert a truecolor to several dithered colors.
    ///  The truecolor RGB components points to N colors in the palette, one color per row of squares. 
    ///  The N colors are mixed together in a dithering pattern to produce a close approximation of the original truecolor.
    ///  
    ///  The steps to create the palette image:
    /// 
    ///	 1. Load the color image to a Texture2D
    ///	 2. Create a list of all the unique colors in the color image
    ///	 3. Create the palette image
    ///	 4. a) Loop through each pixel in the palette image and determine the truecolor for that pixel
    ///		b) Device a mixing plan to achieve the truecolor
    ///		c) Save the N colors in the square column
    ///  5. Save the palette image
    /// </summary>
    private void CreatePalette()
    {
        if (script.MixedColorCount < 1) return;

        // Load the color image to a Texture2D
        Texture2D colorTexture = LoadTexture();
        if (colorTexture == null) return;

        // Create a list of all the unique colors in the color image
        List<Color> paletteColors = new List<Color>();
        bool proceed = false;
        for (int x = 0; x < colorTexture.width; x++)
            for (int y = 0; y < colorTexture.height; y++)
                if (!paletteColors.Contains(colorTexture.GetPixel(x, y))) {
                    paletteColors.Add(colorTexture.GetPixel(x, y));
                    if (paletteColors.Count > MaxColors && !proceed) {
                        proceed = EditorUtility.DisplayDialog("Error", "Source image contains more than " + MaxColors + " colors. Continuing may lock up Unity for a long time", "Continue", "Stop");
                        if (!proceed)
                            return;
                    }
                }

        uint[] palette = new uint[paletteColors.Count];
        for (int i = 0; i < paletteColors.Count; i++)
            palette[i] = ColorToInt(paletteColors[i]);
        MixingPlanner mixingPlanner = new MixingPlanner(palette);

        // Create the palette image
        int height = (int)Math.Pow(2, Math.Ceiling(Math.Log(ColorSquares * script.MixedColorCount - 1) / Math.Log(2)));
        Texture2D paletteTexture = new Texture2D(ColorSquares * ColorSquares, height, TextureFormat.RGB24, false);
        paletteTexture.name = colorTexture.name + "_pal_" + script.MixedColorCount;

        // Loop through each pixel in the palette image and determine the target color for that pixel
        for (int x = 0; x < ColorSquares * ColorSquares; x++)
            for (int y = 0; y < ColorSquares; y++) {
                byte r = (byte)((float)(x / ColorSquares) / (ColorSquares - 1) * 255);
                byte g = (byte)((float)y / (ColorSquares - 1) * 255);
                byte b = (byte)(((float)x % ColorSquares) / (ColorSquares - 1) * 255);
                uint targetColor = (uint)((r << 16) + (g << 8) + b);

                // Device a mixing plan to achieve the truecolor
                uint[] mixingPlan = mixingPlanner.DeviseBestMixingPlan(targetColor, (uint)script.MixedColorCount);

                // Save the N colors in the square column
                for (int c = 0; c < script.MixedColorCount; c++)
                    paletteTexture.SetPixel(x, y + (script.MixedColorCount - c - 1) * ColorSquares, paletteColors[(int)mixingPlan[c]]);
            }

        // Save the palette image
        SaveTexture(paletteTexture);
    }
Example #2
0
        /* PALETTE GENERATION */
        #region Palette generation

        /// <summary>
        ///  Creates and saves a palette image from the unique colors in another image.
        ///
        ///  The palette image structure:
        ///
        ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the third mix color
        ///  |__|__|__|__|__|__|__|__
        ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the second mix color
        ///  |__|__|__|__|__|__|__|__
        ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the first mix color
        ///  |__|__|__|__|__|__|__|__
        ///
        ///  Each horizontal square has a fixed Red component: 0/15 to 15/15.
        ///  The blue component increases from 0 to 1 horizontally over a square.
        ///  The green component increases from 0 to 1 vertically over a square.
        ///
        ///  The palette image is used in the shaders to convert a truecolor to several dithered colors.
        ///  The truecolor RGB components points to N colors in the palette, one color per row of squares.
        ///  The N colors are mixed together in a dithering pattern to produce a close approximation of the original truecolor.
        ///
        ///  The steps to create the palette image:
        ///
        ///	 1. Load the color image to a Texture2D
        ///	 2. Create a list of all the unique colors in the color image
        ///	 3. Create the palette image
        ///	 4. a) Loop through each pixel in the palette image and determine the truecolor for that pixel
        ///		b) Device a mixing plan to achieve the truecolor
        ///		c) Save the N colors in the square column
        ///  5. Save the palette image
        /// </summary>
        private void GeneratePaletteTexture(Palette palette)
        {
            if (palette.Colors.Count == 0)
            {
                Debug.LogError(ContentText.emptyColorListError);
                return;
            }

            uint[]        paletteColors = ConvertColorListToPaletteList(palette.Colors);
            MixingPlanner mixingPlanner = new MixingPlanner(paletteColors);

            // Create the palette image
            int height = (int)Math.Pow(2, Math.Ceiling(Math.Log(_colorSquares * CurrentPalette.MixedColorCount - 1) / Math.Log(2)));

            if (palette.Texture == null)
            {
                palette.Texture            = new Texture2D(_colorSquares * _colorSquares, height, TextureFormat.RGB24, false);
                palette.Texture.name       = "Palette Texture";
                palette.Texture.filterMode = FilterMode.Point;
                palette.Texture.wrapMode   = TextureWrapMode.Repeat;

                AssetDatabase.AddObjectToAsset(palette.Texture, palette);
                AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(palette.Texture));
            }
            else if (palette.Texture.height != height)
            {
                palette.Texture.Resize(_colorSquares * _colorSquares, height);
            }

            // Fill empty rows with magenta
            int x = 0, y = 0;

            for (int i = 0; i < palette.Texture.height * palette.Texture.width; i++)
            {
                x = i / palette.Texture.height;
                y = i % palette.Texture.width;
                palette.Texture.SetPixel(x, y, Color.magenta);
            }

            // Loop through each pixel in the palette image and determine the target color for that pixel
            for (x = 0; x < _colorSquares * _colorSquares; x++)
            {
                for (y = 0; y < _colorSquares; y++)
                {
                    byte r           = (byte)((float)(x / _colorSquares) / (_colorSquares - 1) * 255);
                    byte g           = (byte)((float)y / (_colorSquares - 1) * 255);
                    byte b           = (byte)(((float)x % _colorSquares) / (_colorSquares - 1) * 255);
                    uint targetColor = (uint)((r << 16) + (g << 8) + b);

                    // Device a mixing plan to achieve the truecolor
                    uint[] mixingPlan = mixingPlanner.DeviseBestMixingPlan(targetColor, (uint)CurrentPalette.MixedColorCount);

                    // Save the N colors in the square column
                    for (int c = 0; c < CurrentPalette.MixedColorCount; c++)
                    {
                        palette.Texture.SetPixel(x, y + (CurrentPalette.MixedColorCount - c - 1) * _colorSquares, palette.Colors[(int)mixingPlan[c]]);
                    }
                }
            }

            palette.Texture.Apply();
            palette.HasTexture = true;

            // Save the palette image
            //		SaveTexture(texture);
        }
Example #3
0
    /// <summary>
    ///  Creates and saves a palette image from the unique colors in another image.
    ///
    ///  The palette image structure:
    ///
    ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the third mix color
    ///  |__|__|__|__|__|__|__|__
    ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the second mix color
    ///  |__|__|__|__|__|__|__|__
    ///  |  |  |  |  |  |  |  |    row of 16 16x16 squares with the first mix color
    ///  |__|__|__|__|__|__|__|__
    ///
    ///  Each horizontal square has a fixed Red component: 0/15 to 15/15.
    ///  The blue component increases from 0 to 1 horizontally over a square.
    ///  The green component increases from 0 to 1 vertically over a square.
    ///
    ///  The palette image is used in the shaders to convert a truecolor to several dithered colors.
    ///  The truecolor RGB components points to N colors in the palette, one color per row of squares.
    ///  The N colors are mixed together in a dithering pattern to produce a close approximation of the original truecolor.
    ///
    ///  The steps to create the palette image:
    ///
    ///	 1. Load the color image to a Texture2D
    ///	 2. Create a list of all the unique colors in the color image
    ///	 3. Create the palette image
    ///	 4. a) Loop through each pixel in the palette image and determine the truecolor for that pixel
    ///		b) Device a mixing plan to achieve the truecolor
    ///		c) Save the N colors in the square column
    ///  5. Save the palette image
    /// </summary>
    private void CreatePalette()
    {
        // Load the color image to a Texture2D
        Texture2D colorTexture = LoadTexture();

        if (colorTexture == null)
        {
            return;
        }

        // Create a list of all the unique colors in the color image
        List <Color> paletteColors = new List <Color>();

        for (int x = 0; x < colorTexture.width; x++)
        {
            for (int y = 0; y < colorTexture.height; y++)
            {
                if (!paletteColors.Contains(colorTexture.GetPixel(x, y)))
                {
                    paletteColors.Add(colorTexture.GetPixel(x, y));
                }
            }
        }

        uint[] palette = new uint[paletteColors.Count];
        for (int i = 0; i < paletteColors.Count; i++)
        {
            palette[i] = ColorToInt(paletteColors[i]);
        }
        MixingPlanner mixingPlanner = new MixingPlanner(palette);

        // Create the palette image
        int       height         = (int)Math.Pow(2, Math.Ceiling(Math.Log(ColorSquares * script.MixedColorCount - 1) / Math.Log(2)));
        Texture2D paletteTexture = new Texture2D(ColorSquares * ColorSquares, height, TextureFormat.RGB24, false);

        paletteTexture.name = colorTexture.name + "_pal_" + script.MixedColorCount;

        // Loop through each pixel in the palette image and determine the target color for that pixel
        for (int x = 0; x < ColorSquares * ColorSquares; x++)
        {
            for (int y = 0; y < ColorSquares; y++)
            {
                byte r           = (byte)((float)(x / ColorSquares) / (ColorSquares - 1) * 255);
                byte g           = (byte)((float)y / (ColorSquares - 1) * 255);
                byte b           = (byte)(((float)x % ColorSquares) / (ColorSquares - 1) * 255);
                uint targetColor = (uint)((r << 16) + (g << 8) + b);

                // Device a mixing plan to achieve the truecolor
                uint[] mixingPlan = mixingPlanner.DeviseBestMixingPlan(targetColor, (uint)script.MixedColorCount);

                // Save the N colors in the square column
                for (int c = 0; c < script.MixedColorCount; c++)
                {
                    paletteTexture.SetPixel(x, y + (script.MixedColorCount - c - 1) * ColorSquares, paletteColors[(int)mixingPlan[c]]);
                }
            }
        }

        // Save the palette image
        SaveTexture(paletteTexture);
    }