/******************************************************************************
 * colour.c - Chapter 6 sample code                                           *
 *                                                                            *
 * To be used with mach64 sample code                                         *
 * This module contains arrays for the first 16 colours for pixel depths      *
 * of 8, 15, 16, 24RGB, 24BGR, 32RGB, and 32BGR.                              *
 * Also included are various primitives dealing with colour organization.     *
 * Please reference defines.h for colour codes.                               *
 *                                                                            *
 * Copyright (c) 1994-1997 ATI Technologies Inc.  All rights reserved.        *
 ******************************************************************************/

#include "defines.h"
#include "main.h"

// Arrays containing colour codes for all pixel depths.

// Colour codes for 4 & 8 bpp modes - palette entry based.

static unsigned long colour_table_8[16] =
{
    0x00000000,                         // Black
    0x00000001,                         // Dark Blue
    0x00000002,                         // Dark Green
    0x00000003,                         // Dark Cyan
    0x00000004,                         // Dark Red
    0x00000005,                         // Dark Magenta
    0x00000006,                         // Brown
    0x00000007,                         // Light Gray
    0x00000008,                         // Dark Gray
    0x00000009,                         // Light Blue
    0x0000000A,                         // Light Green
    0x0000000B,                         // Light Cyan
    0x0000000C,                         // Light Red
    0x0000000D,                         // Light Magenta
    0x0000000E,                         // Yellow
    0x0000000F,                         // White
};

// Colour codes for 15 bpp (16 bpp 555 colour weight) modes - direct mapped.

static unsigned long colour_table_15[16] =
{
    0x00000000,                         // Black
    0x00000014,                         // Dark Blue
    0x00000280,                         // Dark Green
    0x00000294,                         // Dark Cyan
    0x00005000,                         // Dark Red
    0x00005014,                         // Dark Magenta
    0x00005280,                         // Brown
    0x00005294,                         // Light Gray
    0x0000294A,                         // Dark Gray
    0x0000001F,                         // Light Blue
    0x000003E0,                         // Light Green
    0x000003FF,                         // Light Cyan
    0x00007C00,                         // Light Red
    0x00007C1F,                         // Light Magenta
    0x00007FE0,                         // Yellow
    0x0000FFFF                          // White
};

// Colour codes for 16 bpp (16 bpp 565 colour weight) modes - direct mapped.

static unsigned long colour_table_16[16] =
{
    0x00000000,                         // Black
    0x00000014,                         // Dark Blue
    0x000004C0,                         // Dark Green
    0x000004D4,                         // Dark Cyan
    0x0000A000,                         // Dark Red
    0x0000A014,                         // Dark Magenta
    0x0000A4C0,                         // Brown
    0x0000A4D4,                         // Light Gray
    0x0000528A,                         // Dark Gray
    0x0000001F,                         // Light Blue
    0x000007E0,                         // Light Green
    0x000007FF,                         // Light Cyan
    0x0000F800,                         // Light Red
    0x0000F81F,                         // Light Magenta
    0x0000FFE0,                         // Yellow
    0x0000FFFF                          // White
};

// Colour codes for 24 bpp RGB colour weight modes - direct mapped.

static unsigned long colour_table_ARGB[16] =
{
    0x00000000,                         // Black
    0x0000009E,                         // Dark Blue
    0x00009E00,                         // Dark Green
    0x00009E9E,                         // Dark Cyan
    0x009E0000,                         // Dark Red
    0x009E009E,                         // Dark Magenta
    0x009E9E00,                         // Brown
    0x009E9E9E,                         // Light Gray
    0x00555555,                         // Dark Gray
    0x000000FF,                         // Light Blue
    0x0000FF00,                         // Light Green
    0x0000FFFF,                         // Light Cyan
    0x00FF0000,                         // Light Red
    0x00FF00FF,                         // Light Magenta
    0x00FFFF00,                         // Yellow
    0x00FFFFFF                          // White
};

// Colour codes for 24 bpp BGR colour weight modes - direct mapped.

