/***********************************************************************
 * mach64 Chapter 8 sample code                                        *
 *                                                                     *
 * keyer.c - Program to demonstrate VT/3D RAGE Overlay Keyer.          *
 *                                                                     *
 * Copyright (c) 1994-1998 ATI Technologies Inc.  All rights reserved. *
 ***********************************************************************/

#include <i86.h>
#include <stdio.h>
#include <stdlib.h>
#include "..\util\atim64vt.h"
#include "..\util\definevt.h"
#include "..\util\main.h"

#define TRUE            1
#define FALSE           0

#define KEY_FALSE       0
#define KEY_TRUE        1
#define KEY_NOT_EQUAL   4
#define KEY_EQUAL       5
#define KEYERDELAY      150
#define VT_GT_G_OR_V_MIX      0xB
#define VTB_GTB_G_OR_V_MIX      0
#define GAMMA_OFF       0
#define GAMMA_22        1
#define GAMMA_18        2
#define GAMMA_14        3

int image_width, image_height;
int temp,pattern;
int CLR_MSK_LIMIT=0;
unsigned long int ISVTGT = 0, ISREVB = 0;

/***********************************************************************
 * Main Program to demonstrate VT Overlay Keyer.                       *
 *  Function: demonstrates VT Overlay Keyer                            *
 *    Inputs: Arguments for mode spatial and colour resolution         *
 *   Outputs: NONE                                                     *
 ***********************************************************************/ 
void main (int argc, char *argv[])
{
    int Counter;
    int moveX, moveY;
    int x, y;
    int multiplier;

    printf ("\nmach64 Chapter 8 sample code\n"
            "\n"
            "keyer.c\n"
            "\n"
            "This program is only available in 16bpp pixel depth.\n"
            "Spatial resolution (640, 800, 1024, 1280, 1600) should be passed as\n"
            "an argument. Default setting is 640x480 spatial resolution.\n");

    // Batch command to detect the mach64, perform a hardware query, Save old
    // mode information, process mode info arguments, load and set mode, enable
    // aperture, set up palettes, initialize engine to known state, and reset
    // all engine queues.

    // Cases when program fails to set color depth and/or spatial resolution.
    // Program will terminate immediately and returns user to dos prompt.
    if (!(start (argc, argv)))
    {
        printf("\nPress any key to exit...\n");
        getch();
        finish();
        exit(1);
    }

    //  Detect for VT/GT.  Program will terminate if neither GT nor VT exists.
    ISVTGT = is_vtgt();
    ISREVB = is_revb_or_greater();

    if (!ISVTGT)
    {
        finish();
        printf("\nWarning: Unable to detect a VT or a GT!\n");
        printf("Reminder: This program only works with a VT or a GT!\n");
        exit(1);
    }

    // Make sure we are in 16bpp mode.
    if (MODE_INFO.bpp != 16)
    {
        // Disable accelerator mode and switch back to VGA text mode.
        finish ();
        printf ("OVERLAY requires colour depth of 16 bpp.\n");
        exit (1);
    } // if

    // Run startup overlay procedure.
    start_overlay();
    if(is_pro())
    {
        pro_overlay_init();
    }
    
    // Display image
    keyer("..\\image\\test16.img", SCALE_IN_16BPP);

    // Disable the scaler/overlay.
    finish_overlay();

    // Batch command to restore old mode.
    finish ();

    exit (0);                           // No errors.

} // main


