/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: AlphaBlender.java
 *
 * Copyright (c) 2006, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.user.redisplay;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

/**
 * Class to perform alpha blending for LayerDrawing.
 */
class AlphaBlender {

    private Color background;
    private int[] opaqueData;

    /** Creates a new instance of AlphaBlender */
    public AlphaBlender() {
    }
    private static final int SCALE_SH = 8;
    private static final int SCALE = 1 << SCALE_SH;
    private AlphaBlendGroup[] groups;
    private int[][] layerBits;
//    private int m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20, m21, m22, m23, m24, m25, m26, m27, m28, m29, m30, m31;
    private int r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31;
    private int g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11, g12, g13, g14, g15, g16, g17, g18, g19, g20, g21, g22, g23, g24, g25, g26, g27, g28, g29, g30, g31;
    private int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31;

    void init(Color background, ArrayList<AbstractDrawing.LayerColor> colors, ArrayList<int[]> bits) {
        this.background = background;
        this.layerBits = bits.toArray(new int[bits.size()][]);

        groups = new AlphaBlendGroup[bits.size() / 13 + 1];
        int k = 0;
        for (int i = 0; i < groups.length; i++) {
            int l = (bits.size() - k) / (groups.length - i);
            groups[i] = new AlphaBlendGroup(this.layerBits, colors, k, l, i == 0);
            k += l;
        }
    }

//    private void unpackBytes(int index) {
//        // unpack pixels
//        int pixel0 = 0, pixel1 = 0, pixel2 = 0, pixel3 = 0, pixel4 = 0, pixel5 = 0, pixel6 = 0, pixel7 = 0;
//        int pixel8 = 0, pixel9 = 0, pixel10 = 0, pixel11 = 0, pixel12 = 0, pixel13 = 0, pixel14 = 0, pixel15 = 0;
//        int pixel16 = 0, pixel17 = 0, pixel18 = 0, pixel19 = 0, pixel20 = 0, pixel21 = 0, pixel22 = 0, pixel23 = 0;
//        int pixel24 = 0, pixel25 = 0, pixel26 = 0, pixel27 = 0, pixel28 = 0, pixel29 = 0, pixel30 = 0, pixel31 = 0;
//        for (int i = 0; i < layerBits.length; i++) {
//            int value = layerBits[i][index];
//            if (value == 0) continue;
//            pixel0 |= (value & 1) << i;
//            pixel1 |= ((value >> 1) & 1) << i;
//            pixel2 |= ((value >> 2) & 1) << i;
//            pixel3 |= ((value >> 3) & 1) << i;
//            pixel4 |= ((value >> 4) & 1) << i;
//            pixel5 |= ((value >> 5) & 1) << i;
//            pixel6 |= ((value >> 6) & 1) << i;
//            pixel7 |= ((value >> 7) & 1) << i;
//            pixel8 |= ((value >> 8) & 1) << i;
//            pixel9 |= ((value >> 9) & 1) << i;
//            pixel10 |= ((value >> 10) & 1) << i;
//            pixel11 |= ((value >> 11) & 1) << i;
//            pixel12 |= ((value >> 12) & 1) << i;
//            pixel13 |= ((value >> 13) & 1) << i;
//            pixel14 |= ((value >> 14) & 1) << i;
//            pixel15 |= ((value >> 15) & 1) << i;
//            pixel16 |= ((value >> 16) & 1) << i;
//            pixel17 |= ((value >> 17) & 1) << i;
//            pixel18 |= ((value >> 18) & 1) << i;
//            pixel19 |= ((value >> 19) & 1) << i;
//            pixel20 |= ((value >> 20) & 1) << i;
//            pixel21 |= ((value >> 21) & 1) << i;
//            pixel22 |= ((value >> 22) & 1) << i;
//            pixel23 |= ((value >> 23) & 1) << i;
//            pixel24 |= ((value >> 24) & 1) << i;
//            pixel25 |= ((value >> 25) & 1) << i;
//            pixel26 |= ((value >> 26) & 1) << i;
//            pixel27 |= ((value >> 27) & 1) << i;
//            pixel28 |= ((value >> 28) & 1) << i;
//            pixel29 |= ((value >> 29) & 1) << i;
//            pixel30 |= ((value >> 30) & 1) << i;
//            pixel31 |= ((value >> 31) & 1) << i;
//        }
//        m0 = pixel0;
//        m1 = pixel1;
//        m2 = pixel2;
//        m3 = pixel3;
//        m4 = pixel4;
//        m5 = pixel5;
//        m6 = pixel6;
//        m7 = pixel7;
//        m8 = pixel8;
//        m9 = pixel9;
//        m10 = pixel10;
//        m11 = pixel11;
//        m12 = pixel12;
//        m13 = pixel13;
//        m14 = pixel14;
//        m15 = pixel15;
//        m16 = pixel16;
//        m17 = pixel17;
//        m18 = pixel18;
//        m19 = pixel19;
//        m20 = pixel20;
//        m21 = pixel21;
//        m22 = pixel22;
//        m23 = pixel23;
//        m24 = pixel24;
//        m25 = pixel25;
//        m26 = pixel26;
//        m27 = pixel27;
//        m28 = pixel28;
//        m29 = pixel29;
//        m30 = pixel30;
//        m31 = pixel31;
//    }
    void composeLine(int inputOffset, int minX, int maxX, int[] opaqueData, int opaqueOffset) {
        int minInt = minX >> 5;
        int maxInt = maxX >> 5;
        this.opaqueData = opaqueData;
        if (minInt == maxInt) {
            long mask = (1L << ((maxX & 31) + 1)) - (1L << (minX & 31));
            composeBits(inputOffset + minInt, (int)mask, opaqueOffset + (minInt << 5));
            return;
        }
        if ((minX & 31) != 0) {
            int headMask = -(1 << (minX & 31));
            composeBits(inputOffset + minInt, headMask, opaqueOffset + (minInt << 5));
            minInt++;
        }
        if ((maxX & 31) != 31) {
            int tailMask = (1 << ((maxX & 31) + 1)) - 1;
            composeBits(inputOffset + maxInt, tailMask, opaqueOffset + (maxInt << 5));
            maxInt--;
        }
        opaqueOffset += minInt << 5;
        for (int index = minInt; index <= maxInt; index++) {
            for (AlphaBlendGroup group : groups) {
                group.unpackBytes(inputOffset + index);
            }
            opaqueOffset = storeRGB32(opaqueOffset);
        }
    }

