/****************************************************************************
 * RAGE128 Chapter 6 Sample Code                                            *
 *                                                                          *
 * ablend.c - This program demonstrates how to set alpha blending states    *
 * using CCE command packets.                                               *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <i86.h>
#include <conio.h>
#include "..\..\util\regdef.h"
#include "..\..\util\defines.h"
#include "..\..\util\main.h"
#include "..\..\util\cce.h"
#include "..\util\cntx3d.h"
#include "..\util\prim.h"
#include "..\util\util3d.h"
#include "..\util\alphblnd.h"

char gErrMsg [64] = {0};

extern DWORD BPPOverride; // Override default 8bpp mode in Chap 3 lib.


/****************************************************************************
 * main                                                                     *
 *  Function: Main loop.                                                    *
 *    Inputs: none                                                          *
 *   Outputs: none                                                          *
 ****************************************************************************/

void main (int argc, char *argv[])
{
	int i, exitcode = 0;
    TLVERTEX2 rect1[4], rect2[4];
	PRIMDATA rect1strip, rect2strip;
	int ch;
	int exitwhile = 0;
	int SrcBlend = (int)BLEND_ONE;
	int DstBlend = (int)BLEND_ZERO;
	int CombFnc = (int)COMBFNC_ADD_CLAMP;

    printf ("Rage 128 Sample Code, Chapter 6.\n"
        "ABLEND.EXE\n\n"
        "This program demonstrates how to set alpha blending states using Rage 128\n"
        "CCE command packets.\n\n"
        "Mode resolution (eg 640 480) and colour depth (15, 16, 32)\n"
        "should be passed as command line arguments.\n"
        "Default resolution and colour depth is 640x480, 32bpp.\n\n"
        "The following keys may be used:\n"
        "\tS: cycle through source blending modes.\n"
        "\tD: cycle through destination blending modes.\n"
        "\tC: cycle through alpha blending combine modes.\n"
        "\tESC: exit the program.\n\n"
        "Press any key to continue.\n\n");

    getch ();

    // Inspect arguments for invalid color depth.

    for (i = 1; i < argc; i++)
    {
        if ((strcmp (argv[i], "8") == 0) || (strcmp (argv[i], "24") == 0))
		{
			printf ("\nThis program does not operate at 8 or 24 bpp.");
			printf ("\nProgram terminated.");
			exit (1);
		}
	}

    // Override default 8bpp mode in Chap 3 lib.

    BPPOverride = 32;

    // First, run StartUp function to set up the application.

    R128_StartUp (argc, argv);

    // Clear the screen.

    R128_ClearScreen (DARKBLUE);

    // Initialize the CCE microengine.

    if (R128_CCEInit (CCE_MODE_192BM) != CCE_SUCCESS)
    {
        R128_ShutDown ();
        printf ("R128_CCEInit failed!!\n");
        exit (1);
    } // if

	// Set the default 3D context.

    R128_Init3DContext ();

	// Set rect parameters.

	rect1[0].x = R128_AdapterInfo.xres * 0.2f;
	rect1[0].y = R128_AdapterInfo.yres * 0.2f;
	rect1[0].z = 0.5f;
	rect1[0].rhw = 1.0f;
	rect1[0].diffuse = 0xffff0000;
    rect1[0].specular = 0x00000000;
	rect1[0].s2 = rect1[0].s1 = 0.0f;
	rect1[0].t2 = rect1[0].t1 = 1.0f;

	rect1[1].x = R128_AdapterInfo.xres * 0.7f;
	rect1[1].y = R128_AdapterInfo.yres * 0.2f;
	rect1[1].z = 0.5f;
	rect1[1].rhw = 1.0f;
	rect1[1].diffuse = 0x00f00000;
    rect1[1].specular = 0x00000000;
	rect1[1].s2 = rect1[1].s1 = 1.0f;
	rect1[1].t2 = rect1[1].t1 = 1.0f;

	rect1[2].x = R128_AdapterInfo.xres * 0.2f;
	rect1[2].y = R128_AdapterInfo.yres * 0.6f;
	rect1[2].z = 0.5f;
	rect1[2].rhw = 1.0f;
	rect1[2].diffuse = 0xff8f0000;
    rect1[2].specular = 0x00000000;
	rect1[2].s2 = rect1[2].s1 = 0.0f;
	rect1[2].t2 = rect1[2].t1 = 0.0f;

	rect1[3].x = R128_AdapterInfo.xres * 0.7f;
	rect1[3].y = R128_AdapterInfo.yres * 0.6f;
	rect1[3].z = 0.5f;
	rect1[3].rhw = 1.0f;
	rect1[3].diffuse = 0x00800000;
    rect1[3].specular = 0x00000000;
	rect1[3].s2 = rect1[3].s1 = 1.0f;
	rect1[3].t2 = rect1[3].t1 = 0.0f;

	rect1strip.numverts = 4;
	rect1strip.verts = rect1;

	// Set rect parameters.

	rect2[0].x = R128_AdapterInfo.xres * 0.3f;
	rect2[0].y = R128_AdapterInfo.yres * 0.4f;
	rect2[0].z = 0.5f;
	rect2[0].rhw = 1.0f;
	rect2[0].diffuse = 0x0000ff00;
    rect2[0].specular = 0x00000000;
	rect2[0].s2 = rect2[0].s1 = 0.0f;
	rect2[0].t2 = rect2[0].t1 = 1.0f;

	rect2[1].x = R128_AdapterInfo.xres * 0.8f;
	rect2[1].y = R128_AdapterInfo.yres * 0.4f;
	rect2[1].z = 0.5f;
	rect2[1].rhw = 1.0f;
	rect2[1].diffuse = 0xff00f000;
    rect2[1].specular = 0x00000000;
	rect2[1].s2 = rect2[1].s1 = 1.0f;
	rect2[1].t2 = rect2[1].t1 = 1.0f;

	rect2[2].x = R128_AdapterInfo.xres * 0.3f;
	rect2[2].y = R128_AdapterInfo.yres * 0.8f;
	rect2[2].z = 0.5f;
	rect2[2].rhw = 1.0f;
	rect2[2].diffuse = 0x00008f00;
    rect2[2].specular = 0x00000000;
	rect2[2].s2 = rect2[2].s1 = 0.0f;
	rect2[2].t2 = rect2[2].t1 = 0.0f;

	rect2[3].x = R128_AdapterInfo.xres * 0.8f;
	rect2[3].y = R128_AdapterInfo.yres * 0.8f;
	rect2[3].z = 0.5f;
	rect2[3].rhw = 1.0f;
	rect2[3].diffuse = 0xff008000;
    rect2[3].specular = 0x00000000;
	rect2[3].s2 = rect2[3].s1 = 1.0f;
	rect2[3].t2 = rect2[3].t1 = 0.0f;

	rect2strip.numverts = 4;
	rect2strip.verts = rect2;

	// Loop processing keyress input.

	while (exitwhile == 0)
	{
		// Turn off alpha blending momentarily. Then, clear the screen
		// and draw the first rectangle.

		ATTEMPT (R128_SetAlphaBlendState (ALPHABLENDSTATE_ENABLE, FALSE), 
			"alpha blend disable failed!!")

        // Clear the screen.

        R128_CCEClearScreen (0x000000ff);

		// Draw rect1.

        ATTEMPT (R128_DrawTriangleStrip (&rect1strip),  
			"R128_DrawTriangleStrip for rect failed!!")

		// Re-enable alpha blending and set the current states. 

		ATTEMPT (R128_SetAlphaBlendState (ALPHABLENDSTATE_ENABLE, TRUE), 
			"alpha blend enable failed!!")

		// Set Src blending factor.

        ATTEMPT (R128_SetAlphaBlendState (ALPHABLENDSTATE_SRCBLEND,
			SrcBlend), "set src alpha blend factor failed!!")

		// Set Dst blending factor.

        ATTEMPT (R128_SetAlphaBlendState (ALPHABLENDSTATE_DSTBLEND,
			DstBlend), "set dst alpha blend factor failed!!")

		// Set Combining function.

        ATTEMPT (R128_SetAlphaBlendState (ALPHABLENDSTATE_COMBFNC,
			CombFnc), "set comb fnc failed!!")

		// Draw rect2.

        ATTEMPT (R128_DrawTriangleStrip (&rect2strip), 
			"R128_DrawTriangleStrip for rect failed!!")

		// Get keypress input.

        while (!kbhit());
        ch = getch ();

		switch (ch)
		{
		case 27: // ESC
			exitwhile = 1;
			break;

		case 's':
		case 'S':
			SrcBlend++;
			if (SrcBlend == (int)BLEND_BOTHINVSRCALPHA)
				SrcBlend = (int)BLEND_SRCSRCALPHA_DSTINVSRCALPHA;
			else if (SrcBlend > (int)BLEND_SRCINVSRCALPHA_DSTSRCALPHA)
				SrcBlend = (int)BLEND_ZERO;
			break;

		case 'd':
		case 'D':
			DstBlend++;
			if (DstBlend > (int)BLEND_SRCALPHASAT)
				DstBlend = (int)BLEND_ZERO;
			break;

		case 'c':
		case 'C':
			CombFnc++;
			if (CombFnc > (int)COMBFNC_SUB_DSTSRC_NOCLAMP)
				CombFnc = (int)COMBFNC_ADD_CLAMP;
			break;
		} // switch
	} // while 

exit_app:

	// Close 3D context, shut down micro-engine and restore original mode.

	R128_Close3DContext ();
    R128_CCEEnd (CCE_END_WAIT);
    R128_ShutDown ();

	// print error message if any.

	if (exitcode == 1)
		printf ("%s\n", gErrMsg);

	exit (exitcode);
} // main
