/****************************************************************************
 * RAGE128 Chapter 6 Sample Code                                            *
 *                                                                          *
 * stencil.c - This program demonstrates how to draw set stencil 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 <math.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\zbuffer.h"
#include "..\util\util3d.h"
#include "..\util\alphblnd.h"

#define NUM_TRIS 10
#define PI_X_2 6.28319f

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 verts[4];
    PRIMDATA primstrip;

    printf ("Rage 128 Sample Code, Chapter 6.\n"
        "STENCIL.EXE\n\n"
        "This program demonstrates how to set stencil 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, 8bpp.\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 ();

    // Clear the screen

    verts[0].x = 0.0f;
    verts[0].y = 0.0f;
    verts[0].z = 0.5f;
    verts[0].rhw = 1.0f;
    verts[0].specular = 0x00000000;
    verts[0].diffuse = 0x000000ff;
    verts[0].s2 = verts[0].s1 = 0.5f;
    verts[0].t2 = verts[0].t1 = 0.5f;

    verts[1].x = (float)R128_AdapterInfo.xres;
    verts[1].y = 0.0f;
    verts[1].z = 0.5f;
    verts[1].rhw = 1.0f;
    verts[1].specular = 0x00000000;
    verts[1].diffuse = 0x0000ff00;
    verts[1].s2 = verts[1].s1 = 0.5f;
    verts[1].t2 = verts[1].t1 = 0.5f;

    verts[2].x = 0.0f;
    verts[2].y = (float)R128_AdapterInfo.yres;
    verts[2].z = 0.5f;
    verts[2].rhw = 1.0f;
    verts[2].specular = 0x00000000;
    verts[2].diffuse = 0x00ff0000;
    verts[2].s2 = verts[2].s1 = 0.5f;
    verts[2].t2 = verts[2].t1 = 0.5f;

    verts[3].x = (float)R128_AdapterInfo.xres;
    verts[3].y = (float)R128_AdapterInfo.yres;
    verts[3].z = 0.5f;
    verts[3].rhw = 1.0f;
    verts[3].specular = 0x00000000;
    verts[3].diffuse = 0x00000000;
    verts[3].s2 = verts[3].s1 = 0.5f;
    verts[3].t2 = verts[3].t1 = 0.5f;

    primstrip.numverts = 4;
    primstrip.verts = verts;

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

    // Create the z/stencil buffer.

    ATTEMPT (R128_CreateZStencilBuffer (ZSTENFORMAT_Z24_STEN8), 
		"create z/stencil buffer failed!!")

	// Clear stencil buffer.

    ATTEMPT (R128_ClearStencilBuffer (0x00000000), 
		"stencil buffer clear failed!!")

	// Set Stencil buffer states:

	// Enable stencil buffer.

    ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_ENABLE, TRUE),
        "enable stencil buffer failed!!")

	// Set stencil compare function.

	ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_CMP, CMP_ALWAYS),
		"set stencil cmp failed!!")

	// Stencil reference.

    ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_REF, 0x01),
		"set stencil ref failed!!")

	// Set stencil fail op.

    ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_SFAILOP, 
		STENCILOP_CURRENT),
		"set stencil fail op failed!!")

	// Set stencil z pass op.

	ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_ZPASSOP, STENCILOP_REF),
        "set stencil z pass op failed!!")

	// Set stencil z fail op.

    ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_ZFAILOP, 
		STENCILOP_CURRENT),
		"set stencil z fail op failed!!")

	// Set stencil mask.

	ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_MASK, 0xff),
		"set stencil mask failed!!")

	// Set stencil write mask.

	ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_WRITEMASK, 0xff),
        "set stencil write mask failed!!")

	// Turn on alpha blending.

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

	// Set Src blending factor.

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

	// Set Dst blending factor.

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

    // Create a triangle.

    verts[0].x = (float)R128_AdapterInfo.xres * 0.25f;
    verts[0].y = (float)R128_AdapterInfo.yres * 0.25f;
    verts[0].z = 0.5f;
    verts[0].rhw = 1.0f;
    verts[0].specular = 0x00000000;
    verts[0].diffuse = 0x80ffffff;
    verts[0].s2 = verts[0].s1 = 0.5f;
    verts[0].t2 = verts[0].t1 = 0.5f;

    verts[1].x = (float)R128_AdapterInfo.xres * 0.65f;
    verts[1].y = (float)R128_AdapterInfo.yres * 0.25f;
    verts[1].z = 0.5f;
    verts[1].rhw = 1.0f;
    verts[1].specular = 0x00000000;
    verts[1].diffuse = 0x80ffffff;
    verts[1].s2 = verts[1].s1 = 0.5f;
    verts[1].t2 = verts[1].t1 = 0.5f;

    verts[2].x = (float)R128_AdapterInfo.xres * 0.25f;
    verts[2].y = (float)R128_AdapterInfo.yres * 0.65f;
    verts[2].z = 0.5f;
    verts[2].rhw = 1.0f;
    verts[2].specular = 0x00000000;
    verts[2].diffuse = 0x80ffffff;
    verts[2].s2 = verts[2].s1 = 0.5f;
    verts[2].t2 = verts[2].t1 = 0.5f;

    primstrip.numverts = 3;

	// Draw the stencilling triangle.

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

	// disable alpha blending.

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

	// Only draw where the stencil value != stencil ref.

    ATTEMPT (R128_SetStencilBufferState (STENCILSTATE_CMP, CMP_NEQUAL),
		"set stencil cmp failed!!")

	// Set rectangle paramters.

    verts[0].x = (float)R128_AdapterInfo.xres * 0.2f;
    verts[0].y = (float)R128_AdapterInfo.yres * 0.2f;
    verts[0].z = 0.5f;
    verts[0].rhw = 1.0f;
    verts[0].specular = 0x00000000;
    verts[0].diffuse = 0x00ff0000;
    verts[0].s2 = verts[0].s1 = 0.5f;
    verts[0].t2 = verts[0].t1 = 0.5f;

    verts[1].x = (float)R128_AdapterInfo.xres * 0.8f;
    verts[1].y = (float)R128_AdapterInfo.yres * 0.2f;
    verts[1].z = 0.5f;
    verts[1].rhw = 1.0f;
    verts[1].specular = 0x00000000;
    verts[1].diffuse = 0x0000ff00;
    verts[1].s2 = verts[1].s1 = 0.5f;
    verts[1].t2 = verts[1].t1 = 0.5f;

    verts[2].x = (float)R128_AdapterInfo.xres * 0.2f;
    verts[2].y = (float)R128_AdapterInfo.yres * 0.8f;
    verts[2].z = 0.5f;
    verts[2].rhw = 1.0f;
    verts[2].specular = 0x00000000;
    verts[2].diffuse = 0x000000ff;
    verts[2].s2 = verts[2].s1 = 0.5f;
    verts[2].t2 = verts[2].t1 = 0.5f;

    verts[3].x = (float)R128_AdapterInfo.xres * 0.8f;
    verts[3].y = (float)R128_AdapterInfo.yres * 0.8f;
    verts[3].z = 0.5f;
    verts[3].rhw = 1.0f;
    verts[3].specular = 0x00000000;
    verts[3].diffuse = 0x00ffffff;
    verts[3].s2 = verts[3].s1 = 0.5f;
    verts[3].t2 = verts[3].t1 = 0.5f;

    primstrip.numverts = 4;

	// Draw the rectangle.

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

	getch ();

exit_app:

	// Free the z/stencil 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