static unsigned long colour_table_ABGR[16] =
{
    0x00000000,                         // Black
    0x009E0000,                         // Dark Blue
    0x00009E00,                         // Dark Green
    0x009E9E00,                         // Dark Cyan
    0x0000009E,                         // Dark Red
    0x009E009E,                         // Dark Magenta
    0x00009E9E,                         // Brown
    0x009E9E9E,                         // Light Gray
    0x00555555,                         // Dark Gray
    0x00FF0000,                         // Light Blue
    0x0000FF00,                         // Light Green
    0x00FFFF00,                         // Light Cyan
    0x000000FF,                         // Light Red
    0x00FF00FF,                         // Light Magenta
    0x0000FFFF,                         // Yellow
    0x00FFFFFF                          // White
};

// Colour codes for 32 bpp RGBA colour weight modes - direct mapped.

static unsigned long colour_table_RGBA[16] =
{
    0x00000000,                         // Black
    0x00009E00,                         // Dark Blue
    0x009E0000,                         // Dark Green
    0x009E9E00,                         // Dark Cyan
    0x9E000000,                         // Dark Red
    0x9E009E00,                         // Dark Magenta
    0x9E9E0000,                         // Brown
    0x9E9E9E00,                         // Light Gray
    0x55555500,                         // Dark Gray
    0x0000FF00,                         // Light Blue
    0x00FF0000,                         // Light Green
    0x00FFFF00,                         // Light Cyan
    0xFF000000,                         // Light Red
    0xFF00FF00,                         // Light Magenta
    0xFFFF0000,                         // Yellow
    0xFFFFFF00                          // White
};

// Colour codes for 32 bpp BGRA colour weight modes - direct mapped.

static unsigned long colour_table_BGRA[16] =
{
    0x00000000,                         // Black
    0x9E000000,                         // Dark Blue
    0x009E0000,                         // Dark Green
    0x9E9E0000,                         // Dark Cyan
    0x00009E00,                         // Dark Red
    0x9E009E00,                         // Dark Magenta
    0x009E9E00,                         // Brown
    0x9E9E9E00,                         // Light Gray
    0x55555500,                         // Dark Gray
    0xFF000000,                         // Light Blue
    0x00FF0000,                         // Light Green
    0xFFFF0000,                         // Light Cyan
    0x0000FF00,                         // Light Red
    0xFF00FF00,                         // Light Magenta
    0x00FFFF00,                         // Yellow
    0xFFFFFF00                          // White
};


/******************************************************************************
 * get_colour_code                                                            *
 *  Function: returns the colour code for the given generic colour            *
 *    Inputs: colour_index - number 0 to 15 representing first 16 VGA colours *
 *   Outputs: colour_code - 32bit hex value indicating the colour code.       *
 ******************************************************************************/

unsigned long get_colour_code (int colour_index)
{
    colour_index %= 16;                 // Ensure index is modulo 16.

    switch (MODE_INFO.bpp)
    {
        case 8:
            return (colour_table_8[colour_index]);

        case 15:
        case 16:
            switch (MODE_INFO.depth)
            {
                case DEPTH_SUPPORT_555:
                    return (colour_table_15[colour_index]);

                case DEPTH_SUPPORT_565:
                    return (colour_table_16[colour_index]);
            } // switch
            break;

        case 24:
            switch (MODE_INFO.depth)
            {
                case DEPTH_SUPPORT_RGB:
                    return (colour_table_ARGB[colour_index]);

                case DEPTH_SUPPORT_BGR:
                    return (colour_table_ABGR[colour_index]);
            } // switch
            break;

        case 32:
            switch (MODE_INFO.depth)
            {
                case DEPTH_SUPPORT_RGBA:
                    return (colour_table_RGBA[colour_index]);

                case DEPTH_SUPPORT_ARGB:
                    return (colour_table_ARGB[colour_index]);

                case DEPTH_SUPPORT_BGRA:
                    return (colour_table_BGRA[colour_index]);

                case DEPTH_SUPPORT_ABGR:
                    return (colour_table_ABGR[colour_index]);
            } // switch
            break;

        default:
            return ((unsigned long) BLACK);
    } // switch
    return (0);
} // get_colour_code


