/****************************************************************************
 * RAGE128 Chapter 6 Sample Code                                            *
 *                                                                          *
 * tritex.c - This program demonstrates how to draw a textured mapped       *
 * 3D triangle 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 <string.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\texture.h"
#include "..\util\util3d.h"

#define TEX_FILE "..\\image\\brick.bmp"
#define TEX2_FILE "..\\image\\wood.bmp"

char gErrMsg [64] = {0};

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

void DrawTriangle (void);


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

void main (int argc, char *argv[])
{
	int i, exitcode = 0;
    TEXINFO tex1info, tex2info;
	int ch;
	int exitwhile = 0;
	int TexCombFnc = (int)TEXCOMBFNC_COPY;
	int TexMagBlend = (int) MAGBLEND_NEAREST;
	int TexMinBlend = (int) MINBLEND_NEAREST;
    int tselect = 0;

    printf ("Rage 128 Sample Code, Chapter 6.\n"
        "TRITEX.EXE\n\n"
        "This program demonstrates how to draw a texture mapped triangle using\n"
        "Rage 128 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"
        "\tM: cycle through texture magnification blend modes.\n"
        "\tN: cycle through texture minification blend modes.\n"
        "\tC: cycle through texture combine function modes.\n"
        "\tT: toggle between two textures.\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 ();

	// Load the texture map.

	memset (&tex1info, 0, sizeof (tex1info));
    ATTEMPT (R128_LoadTextureBMP_ARGB8888 (TEX_FILE, &tex1info),
        "load first texture failed!!")

	memset (&tex2info, 0, sizeof (tex2info));
    ATTEMPT (R128_LoadTextureBMP_ARGB8888 (TEX2_FILE, &tex2info),
        "load second texture failed!!")

	// Set the texture.

    ATTEMPT (R128_SetTexture (0, &tex1info), "SetTexture failed!!")

	// Enable texture mapping.

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

	// Set the minification filtering mode.

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

	// Set the magnification filtering mode.

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

	// Set the texture combine function.

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

	// Loop processing keyress input.

	while (exitwhile == 0)
	{
        // Clear the screen.

        R128_CCEClearScreen (0x000000ff);

        // Draw a single triangle.

		DrawTriangle ();

		// Get keypress input.

        while (!kbhit());

        ch = getch ();

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

        // Set magnification filtering mode.

        case 'm':
        case 'M':
			TexMagBlend++;
			if (TexMagBlend > (int)MAGBLEND_BILINEAR)
				TexMagBlend = (int)MAGBLEND_NEAREST;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_MAGBLEND, 
				TexMagBlend), 
				"set mag blend failed!!")
			break;

        // Set minification filtering mode.

		case 'n':
		case 'N':
			TexMinBlend++;
			if (TexMinBlend > (int)MINBLEND_TRILINEAR)
				TexMinBlend = (int)MINBLEND_NEAREST;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_MINBLEND, 
				TexMinBlend), 
				"set min blend failed!!")
			break;

        // Set the alpha blending combine function.

		case 'c':
		case 'C':
			TexCombFnc++;
			if (TexCombFnc > (int)TEXCOMBFNC_BLEND_CONSTANTCOLOR)
				TexCombFnc = (int)TEXCOMBFNC_COPY;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_COMB_FNC, 
				TexCombFnc), 
				"set comb fnc failed!!")
			break;

        // Switch textures.

        case 't':
        case 'T':
            tselect++;

            if (tselect & 1)
            {
                ATTEMPT (R128_SetTexture (0, &tex2info), 
                    "SetTexture (2) failed!!")
            }
            else
            {
                ATTEMPT (R128_SetTexture (0, &tex1info), 
                    "SetTexture (1) failed!!")
            }
            break;

		} // switch
	} // while 

exit_app:

    // Shut down the microengine.

	if (tex1info.Offset[0])
        R128_FreeTexture (&tex1info);
	if (tex2info.Offset[0])
		R128_FreeTexture (&tex2info);

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


/****************************************************************************
 * DrawTriangle                                                             *
 *  Function: Draw a single gouraud shaded triangle.                        *
 *    Inputs: none                                                          *
 *   Outputs: none                                                          *
 ****************************************************************************/

void DrawTriangle (void)
{
    TLVERTEX2 triverts[3];

    // Set triangle vertices:

    // Vertex 0:

    triverts[0].x = ((float)R128_AdapterInfo.xres/2.0f);
    triverts[0].y = ((float)R128_AdapterInfo.yres/4.0f);
    triverts[0].z = 0.5f;
    triverts[0].rhw = 1.0f;
    triverts[0].diffuse = 0x000000ff;
    triverts[0].specular = 0x00000000;
    triverts[0].s1 = 0.5f;
    triverts[0].t1 = 1.0f;
    triverts[0].s2 = 0.5f;                                                                  // s2
    triverts[0].t2 = 0.0f;                                                                  // t2

    // Vertex 1:

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

    // Vertex 2:

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

    // Draw a single triangle.

    R128_DrawTriangle (triverts);
}