    void composeBits(int inputOffset, int mask, int outputOffset) {
        for (AlphaBlendGroup group : groups) {
            group.unpackBytes(inputOffset);
        }
        if ((mask & (1 << 0)) != 0) {
            storeRGB(outputOffset + 0, r0, g0, b0);
        }
        if ((mask & (1 << 1)) != 0) {
            storeRGB(outputOffset + 1, r1, g1, b1);
        }
        if ((mask & (1 << 2)) != 0) {
            storeRGB(outputOffset + 2, r2, g2, b2);
        }
        if ((mask & (1 << 3)) != 0) {
            storeRGB(outputOffset + 3, r3, g3, b3);
        }
        if ((mask & (1 << 4)) != 0) {
            storeRGB(outputOffset + 4, r4, g4, b4);
        }
        if ((mask & (1 << 5)) != 0) {
            storeRGB(outputOffset + 5, r5, g5, b5);
        }
        if ((mask & (1 << 6)) != 0) {
            storeRGB(outputOffset + 6, r6, g6, b6);
        }
        if ((mask & (1 << 7)) != 0) {
            storeRGB(outputOffset + 7, r7, g7, b7);
        }
        if ((mask & (1 << 8)) != 0) {
            storeRGB(outputOffset + 8, r8, g8, b8);
        }
        if ((mask & (1 << 9)) != 0) {
            storeRGB(outputOffset + 9, r9, g9, b9);
        }
        if ((mask & (1 << 10)) != 0) {
            storeRGB(outputOffset + 10, r10, g10, b10);
        }
        if ((mask & (1 << 11)) != 0) {
            storeRGB(outputOffset + 11, r11, g11, b11);
        }
        if ((mask & (1 << 12)) != 0) {
            storeRGB(outputOffset + 12, r12, g12, b12);
        }
        if ((mask & (1 << 13)) != 0) {
            storeRGB(outputOffset + 13, r13, g13, b13);
        }
        if ((mask & (1 << 14)) != 0) {
            storeRGB(outputOffset + 14, r14, g14, b14);
        }
        if ((mask & (1 << 15)) != 0) {
            storeRGB(outputOffset + 15, r15, g15, b15);
        }
        if ((mask & (1 << 16)) != 0) {
            storeRGB(outputOffset + 16, r16, g16, b16);
        }
        if ((mask & (1 << 17)) != 0) {
            storeRGB(outputOffset + 17, r17, g17, b17);
        }
        if ((mask & (1 << 18)) != 0) {
            storeRGB(outputOffset + 18, r18, g18, b18);
        }
        if ((mask & (1 << 19)) != 0) {
            storeRGB(outputOffset + 19, r19, g19, b19);
        }
        if ((mask & (1 << 20)) != 0) {
            storeRGB(outputOffset + 20, r20, g20, b20);
        }
        if ((mask & (1 << 21)) != 0) {
            storeRGB(outputOffset + 21, r21, g21, b21);
        }
        if ((mask & (1 << 22)) != 0) {
            storeRGB(outputOffset + 22, r22, g22, b22);
        }
        if ((mask & (1 << 23)) != 0) {
            storeRGB(outputOffset + 23, r23, g23, b23);
        }
        if ((mask & (1 << 24)) != 0) {
            storeRGB(outputOffset + 24, r24, g24, b24);
        }
        if ((mask & (1 << 25)) != 0) {
            storeRGB(outputOffset + 25, r25, g25, b25);
        }
        if ((mask & (1 << 26)) != 0) {
            storeRGB(outputOffset + 26, r26, g26, b26);
        }
        if ((mask & (1 << 27)) != 0) {
            storeRGB(outputOffset + 27, r27, g27, b27);
        }
        if ((mask & (1 << 28)) != 0) {
            storeRGB(outputOffset + 28, r28, g28, b28);
        }
        if ((mask & (1 << 29)) != 0) {
            storeRGB(outputOffset + 29, r29, g29, b29);
        }
        if ((mask & (1 << 30)) != 0) {
            storeRGB(outputOffset + 30, r30, g30, b30);
        }
        if ((mask & (1 << 31)) != 0) {
            storeRGB(outputOffset + 31, r31, g31, b31);
        }
    }

//    private int storeRGB32(int baseIndex) {
//        storeRGB_(baseIndex++, m0);
//        storeRGB_(baseIndex++, m1);
//        storeRGB_(baseIndex++, m2);
//        storeRGB_(baseIndex++, m3);
//        storeRGB_(baseIndex++, m4);
//        storeRGB_(baseIndex++, m5);
//        storeRGB_(baseIndex++, m6);
//        storeRGB_(baseIndex++, m7);
//        storeRGB_(baseIndex++, m8);
//        storeRGB_(baseIndex++, m9);
//        storeRGB_(baseIndex++, m10);
//        storeRGB_(baseIndex++, m11);
//        storeRGB_(baseIndex++, m12);
//        storeRGB_(baseIndex++, m13);
//        storeRGB_(baseIndex++, m14);
//        storeRGB_(baseIndex++, m15);
//        storeRGB_(baseIndex++, m16);
//        storeRGB_(baseIndex++, m17);
//        storeRGB_(baseIndex++, m18);
//        storeRGB_(baseIndex++, m19);
//        storeRGB_(baseIndex++, m20);
//        storeRGB_(baseIndex++, m21);
//        storeRGB_(baseIndex++, m22);
//        storeRGB_(baseIndex++, m23);
//        storeRGB_(baseIndex++, m24);
//        storeRGB_(baseIndex++, m25);
//        storeRGB_(baseIndex++, m26);
//        storeRGB_(baseIndex++, m27);
//        storeRGB_(baseIndex++, m28);
//        storeRGB_(baseIndex++, m29);
//        storeRGB_(baseIndex++, m30);
//        storeRGB_(baseIndex++, m31);
//        return baseIndex;
//    }
    private int storeRGB32(int baseIndex) {
        storeRGB(baseIndex++, r0, g0, b0);
        storeRGB(baseIndex++, r1, g1, b1);
        storeRGB(baseIndex++, r2, g2, b2);
        storeRGB(baseIndex++, r3, g3, b3);
        storeRGB(baseIndex++, r4, g4, b4);
        storeRGB(baseIndex++, r5, g5, b5);
        storeRGB(baseIndex++, r6, g6, b6);
        storeRGB(baseIndex++, r7, g7, b7);
        storeRGB(baseIndex++, r8, g8, b8);
        storeRGB(baseIndex++, r9, g9, b9);
        storeRGB(baseIndex++, r10, g10, b10);
        storeRGB(baseIndex++, r11, g11, b11);
        storeRGB(baseIndex++, r12, g12, b12);
        storeRGB(baseIndex++, r13, g13, b13);
        storeRGB(baseIndex++, r14, g14, b14);
        storeRGB(baseIndex++, r15, g15, b15);
        storeRGB(baseIndex++, r16, g16, b16);
        storeRGB(baseIndex++, r17, g17, b17);
        storeRGB(baseIndex++, r18, g18, b18);
        storeRGB(baseIndex++, r19, g19, b19);
        storeRGB(baseIndex++, r20, g20, b20);
        storeRGB(baseIndex++, r21, g21, b21);
        storeRGB(baseIndex++, r22, g22, b22);
        storeRGB(baseIndex++, r23, g23, b23);
        storeRGB(baseIndex++, r24, g24, b24);
        storeRGB(baseIndex++, r25, g25, b25);
        storeRGB(baseIndex++, r26, g26, b26);
        storeRGB(baseIndex++, r27, g27, b27);
        storeRGB(baseIndex++, r28, g28, b28);
        storeRGB(baseIndex++, r29, g29, b29);
        storeRGB(baseIndex++, r30, g30, b30);
        storeRGB(baseIndex++, r31, g31, b31);
        return baseIndex;
    }

//     private void storeRGB_(int baseIndex, int m) {
//        int r = 0, g = 0, b = 0;
//        for (int i = 0; i < groups.length; i++) {
//            AlphaBlendGroup group = groups[i];
//            int bits = (m >> group.groupShift) & group.groupMask;
//            int red = group.redMap[bits];
//            int green = group.greenMap[bits];
//            int blue = group.blueMap[bits];
//            int ia = group.inverseAlphaMap[bits];
//            if (ia == 0) {
//                r = red >> SCALE_SH;
//                g = green >> SCALE_SH;
//                b = blue >> SCALE_SH;
//            } else if (ia != SCALE) {
//                r = (red + r * ia) >> SCALE_SH;
//                g = (green + g * ia) >> SCALE_SH;
//                b = (blue + b * ia) >> SCALE_SH;
//            }
//        }
//        assert 0 <= r && r <= 255;
//        assert 0 <= g && g <= 255;
//        assert 0 <= b && b <= 255;
//        int color = (r << 16) | (g << 8) + b;
//        opaqueData[baseIndex] = color;
//    }
    private void storeRGB(int baseIndex, int red, int green, int blue) {
        int color;
        if (((red | green | blue) & ~0xFF) == 0) {
            color = (red << 16) | (green << 8) | blue;
        } else {
            color = normalizeRgbDim(red, green, blue);
        }
        opaqueData[baseIndex] = color;
    }

//    private int normalizeRgbHighlight(int red, int green, int blue) {
//        return 0xFFFFFF;
//    }
//
//    private int normalizeRgbClip(int red, int green, int blue) {
//        red = Math.max(0, Math.min(0xFF, red));
//        green = Math.max(0, Math.min(0xFF, red));
//        blue = Math.max(0, Math.min(0xFF, red));
//        return (red << 16) | (green << 8) | blue;
//    }
    private int normalizeRgbDim(int red, int green, int blue) {
        int min, max;
        if (red <= green) {
            min = red;
            max = green;
        } else {
            min = green;
            max = red;
        }
        if (blue > max) {
            max = blue;
        }
        if (blue < min) {
            min = blue;
        }

        if (max - min <= 255) {
            int dec = min < 0 ? min : max - 255;
            red -= dec;
            green -= dec;
            blue -= dec;
        } else {
            int dec = max - 255;
            red = Math.max(0, red - dec);
            green = Math.max(0, green - dec);
            blue = Math.max(0, blue - dec);
        }
        return (red << 16) | (green << 8) | blue;
    }