/******************************************************************************
 * get_primary_colour                                                         *
 *  Function: separate the primary colour component from a given colour       *
 *            (i.e. separate the RED, GREEN, or BLUE component value.         *
 *    Inputs: pri_col - RED, GREEN, or BLUE                                   *
 *            colour - colour to be broken down                               *
 *   Outputs: primary - value of pri_col contained within colour.             *
 *     Notes: This function is only useful for non-palettized modes such      *
 *            as 15, 16, 24, and 32 bpp colour depths. If this function       *
 *            is called for 4 or 8 bpp modes, the index value will be         *
 *            returned without modification.                                  *
 ******************************************************************************/

unsigned long get_primary_colour (primarycolour pri_col, unsigned long colour)
{
    unsigned long primary;

    switch (MODE_INFO.bpp)
    {
        case 4:
        case 8:
            primary = colour;
            break;

        case 15:
            switch (pri_col)
            {
                case RED:
                    primary = (colour >> 10) & 0x1F;
                    break;

                case GREEN:
                    primary = (colour >> 5) & 0x1F;
                    break;

                case BLUE:
                    primary = colour & 0x1F;
                    break;
            } // switch
            break;

        case 16:
            switch (pri_col)
            {
                case RED:
                    primary = (colour >> 11) & 0x1F;
                    break;

                case GREEN:
                    primary = (colour >> 5) & 0x3F;
                    break;

                case BLUE:
                    primary = colour & 0x1F;
                    break;
            } // switch
            break;

        case 24:
            switch (pri_col)
            {
                case RED:
                    if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_RGB)
                    {
                        primary = (colour >> 16) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_BGR)
                    {
                        primary = (colour) & 0xFF;
                    } // if
                    break;

                case GREEN:
                    primary = (colour >> 8) & 0xFF;
                    break;

                case BLUE:
                    if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_RGB)
                    {
                        primary = (colour) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_BGR)
                    {
                        primary = (colour >> 16) & 0xFF;
                    } // if
                    break;
            } // switch
            break;

        case 32:
            switch (pri_col)
            {
                case RED:
                    if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_ARGB)
                    {
                        primary = (colour >> 16) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_BGRA)
                    {
                        primary = (colour >> 8) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_RGBA)
                    {
                        primary = (colour >> 24) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_ABGR)
                    {
                        primary = (colour) & 0xFF;
                    } // if
                    break;

                case GREEN:
                    if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_ARGB)
                    {
                        primary = (colour >> 8) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_BGRA)
                    {
                        primary = (colour >> 16) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_RGBA)
                    {
                        primary = (colour >> 16) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_ABGR)
                    {
                        primary = (colour >> 8) & 0xFF;
                    } // if
                    break;

                case BLUE:
                    if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_ARGB)
                    {
                        primary = (colour) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_BGRA)
                    {
                        primary = (colour >> 24) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_RGBA)
                    {
                        primary = (colour >> 8) & 0xFF;
                    }
                    else if (QUERY_DATA.colour_depth_support & DEPTH_SUPPORT_ABGR)
                    {
                        primary = (colour >> 16) & 0xFF;
                    } // if
                    break;
            } // switch
            break;
    } // switch

    return (primary);
} // get_primary_colour


/******************************************************************************
 * get_xy_offset                                                              *
 *  Function: Calculates the byte offset from a given point (x, y)            *
 *    Inputs: x - x coordinate of point                                       *
 *            y - y coordinate of point                                       *
 *   Outputs: offset - offset of point (x,y)                                  *
 ******************************************************************************/

unsigned long get_xy_offset (int x, int y)
{
    unsigned long offset;
    int bpp;

    offset = (unsigned long) y;
    offset = (unsigned long) (offset * MODE_INFO.pitch);
    bpp = MODE_INFO.bpp;
    if (bpp == 15)
    {
        bpp = 16;
    } // if
    offset = (unsigned long) (offset * (bpp / 8));
    offset = (unsigned long) (offset + ((bpp / 8) * x));
    return (offset);
} // get_xy_offset
