/****************************************************************************
 * RAGE128 Chapter 6 Sample Code                                            *
 *                                                                          *
 * atest.c - This program demonstrates how to set alpha testing 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\alphtest.h"
#include "..\util\alphblnd.h"
#include "..\util\texture.h"
#include "..\util\zbuffer.h"

#define BACKGROUND_TEX_FILE "..\\image\\backgnd.tga"
#define EXPLODE_TEX_FILE "..\\image\\explode.tga"

char gErrMsg [64] = {0};

extern DWORD BPPOverride; // Override default 8bpp mode in Chap 3 lib.
extern CONTEXT3D gContext3D;
extern DWORD gCommandBuf[];


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

void main (int argc, char *argv[])
{
	int i, exitcode = 0;
    TLVERTEX2 background[4], explode[4], bluefilm[4];
	PRIMDATA primdata;
	TEXINFO backgroundtex, explodetex;
	int ch;
	int exitwhile = 0;
	DWORD alpharef = 128;
    BOOL balphatest = TRUE;

    printf ("Rage 128 Sample Code, Chapter 6.\n"
        "ATEST.EXE\n\n"
        "This program demonstrates how to set alpha testing 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"
        "\tA: toggle alpha testing on and off.\n"
        "\tI: increment alpha reference.\n"
        "\tD: decrement alpha reference.\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);

    // 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 ();

    // Create a z buffer.

	ATTEMPT (R128_CreateZStencilBuffer (ZSTENFORMAT_Z32),
		"create z buffer failed!!")

    // Enable z testing and allow z buffer updates.

	ATTEMPT (R128_SetZBufferState (ZBUFFERSTATE_MODE, ZMODE_TESTWRITE),
		"enable z buffer failed!!")

    // Set the z compare function.

    ATTEMPT (R128_SetZBufferState (ZBUFFERSTATE_CMP, CMP_LESS),
		"set z func failed!!")

    // Set alpha test function.

	ATTEMPT (R128_SetAlphaTestState (ALPHATESTSTATE_CMP, CMP_GREATER),
		"set alpha test func failed!!")

    // Set alpha reference.

	ATTEMPT (R128_SetAlphaTestState (ALPHATESTSTATE_REF, alpharef),
		"set alpha reference failed!!")

    // Load the background texture.

    memset (&backgroundtex, 0, sizeof (backgroundtex));
	ATTEMPT (R128_LoadTextureTGA_ARGB8888 (BACKGROUND_TEX_FILE, 
        &backgroundtex), "load background texture failed!!")

    // Load the explosion texture.

    memset (&explodetex, 0, sizeof (explodetex));
	ATTEMPT (R128_LoadTextureTGA_ARGB8888 (EXPLODE_TEX_FILE, 
        &explodetex), "load explode texture failed!!")

    // Enable texture mapping.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_ENABLE, TRUE),
		"enable texture mapping failed!!")

	// Set the minification filtering mode.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_MINBLEND, 
        MINBLEND_BILINEAR),"set min blend failed!!")

	// Set the magnification filtering mode.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_MAGBLEND, 
        MAGBLEND_BILINEAR), "set mag blend failed!!")

    // Set the texture color combine function.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_COMB_FNC,
        TEXCOMBFNC_COPY), "set comb fnc failed!!")

    // Set the texture alpha combine function.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_COMB_FNC_ALPHA, 
        TEXCOMBFNC_COPY), "set comb fnc alpha failed!!")

    // Set the source alpha blending mode.

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

    // Set the destination alpha blending mode.

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

	// Set rect parameters.

	background[0].x = 0.0f;
	background[0].y = 0.0f;
	background[0].z = 0.9f;
	background[0].rhw = 1.0f;
    background[0].diffuse = 0xffffffff;
    background[0].specular = 0x00000000;
    background[0].s2 = background[0].s1 = 0.0f;
    background[0].t2 = background[0].t1 = 0.0f;

	background[1].x = R128_AdapterInfo.xres;
	background[1].y = 0.0f;
	background[1].z = 0.9f;
	background[1].rhw = 1.0f;
    background[1].diffuse = 0xffffffff;
    background[1].specular = 0x00000000;
    background[1].s2 = background[1].s1 = 1.0f;
    background[1].t2 = background[1].t1 = 0.0f;

	background[2].x = 0.0f;
	background[2].y = R128_AdapterInfo.yres;
	background[2].z = 0.9f;
	background[2].rhw = 1.0f;
    background[2].diffuse = 0xffffffff;
    background[2].specular = 0x00000000;
    background[2].s2 = background[2].s1 = 0.0f;
    background[2].t2 = background[2].t1 = 1.0f;

	background[3].x = R128_AdapterInfo.xres;
	background[3].y = R128_AdapterInfo.yres;
	background[3].z = 0.9f;
	background[3].rhw = 1.0f;
    background[3].diffuse = 0xffffffff;
    background[3].specular = 0x00000000;
    background[3].s2 = background[3].s1 = 1.0f;
    background[3].t2 = background[3].t1 = 1.0f;

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

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

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

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

	// Set rect parameters.

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

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

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

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

	primdata.numverts = 4;


	// Loop processing keyress input.

	while (exitwhile == 0)
	{

        // Clear the z buffer.

		ATTEMPT (R128_ClearZBuffer (0xffffffff),
			"clear z buffer failed!!")

        // Set the current texture to background.

		ATTEMPT (R128_SetTexture (0, &backgroundtex),
            "set background texture failed!!")

        // Disable alpha blending.

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

        // Draw the background.

		primdata.verts = background;
	
        ATTEMPT (R128_DrawTriangleStrip (&primdata),
			"draw background failed!!")

        // Set the current texture to explode.

		ATTEMPT (R128_SetTexture (0, &explodetex),
            "set explode texture failed!!")

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

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

        // Enable alpha testing.

        ATTEMPT (R128_SetAlphaTestState (ALPHATESTSTATE_ENABLE, balphatest),
            "enable alpha test failed!!")

		primdata.verts = explode;


        // Draw the explosion rect.

        ATTEMPT (R128_DrawTriangleStrip (&primdata),
			"draw explode failed!!")

		// Disable texture mapping.

		ATTEMPT (R128_SetTextureState (0, TEXSTATE_ENABLE, FALSE),
			"disable texture mapping failed!!")

        // Draw the blue film rect.

		primdata.verts = bluefilm;

        ATTEMPT (R128_DrawTriangleStrip (&primdata),
			"draw bluefilm failed!!")

		// Enable texture mapping.

		ATTEMPT (R128_SetTextureState (0, TEXSTATE_ENABLE, TRUE),
			"enable texture mapping failed!!")

		// Get keypress input.

        while (!kbhit());

        ch = getch ();

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

        // Toggle alpha testing on and off.

        case 'a':
        case 'A':
            if (balphatest)
                balphatest = FALSE;
            else
                balphatest = TRUE;
			break;

        // Increment alpha reference.

        case 'i':
        case 'I':
            alpharef++;
            alpharef &= 0xff;

            ATTEMPT (R128_SetAlphaTestState (ALPHATESTSTATE_REF, alpharef),
                "set alpha reference failed!!")

			break;

        // Decrement alpha reference.

        case 'd':
        case 'D':
            alpharef--;
            alpharef &= 0xff;

            ATTEMPT (R128_SetAlphaTestState (ALPHATESTSTATE_REF, alpharef),
                "set alpha reference failed!!")

			break;

		} // switch
	} // while 

exit_app:

	// Free textures.

    if (backgroundtex.Offset[0])
        R128_FreeTexture (&backgroundtex);
    if (explodetex.Offset[0])
        R128_FreeTexture (&explodetex);

	// Free the z buffer.

	R128_FreeZStencilBuffer ();

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