    //********************************************************************
    private class AlphaBlendGroup {

//        int groupShift;
//        int groupMask;
        int[] redMap;
        int[] greenMap;
        int[] blueMap;
        int[] inverseAlphaMap;
        int[][] bits;

        AlphaBlendGroup(int[][] bits, List<AbstractDrawing.LayerColor> cols, int offset, int len, boolean fillBackround) {
//            groupShift = offset;
//            groupMask = (1 << len) - 1;
            int mapLen = 1 << len;
            redMap = new int[mapLen];
            greenMap = new int[mapLen];
            blueMap = new int[mapLen];
            inverseAlphaMap = new int[mapLen];
            this.bits = new int[len][];

            for (int i = 0; i < len; i++) {
                this.bits[i] = bits[offset + i];
            }

            float[] backgroundComps = background.getRGBColorComponents(null);
            float bRed = backgroundComps[0];
            float bGreen = backgroundComps[1];
            float bBlue = backgroundComps[2];
            for (int k = 0; k < mapLen; k++) {
                double red = 0, green = 0, blue = 0, ia = 1.0;
                if (fillBackround) {
                    red = bRed;
                    green = bGreen;
                    blue = bBlue;
                    ia = 0.0;
                }
                for (int i = 0; i < len; i++) {
                    if ((k & (1 << i)) == 0) {
                        continue;
                    }
                    AbstractDrawing.LayerColor lc = cols.get(offset + i);
                    double iAlpha = lc.inverseAlpha;
                    red *= iAlpha;
                    green *= iAlpha;
                    blue *= iAlpha;
                    ia *= iAlpha;
                    red += lc.premultipliedRed;
                    green += lc.premultipliedGreen;
                    blue += lc.premultipliedBlue;
                }
                redMap[k] = (int) (red * SCALE * 255);
                greenMap[k] = (int) (green * SCALE * 255);
                blueMap[k] = (int) (blue * SCALE * 255);
                inverseAlphaMap[k] = (int) (ia * SCALE);
            }
        }