void keyer(char *filename, int img_bpp)
{
    img_handle *ReturnPtr;
    int iReturnValue;

    unsigned long localmask,localmaxmask,mask=0x0;
    unsigned short i;
    int xcurr,ycurr,xdir,ydir;
    int xcount=0;
    int ycount=0;

    clear_screen (0, 0, MODE_INFO.xres, MODE_INFO.yres);

    ReturnPtr = get_img_header("..\\image\\cbars16.img");

    if ( ReturnPtr == NULL)
    {
        finish();
        printf("Program was not able to load the image file header.");
        exit(1);
    }

    image_width = ReturnPtr->image->width;
    image_height = ReturnPtr->image->height;
    
    iReturnValue = load_img(ReturnPtr, 0, 0);
    if (iReturnValue == LOAD_FAILED)
    {
        finish();
        printf("Program was not able to load the image file.");
        exit(1);
    }

    // Deallocate memory to pointer ReturnPtr
    free(ReturnPtr);

    wait_for_fifo (1);
    regw (DP_SRC, MONO_SRC_ONE | FRGD_SRC_BLIT);

    // blit the image as many times as necessary to fill up the screen
    for (ycount=0; ycount<=MODE_INFO.yres; ycount+=image_height)
    {
        for (xcount=0; xcount<=MODE_INFO.xres; xcount+=image_width)
        {
            if ((ycount!=0) || (xcount!=0))
            {
                blit (0, 0, xcount, ycount, image_width, image_height);
            }
        }
    }
    
    ReturnPtr = get_img_header (filename);

    if ( ReturnPtr == NULL)
    {
        finish();
        printf("Program was not able to load the image file header.");
        exit(1);
    }

    iReturnValue = load_img (ReturnPtr, MODE_INFO.xres, MODE_INFO.yres);
    if (iReturnValue == LOAD_FAILED)
    {
        finish();
        printf("Program was not able to load the image file.");
        exit(1);
    }

    // Deallocate memory to pointer ReturnPtr
    free(ReturnPtr);

    // Setup overlay.
    setup_overlay(img_bpp, get_xy_offset(MODE_INFO.xres,MODE_INFO.yres));

    if (ISREVB)
    {
        // Set graphics key compare function.
        regw(OVERLAY_KEY_CNTL, (regr(OVERLAY_KEY_CNTL)) | ((KEY_NOT_EQUAL) << 4));

        // Set video key compare function.
        regw(OVERLAY_KEY_CNTL, (regr(OVERLAY_KEY_CNTL)) | (KEY_NOT_EQUAL));

        // Set overlay mix function.
        regw(OVERLAY_KEY_CNTL, (regr(OVERLAY_KEY_CNTL)) | ((VTB_GTB_G_OR_V_MIX) << 8));

        // Set video/graphics key colour
        regw(OVERLAY_VIDEO_KEY_CLR, 0x00FFFFFF);
        regw(OVERLAY_GRAPHICS_KEY_CLR, 0x00FFFFFF);

        // Set video/graphics key mask
        regw(OVERLAY_VIDEO_KEY_MSK, (mask & 0xFF));
        regw(OVERLAY_GRAPHICS_KEY_MSK, (mask & 0xFF));

        // Set overlay location (upper left corner of display) and mix key.
        set_overlay (0, 0, MODE_INFO.xres-1, MODE_INFO.yres-1);
        if (MODE_INFO.xres>1024)
        {
            set_scale (320, 200, MODE_INFO.xres-1, (MODE_INFO.yres-1)/2);
        }
        else
        {
            set_scale (320, 200, MODE_INFO.xres-1, MODE_INFO.yres-1);
        }

        enable_overlay();

        while (!kbhit())
        {
            //  Apply different gamma correction factor
            pattern = (rand() % 4)+1;
            if (pattern==1)
            {
                regw(OVERLAY_SCALE_CNTL,(regr(OVERLAY_SCALE_CNTL) & (0xFFFFFF9F)) | (GAMMA_OFF<<5));
            }
            if (pattern==2)
            {
                regw(OVERLAY_SCALE_CNTL,(regr(OVERLAY_SCALE_CNTL) & (0xFFFFFF9F)) | (GAMMA_22<<5));
            }
            if (pattern==3)
            {
                regw(OVERLAY_SCALE_CNTL,(regr(OVERLAY_SCALE_CNTL) & (0xFFFFFF9F)) | (GAMMA_18<<5));
            }
            if (pattern==4)
            {
                regw(OVERLAY_SCALE_CNTL,(regr(OVERLAY_SCALE_CNTL) & (0xFFFFFF9F)) | (GAMMA_14<<5));
            }

            mask=0x0;
            for (i=24; i>CLR_MSK_LIMIT; i--)
            {
                localmaxmask = 0xFFFFFF >> (i-1);
                localmaxmask <<= (i-1);
                localmask = 0x1;
                delay(KEYERDELAY);

                // Set video/graphics key mask
                regw(OVERLAY_VIDEO_KEY_MSK, mask+localmask);
                regw(OVERLAY_GRAPHICS_KEY_MSK, mask+localmask);

                while (((mask+localmask) != (localmaxmask)) && (!kbhit()))
                {
                    localmask *=0x2;
                    delay(KEYERDELAY);

                    // Set video/graphics key mask
                    regw(OVERLAY_VIDEO_KEY_MSK, mask+localmask);
                    regw(OVERLAY_GRAPHICS_KEY_MSK, mask+localmask);
                }
                mask+=localmask;
                
            }
            delay(KEYERDELAY);

            // Set video/graphics key mask
            regw(OVERLAY_VIDEO_KEY_MSK, 0x00FFFFFF);
            regw(OVERLAY_GRAPHICS_KEY_MSK, 0x00FFFFFF);
            delay(KEYERDELAY);
        } // while
    }

    else
    {
        // Set graphics key compare function.
        regw(OVERLAY_KEY_CNTL, (regr(OVERLAY_KEY_CNTL)) | ((KEY_FALSE) << 4));

        // Set video key compare function.
        regw(OVERLAY_KEY_CNTL, (regr(OVERLAY_KEY_CNTL)) | (KEY_NOT_EQUAL));

        // Set overlay mix function.
        regw(OVERLAY_KEY_CNTL, (regr(OVERLAY_KEY_CNTL)) | ((VT_GT_G_OR_V_MIX) << 8));

        // Set video key colour
        regw(OVERLAY_VIDEO_KEY_CLR, 0x00FFFFFF);

        // Set video key mask
        regw(OVERLAY_VIDEO_KEY_MSK, mask);

        // Set overlay location (upper left corner of display) and mix key.
        set_overlay (0, 0, MODE_INFO.xres-1, MODE_INFO.yres-1);
        if (MODE_INFO.xres>1024)
        {
            set_scale (320, 200, MODE_INFO.xres-1, (MODE_INFO.yres-1)/2);
        }
        else
        {
            set_scale (320, 200, MODE_INFO.xres-1, MODE_INFO.yres-1);
        }

        enable_overlay();

        while (!kbhit())
        {
            mask=0x0;
            for (i=24; i>CLR_MSK_LIMIT; i--)
            {
                localmaxmask = 0xFFFFFF >> (i-1);
                localmaxmask <<= (i-1);

                localmask = 0x1;
                delay(KEYERDELAY);

                // Set video key mask
                regw(OVERLAY_VIDEO_KEY_MSK, mask+localmask);

                while (((mask+localmask) != (localmaxmask)) && (!kbhit()))
                {
                    localmask *=0x2;
                    delay(KEYERDELAY);
                    // Set video key mask
                    regw(OVERLAY_VIDEO_KEY_MSK, mask+localmask);
                } // while

                mask+=localmask;
            } // for

            delay(KEYERDELAY);

            // Set video key mask
            regw(OVERLAY_VIDEO_KEY_MSK, 0x00FFFFFF);
            delay(KEYERDELAY);

        } // while

    } // else
    getch();

    disable_overlay();

    return;
    
}

/******************************************************************************
 * 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