        private void unpackBytes(int index) {
            // unpack pixels
            int pixel0 = 0, pixel1 = 0, pixel2 = 0, pixel3 = 0, pixel4 = 0, pixel5 = 0, pixel6 = 0, pixel7 = 0;
            int pixel8 = 0, pixel9 = 0, pixel10 = 0, pixel11 = 0, pixel12 = 0, pixel13 = 0, pixel14 = 0, pixel15 = 0;
            int pixel16 = 0, pixel17 = 0, pixel18 = 0, pixel19 = 0, pixel20 = 0, pixel21 = 0, pixel22 = 0, pixel23 = 0;
            int pixel24 = 0, pixel25 = 0, pixel26 = 0, pixel27 = 0, pixel28 = 0, pixel29 = 0, pixel30 = 0, pixel31 = 0;
            for (int i = 0; i < bits.length; i++) {
                int value = bits[i][index];
                if (value == 0) {
                    continue;
                }
                pixel0 |= (value & 1) << i;
                pixel1 |= ((value >> 1) & 1) << i;
                pixel2 |= ((value >> 2) & 1) << i;
                pixel3 |= ((value >> 3) & 1) << i;
                pixel4 |= ((value >> 4) & 1) << i;
                pixel5 |= ((value >> 5) & 1) << i;
                pixel6 |= ((value >> 6) & 1) << i;
                pixel7 |= ((value >> 7) & 1) << i;
                pixel8 |= ((value >> 8) & 1) << i;
                pixel9 |= ((value >> 9) & 1) << i;
                pixel10 |= ((value >> 10) & 1) << i;
                pixel11 |= ((value >> 11) & 1) << i;
                pixel12 |= ((value >> 12) & 1) << i;
                pixel13 |= ((value >> 13) & 1) << i;
                pixel14 |= ((value >> 14) & 1) << i;
                pixel15 |= ((value >> 15) & 1) << i;
                pixel16 |= ((value >> 16) & 1) << i;
                pixel17 |= ((value >> 17) & 1) << i;
                pixel18 |= ((value >> 18) & 1) << i;
                pixel19 |= ((value >> 19) & 1) << i;
                pixel20 |= ((value >> 20) & 1) << i;
                pixel21 |= ((value >> 21) & 1) << i;
                pixel22 |= ((value >> 22) & 1) << i;
                pixel23 |= ((value >> 23) & 1) << i;
                pixel24 |= ((value >> 24) & 1) << i;
                pixel25 |= ((value >> 25) & 1) << i;
                pixel26 |= ((value >> 26) & 1) << i;
                pixel27 |= ((value >> 27) & 1) << i;
                pixel28 |= ((value >> 28) & 1) << i;
                pixel29 |= ((value >> 29) & 1) << i;
                pixel30 |= ((value >> 30) & 1) << i;
                pixel31 |= ((value >> 31) & 1) << i;
            }

            //
            int red, green, blue, ia;

            red = redMap[pixel0];
            green = greenMap[pixel0];
            blue = blueMap[pixel0];
            ia = inverseAlphaMap[pixel0];
            if (ia == 0) {
                r0 = red >> SCALE_SH;
                g0 = green >> SCALE_SH;
                b0 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r0 = (red + r0 * ia) >> SCALE_SH;
                g0 = (green + g0 * ia) >> SCALE_SH;
                b0 = (blue + b0 * ia) >> SCALE_SH;
            }

            red = redMap[pixel1];
            green = greenMap[pixel1];
            blue = blueMap[pixel1];
            ia = inverseAlphaMap[pixel1];
            if (ia == 0) {
                r1 = red >> SCALE_SH;
                g1 = green >> SCALE_SH;
                b1 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r1 = (red + r1 * ia) >> SCALE_SH;
                g1 = (green + g1 * ia) >> SCALE_SH;
                b1 = (blue + b1 * ia) >> SCALE_SH;
            }

            red = redMap[pixel2];
            green = greenMap[pixel2];
            blue = blueMap[pixel2];
            ia = inverseAlphaMap[pixel2];
            if (ia == 0) {
                r2 = red >> SCALE_SH;
                g2 = green >> SCALE_SH;
                b2 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r2 = (red + r2 * ia) >> SCALE_SH;
                g2 = (green + g2 * ia) >> SCALE_SH;
                b2 = (blue + b2 * ia) >> SCALE_SH;
            }

            red = redMap[pixel3];
            green = greenMap[pixel3];
            blue = blueMap[pixel3];
            ia = inverseAlphaMap[pixel3];
            if (ia == 0) {
                r3 = red >> SCALE_SH;
                g3 = green >> SCALE_SH;
                b3 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r3 = (red + r3 * ia) >> SCALE_SH;
                g3 = (green + g3 * ia) >> SCALE_SH;
                b3 = (blue + b3 * ia) >> SCALE_SH;
            }

            red = redMap[pixel4];
            green = greenMap[pixel4];
            blue = blueMap[pixel4];
            ia = inverseAlphaMap[pixel4];
            if (ia == 0) {
                r4 = red >> SCALE_SH;
                g4 = green >> SCALE_SH;
                b4 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r4 = (red + r4 * ia) >> SCALE_SH;
                g4 = (green + g4 * ia) >> SCALE_SH;
                b4 = (blue + b4 * ia) >> SCALE_SH;
            }

            red = redMap[pixel5];
            green = greenMap[pixel5];
            blue = blueMap[pixel5];
            ia = inverseAlphaMap[pixel5];
            if (ia == 0) {
                r5 = red >> SCALE_SH;
                g5 = green >> SCALE_SH;
                b5 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r5 = (red + r5 * ia) >> SCALE_SH;
                g5 = (green + g5 * ia) >> SCALE_SH;
                b5 = (blue + b5 * ia) >> SCALE_SH;
            }

            red = redMap[pixel6];
            green = greenMap[pixel6];
            blue = blueMap[pixel6];
            ia = inverseAlphaMap[pixel6];
            if (ia == 0) {
                r6 = red >> SCALE_SH;
                g6 = green >> SCALE_SH;
                b6 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r6 = (red + r6 * ia) >> SCALE_SH;
                g6 = (green + g6 * ia) >> SCALE_SH;
                b6 = (blue + b6 * ia) >> SCALE_SH;
            }

            red = redMap[pixel7];
            green = greenMap[pixel7];
            blue = blueMap[pixel7];
            ia = inverseAlphaMap[pixel7];
            if (ia == 0) {
                r7 = red >> SCALE_SH;
                g7 = green >> SCALE_SH;
                b7 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r7 = (red + r7 * ia) >> SCALE_SH;
                g7 = (green + g7 * ia) >> SCALE_SH;
                b7 = (blue + b7 * ia) >> SCALE_SH;
            }

            red = redMap[pixel8];
            green = greenMap[pixel8];
            blue = blueMap[pixel8];
            ia = inverseAlphaMap[pixel8];
            if (ia == 0) {
                r8 = red >> SCALE_SH;
                g8 = green >> SCALE_SH;
                b8 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r8 = (red + r8 * ia) >> SCALE_SH;
                g8 = (green + g8 * ia) >> SCALE_SH;
                b8 = (blue + b8 * ia) >> SCALE_SH;
            }

            red = redMap[pixel9];
            green = greenMap[pixel9];
            blue = blueMap[pixel9];
            ia = inverseAlphaMap[pixel9];
            if (ia == 0) {
                r9 = red >> SCALE_SH;
                g9 = green >> SCALE_SH;
                b9 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r9 = (red + r9 * ia) >> SCALE_SH;
                g9 = (green + g9 * ia) >> SCALE_SH;
                b9 = (blue + b9 * ia) >> SCALE_SH;
            }

            red = redMap[pixel10];
            green = greenMap[pixel10];
            blue = blueMap[pixel10];
            ia = inverseAlphaMap[pixel10];
            if (ia == 0) {
                r10 = red >> SCALE_SH;
                g10 = green >> SCALE_SH;
                b10 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r10 = (red + r10 * ia) >> SCALE_SH;
                g10 = (green + g10 * ia) >> SCALE_SH;
                b10 = (blue + b10 * ia) >> SCALE_SH;
            }

            red = redMap[pixel11];
            green = greenMap[pixel11];
            blue = blueMap[pixel11];
            ia = inverseAlphaMap[pixel11];
            if (ia == 0) {
                r11 = red >> SCALE_SH;
                g11 = green >> SCALE_SH;
                b11 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r11 = (red + r11 * ia) >> SCALE_SH;
                g11 = (green + g11 * ia) >> SCALE_SH;
                b11 = (blue + b11 * ia) >> SCALE_SH;
            }

            red = redMap[pixel12];
            green = greenMap[pixel12];
            blue = blueMap[pixel12];
            ia = inverseAlphaMap[pixel12];
            if (ia == 0) {
                r12 = red >> SCALE_SH;
                g12 = green >> SCALE_SH;
                b12 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r12 = (red + r12 * ia) >> SCALE_SH;
                g12 = (green + g12 * ia) >> SCALE_SH;
                b12 = (blue + b12 * ia) >> SCALE_SH;
            }

            red = redMap[pixel13];
            green = greenMap[pixel13];
            blue = blueMap[pixel13];
            ia = inverseAlphaMap[pixel13];
            if (ia == 0) {
                r13 = red >> SCALE_SH;
                g13 = green >> SCALE_SH;
                b13 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r13 = (red + r13 * ia) >> SCALE_SH;
                g13 = (green + g13 * ia) >> SCALE_SH;
                b13 = (blue + b13 * ia) >> SCALE_SH;
            }

            red = redMap[pixel14];
            green = greenMap[pixel14];
            blue = blueMap[pixel14];
            ia = inverseAlphaMap[pixel14];
            if (ia == 0) {
                r14 = red >> SCALE_SH;
                g14 = green >> SCALE_SH;
                b14 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r14 = (red + r14 * ia) >> SCALE_SH;
                g14 = (green + g14 * ia) >> SCALE_SH;
                b14 = (blue + b14 * ia) >> SCALE_SH;
            }

            red = redMap[pixel15];
            green = greenMap[pixel15];
            blue = blueMap[pixel15];
            ia = inverseAlphaMap[pixel15];
            if (ia == 0) {
                r15 = red >> SCALE_SH;
                g15 = green >> SCALE_SH;
                b15 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r15 = (red + r15 * ia) >> SCALE_SH;
                g15 = (green + g15 * ia) >> SCALE_SH;
                b15 = (blue + b15 * ia) >> SCALE_SH;
            }

            red = redMap[pixel16];
            green = greenMap[pixel16];
            blue = blueMap[pixel16];
            ia = inverseAlphaMap[pixel16];
            if (ia == 0) {
                r16 = red >> SCALE_SH;
                g16 = green >> SCALE_SH;
                b16 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r16 = (red + r16 * ia) >> SCALE_SH;
                g16 = (green + g16 * ia) >> SCALE_SH;
                b16 = (blue + b16 * ia) >> SCALE_SH;
            }

            red = redMap[pixel17];
            green = greenMap[pixel17];
            blue = blueMap[pixel17];
            ia = inverseAlphaMap[pixel17];
            if (ia == 0) {
                r17 = red >> SCALE_SH;
                g17 = green >> SCALE_SH;
                b17 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r17 = (red + r17 * ia) >> SCALE_SH;
                g17 = (green + g17 * ia) >> SCALE_SH;
                b17 = (blue + b17 * ia) >> SCALE_SH;
            }

            red = redMap[pixel18];
            green = greenMap[pixel18];
            blue = blueMap[pixel18];
            ia = inverseAlphaMap[pixel18];
            if (ia == 0) {
                r18 = red >> SCALE_SH;
                g18 = green >> SCALE_SH;
                b18 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r18 = (red + r18 * ia) >> SCALE_SH;
                g18 = (green + g18 * ia) >> SCALE_SH;
                b18 = (blue + b18 * ia) >> SCALE_SH;
            }

            red = redMap[pixel19];
            green = greenMap[pixel19];
            blue = blueMap[pixel19];
            ia = inverseAlphaMap[pixel19];
            if (ia == 0) {
                r19 = red >> SCALE_SH;
                g19 = green >> SCALE_SH;
                b19 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r19 = (red + r19 * ia) >> SCALE_SH;
                g19 = (green + g19 * ia) >> SCALE_SH;
                b19 = (blue + b19 * ia) >> SCALE_SH;
            }

            red = redMap[pixel20];
            green = greenMap[pixel20];
            blue = blueMap[pixel20];
            ia = inverseAlphaMap[pixel20];
            if (ia == 0) {
                r20 = red >> SCALE_SH;
                g20 = green >> SCALE_SH;
                b20 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r20 = (red + r20 * ia) >> SCALE_SH;
                g20 = (green + g20 * ia) >> SCALE_SH;
                b20 = (blue + b20 * ia) >> SCALE_SH;
            }

            red = redMap[pixel21];
            green = greenMap[pixel21];
            blue = blueMap[pixel21];
            ia = inverseAlphaMap[pixel21];
            if (ia == 0) {
                r21 = red >> SCALE_SH;
                g21 = green >> SCALE_SH;
                b21 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r21 = (red + r21 * ia) >> SCALE_SH;
                g21 = (green + g21 * ia) >> SCALE_SH;
                b21 = (blue + b21 * ia) >> SCALE_SH;
            }

            red = redMap[pixel22];
            green = greenMap[pixel22];
            blue = blueMap[pixel22];
            ia = inverseAlphaMap[pixel22];
            if (ia == 0) {
                r22 = red >> SCALE_SH;
                g22 = green >> SCALE_SH;
                b22 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r22 = (red + r22 * ia) >> SCALE_SH;
                g22 = (green + g22 * ia) >> SCALE_SH;
                b22 = (blue + b22 * ia) >> SCALE_SH;
            }

            red = redMap[pixel23];
            green = greenMap[pixel23];
            blue = blueMap[pixel23];
            ia = inverseAlphaMap[pixel23];
            if (ia == 0) {
                r23 = red >> SCALE_SH;
                g23 = green >> SCALE_SH;
                b23 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r23 = (red + r23 * ia) >> SCALE_SH;
                g23 = (green + g23 * ia) >> SCALE_SH;
                b23 = (blue + b23 * ia) >> SCALE_SH;
            }

            red = redMap[pixel24];
            green = greenMap[pixel24];
            blue = blueMap[pixel24];
            ia = inverseAlphaMap[pixel24];
            if (ia == 0) {
                r24 = red >> SCALE_SH;
                g24 = green >> SCALE_SH;
                b24 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r24 = (red + r24 * ia) >> SCALE_SH;
                g24 = (green + g24 * ia) >> SCALE_SH;
                b24 = (blue + b24 * ia) >> SCALE_SH;
            }

            red = redMap[pixel25];
            green = greenMap[pixel25];
            blue = blueMap[pixel25];
            ia = inverseAlphaMap[pixel25];
            if (ia == 0) {
                r25 = red >> SCALE_SH;
                g25 = green >> SCALE_SH;
                b25 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r25 = (red + r25 * ia) >> SCALE_SH;
                g25 = (green + g25 * ia) >> SCALE_SH;
                b25 = (blue + b25 * ia) >> SCALE_SH;
            }

            red = redMap[pixel26];
            green = greenMap[pixel26];
            blue = blueMap[pixel26];
            ia = inverseAlphaMap[pixel26];
            if (ia == 0) {
                r26 = red >> SCALE_SH;
                g26 = green >> SCALE_SH;
                b26 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r26 = (red + r26 * ia) >> SCALE_SH;
                g26 = (green + g26 * ia) >> SCALE_SH;
                b26 = (blue + b26 * ia) >> SCALE_SH;
            }

            red = redMap[pixel27];
            green = greenMap[pixel27];
            blue = blueMap[pixel27];
            ia = inverseAlphaMap[pixel27];
            if (ia == 0) {
                r27 = red >> SCALE_SH;
                g27 = green >> SCALE_SH;
                b27 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r27 = (red + r27 * ia) >> SCALE_SH;
                g27 = (green + g27 * ia) >> SCALE_SH;
                b27 = (blue + b27 * ia) >> SCALE_SH;
            }

            red = redMap[pixel28];
            green = greenMap[pixel28];
            blue = blueMap[pixel28];
            ia = inverseAlphaMap[pixel28];
            if (ia == 0) {
                r28 = red >> SCALE_SH;
                g28 = green >> SCALE_SH;
                b28 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r28 = (red + r28 * ia) >> SCALE_SH;
                g28 = (green + g28 * ia) >> SCALE_SH;
                b28 = (blue + b28 * ia) >> SCALE_SH;
            }

            red = redMap[pixel29];
            green = greenMap[pixel29];
            blue = blueMap[pixel29];
            ia = inverseAlphaMap[pixel29];
            if (ia == 0) {
                r29 = red >> SCALE_SH;
                g29 = green >> SCALE_SH;
                b29 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r29 = (red + r29 * ia) >> SCALE_SH;
                g29 = (green + g29 * ia) >> SCALE_SH;
                b29 = (blue + b29 * ia) >> SCALE_SH;
            }

            red = redMap[pixel30];
            green = greenMap[pixel30];
            blue = blueMap[pixel30];
            ia = inverseAlphaMap[pixel30];
            if (ia == 0) {
                r30 = red >> SCALE_SH;
                g30 = green >> SCALE_SH;
                b30 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r30 = (red + r30 * ia) >> SCALE_SH;
                g30 = (green + g30 * ia) >> SCALE_SH;
                b30 = (blue + b30 * ia) >> SCALE_SH;
            }

            red = redMap[pixel31];
            green = greenMap[pixel31];
            blue = blueMap[pixel31];
            ia = inverseAlphaMap[pixel31];
            if (ia == 0) {
                r31 = red >> SCALE_SH;
                g31 = green >> SCALE_SH;
                b31 = blue >> SCALE_SH;
            } else if (ia != SCALE) {
                r31 = (red + r31 * ia) >> SCALE_SH;
                g31 = (green + g31 * ia) >> SCALE_SH;
                b31 = (blue + b31 * ia) >> SCALE_SH;
            }
        }
    }
}
