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

#include <stdio.h>
#include <stdlib.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"
#include "..\util\rendstat.h"
#include "..\util\key.h"

#define TEX1_FILE "..\\image\\brick.bmp"
#define TEX2_FILE "..\\image\\lightmap.bmp"
#define TEX3_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[];

void DrawRect (void);

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

void main (int argc, char *argv[])
{
	int i, exitcode = 0;
	TEXINFO tex1info, tex2info, tex3info;
    int exitwhile = 0;
    WORD key;

    // Primary texture states.

    ETEXCOMBFNC TexCombFnc = TEXCOMBFNC_COPY;
    EFACTOR TexColorFactor= FACTOR_TEXTURECOLOR;
    EINPUTFACTOR TexInputFactor = INPUTFACTOR_INTERPCOLOR;
    ETEXCOMBFNC TexCombFncAlpha = TEXCOMBFNC_DISABLE;
    EFACTOR TexAlphaFactor = FACTOR_TEXTUREALPHA;
    EINPUTFACTOR TexInputFactorAlpha = INPUTFACTORALPHA_INTERPALPHA;

    // Secondary texture states.

    ETEXCOMBFNC SecTexCombFnc = TEXCOMBFNC_MODULATE2X;
    EFACTOR SecTexColorFactor = FACTOR_TEXTURECOLOR;
    EINPUTFACTOR SecTexInputFactor = INPUTFACTOR_PREVCOLOR;
    ETEXCOMBFNC SecTexCombFncAlpha = TEXCOMBFNC_DISABLE;
    EFACTOR SecTexAlphaFactor = FACTOR_TEXTUREALPHA;
    EINPUTFACTOR SecTexInputFactorAlpha = INPUTFACTORALPHA_PREVALPHA;
	DWORD WrapS = 0;
	DWORD WrapT = 0;
	ECLAMP ClampS = CLAMP_BORDER_COLOR;
	ECLAMP ClampT = CLAMP_BORDER_COLOR;
	DWORD TSelect = 0;

    // Post multi-texture light states.

    ETEXCOMBFNC TexLightFnc = TEXCOMBFNC_COPY;
    ETEXCOMBFNC AlphaLightFnc = TEXCOMBFNC_COPY;


    printf ("Rage 128 Sample Code, Chapter 6.\n"
        "MULTITEX.EXE\n\n"
        "This program demonstrates how to set multitexturing states using\n"
        "Rage 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"
        "The following keys may be used:\n"
        "\tF1: cycle through primary texture color combine functions.\n"
        "\tF2: cycle through primary texture color factors.\n"
        "\tF3: cycle through primary texture input factors.\n"
        "\tF4: cycle through primary texture alpha combine functions.\n"
        "\tF5: cycle through primary texture alpha factors.\n"
        "\tF6: cycle through primary texture alpha input factors.\n"
        "\tShift+F1: cycle through secondary texture color combine functions.\n"
        "\tShift+F2: cycle through secondary texture color factors.\n"
        "\tShift+F3: cycle through secondary texture input factors.\n"
        "\tShift+F4: cycle through secondary texture alpha combine functions.\n"
        "\tShift+F5: cycle through secondary texture alpha factors.\n"
        "\tShift+F6: cycle through secondary texture alpha input factors.\n"
        "\tF7: cycle through post-multitexture texture lighting functions.\n"
        "\tF8: cycle through post-multitexture alpha lighting functions.\n"
        "\tw: cycle through secondary texture S  wrap modes.\n"
        "\tc: cycle through secondary texture S clamp modes.\n"
        "\tW: cycle through secondary texture T wrap modes.\n"
        "\tC: cycle through secondary texture T clamp modes.\n"
        "\tt: toggle secondary texture:\n"
		"\t   lightmap-no texture alpha, explode-texture alpha.\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 the constant color to green.

    ATTEMPT (R128_SetRenderState (RENDERSTATE_SOLIDCOLOR, 0x0000ff00),
        "failed to set solid color!!")

	// Load the first texture map.

    memset (&tex1info, 0, sizeof (tex1info));
    ATTEMPT (R128_LoadTextureBMP_ARGB8888 (TEX1_FILE, &tex1info),
        "failed to load base texture!!")

	// Load the second texture map.

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

	// Load the third texture map.

    memset (&tex3info, 0, sizeof (tex3info));
    ATTEMPT (R128_LoadTextureTGA_ARGB8888 (TEX3_FILE, &tex3info),
        "failed to load second secondary texture!!")

	// Set the textures.

    ATTEMPT (R128_SetTexture (0, &tex1info),
	    "failed to set the first texture!!")

    ATTEMPT (R128_SetTexture (1, &tex2info),
        "failed to set the second texture!!")

	// Enable texture mapping.

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

	// Enable second texture map.

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


    // ***** Set initial states for primary texture: *****

	// 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 color combine function.

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

	// Set the color factor state.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_COLOR_FACTOR, 
        (DWORD)TexColorFactor), "set color factor failed!!")

	// Set the input factor state.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_INPUT_FACTOR, 
        (DWORD)TexInputFactor), "set input factor failed!!")

	// Set the alpha combine function.

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

	// Set the alpha factor state.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_ALPHA_FACTOR, 
        (DWORD)TexAlphaFactor), "set alpha factor failed!!")

	// Set the alpha input factor state.

    ATTEMPT (R128_SetTextureState (0, TEXSTATE_INPUT_FACTOR_ALPHA, 
        (DWORD)TexInputFactorAlpha), "set input factor alpha failed!!")

    // ***** Set initial states for secondary texture: *****

	// Set the minification filtering mode.

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

	// Set the magnification filtering mode.

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

	// Set the color combine function.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_COMB_FNC, 
        (DWORD)SecTexCombFnc), "set sec comb fnc failed!!")

	// Set the color factor state.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_COLOR_FACTOR, 
        (DWORD)SecTexColorFactor), "set sec color factor failed!!")

	// Set the input factor state.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_INPUT_FACTOR, 
        (DWORD)SecTexInputFactor), "set sec input factor failed!!")

	// Set the alpha combine function.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_COMB_FNC_ALPHA, 
        (DWORD)SecTexCombFncAlpha), "set sec comb fnc alpha failed!!")

	// Set the alpha factor state.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_ALPHA_FACTOR, 
        (DWORD)SecTexAlphaFactor), "set sec alpha factor failed!!")

	// Set the alpha input factor state.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_INPUT_FACTOR_ALPHA, 
        (DWORD)SecTexInputFactorAlpha), "set sec input factor alpha failed!!")

	// Set the S coordinate wrap mode.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_SWRAP_MODE, 
        (DWORD)(WrapS & 1)), "set sec wrap s failed!!")

	// Set the S coordinate clamp mode.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_SCLAMP_MODE, 
        (DWORD)ClampS), "set sec clamp s failed!!")

	// Set the T coordinate wrap mode.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_TWRAP_MODE, 
        (DWORD)(WrapT & 1)), "set sec wrap t failed!!")

	// Set the T coordinate clamp mode.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_TCLAMP_MODE, 
        (DWORD)ClampT), "set sec clamp t failed!!")

	// Set the border color.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_BORDER_COLOR, 
        0x00ff0000), "set sec border color failed!!")

	// Select the s,t coordinate pair for the secondary texture..

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_SELECTST, 
        SELECTST_SEC), "select st failed!!")

	// Select the W coordinate for the secondary texture.

    ATTEMPT (R128_SetTextureState (1, TEXSTATE_SELECTW,
        SELECTW_PRIM), "select w failed!!")

	// Loop processing keyress input.

	while (exitwhile == 0)
	{

        // Draw multitextured rectangle.

        DrawRect ();

		// Get keypress input.

        while ((key = R128_GetKey ()) == 0);


        switch (key)
		{
        case KEY_ESC: // ESC
			exitwhile = 1;
			break;

		// Primary texture color combine function.

        case KEY_F1:
			TexCombFnc++;
            if (TexCombFnc > TEXCOMBFNC_BLEND_CONSTANTCOLOR)
                TexCombFnc = TEXCOMBFNC_COPY;

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

		// Primary texture color factor.

        case KEY_F2:
            TexColorFactor++;
            if (TexColorFactor > FACTOR_NTEXTUREALPHA)
                TexColorFactor = FACTOR_TEXTURECOLOR;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_COLOR_FACTOR, 
                (DWORD)TexColorFactor), "set color factor failed!!")
			break;

		// Primary texture input factor.

        case KEY_F3:
            TexInputFactor++;
            if (TexInputFactor > INPUTFACTOR_INTERPALPHA)
                TexInputFactor = INPUTFACTOR_CONSTANTCOLOR;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_INPUT_FACTOR, 
                (DWORD)TexInputFactor), "set input factor failed!!")
			break;

		// Primary texture alpha combine function.

        case KEY_F4:
            TexCombFncAlpha++;
            if (TexCombFncAlpha == TEXCOMBFNC_BLEND_VERTEX)
                TexCombFncAlpha = TEXCOMBFNC_ADDSIGNED2X;
            else if (TexCombFncAlpha > TEXCOMBFNC_ADDSIGNED2X)
                TexCombFncAlpha = TEXCOMBFNC_DISABLE;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_COMB_FNC_ALPHA, 
                (DWORD)TexCombFncAlpha), "set comb fnc alpha failed!!")
			break;

		// Primary texture alpha factor.

        case KEY_F5:
            TexAlphaFactor++;
            if (TexAlphaFactor > FACTOR_NTEXTUREALPHA)
                TexAlphaFactor = FACTOR_TEXTUREALPHA;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_ALPHA_FACTOR, 
                (DWORD)TexAlphaFactor), "set alpha factor failed!!")
			break;


		// Primary texture alpha input factor.

        case KEY_F6:
            TexInputFactorAlpha++;
            if (TexInputFactorAlpha > INPUTFACTORALPHA_INTERPALPHA)
                TexInputFactorAlpha = INPUTFACTORALPHA_CONSTANTALPHA;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_INPUT_FACTOR_ALPHA, 
                (DWORD)TexInputFactorAlpha), "set input factor alpha failed!!")
			break;

		// Secondary texture color combine function.

        case KEY_SHFT_F1:
            SecTexCombFnc++;
            if (SecTexCombFnc > TEXCOMBFNC_BLEND_CONSTANTCOLOR)
                SecTexCombFnc = TEXCOMBFNC_DISABLE;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_COMB_FNC, 
                (DWORD)SecTexCombFnc), "set sec comb fnc failed!!")
			break;

		// Secondary texture color factor.

        case KEY_SHFT_F2:
            SecTexColorFactor++;
            if (SecTexColorFactor > FACTOR_NTEXTUREALPHA)
                SecTexColorFactor = FACTOR_TEXTURECOLOR;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_COLOR_FACTOR, 
                (DWORD)SecTexColorFactor), "set sec color factor failed!!")
			break;

		// Secondary texture input factor.

        case KEY_SHFT_F3:
            SecTexInputFactor++;
            if (SecTexInputFactor == (INPUTFACTOR_INTERPALPHA+1))
                SecTexInputFactor = INPUTFACTOR_PREVCOLOR;
            else if (SecTexInputFactor > INPUTFACTOR_PREVALPHA)
                SecTexInputFactor = INPUTFACTOR_CONSTANTCOLOR;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_INPUT_FACTOR, 
                (DWORD)SecTexInputFactor), "set sec input factor failed!!")
			break;

		// Secondary texture alpha combine function.

        case KEY_SHFT_F4:
            SecTexCombFncAlpha++;
            if (SecTexCombFncAlpha == TEXCOMBFNC_BLEND_VERTEX)
                SecTexCombFncAlpha = TEXCOMBFNC_ADDSIGNED2X;
            else if (SecTexCombFncAlpha > TEXCOMBFNC_ADDSIGNED2X)
                SecTexCombFncAlpha = TEXCOMBFNC_DISABLE;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_COMB_FNC_ALPHA, 
                (DWORD)SecTexCombFncAlpha), "set sec comb fnc alpha failed!!")
			break;

		// Secondary texture alpha factor.

        case KEY_SHFT_F5:
            SecTexAlphaFactor++;
            if (SecTexAlphaFactor > FACTOR_NTEXTUREALPHA)
                SecTexAlphaFactor = FACTOR_TEXTUREALPHA;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_ALPHA_FACTOR, 
                (DWORD)SecTexAlphaFactor), "set sec alpha factor failed!!")
			break;

		// Secondary texture alpha input factor.

        case KEY_SHFT_F6:
            SecTexInputFactorAlpha++;
            if (SecTexInputFactorAlpha == (INPUTFACTORALPHA_INTERPALPHA + 1))
                SecTexInputFactorAlpha = INPUTFACTORALPHA_PREVALPHA;

            if (SecTexInputFactorAlpha > INPUTFACTORALPHA_PREVALPHA)
                SecTexInputFactorAlpha = INPUTFACTORALPHA_CONSTANTALPHA;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_INPUT_FACTOR_ALPHA, 
                (DWORD)SecTexInputFactorAlpha), "set sec input factor alpha failed!!")
			break;

        // Post multi-texture color light function.

        case KEY_F7:
            TexLightFnc++;
            if (TexLightFnc == TEXCOMBFNC_BLEND_PREMULTIPLY)
                TexLightFnc = TEXCOMBFNC_BLEND_PREVIOUS;
            else if (TexLightFnc > TEXCOMBFNC_BLEND_PREVIOUS)
                TexLightFnc = TEXCOMBFNC_DISABLE;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_TEX_LIGHT_FCN, 
                (DWORD)TexLightFnc), "set tex light fnc failed!!")

            break;

        // Post multi-texture alpha light function.

        case KEY_F8:

            AlphaLightFnc++;
            if (AlphaLightFnc > TEXCOMBFNC_ADDSIGNED)
                AlphaLightFnc = TEXCOMBFNC_DISABLE;

            ATTEMPT (R128_SetTextureState (0, TEXSTATE_ALPHA_LIGHT_FCN, 
                (DWORD)AlphaLightFnc), "set alpha light fnc failed!!")

            break;


        } // switch

        switch (key & 0xff) // check ASCII only
		{
		// Secondary texture S  wrap mode.

        case 'w':
            WrapS++;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_SWRAP_MODE, 
                (DWORD)(WrapS & 1)), "set sec wrap s failed!!")
			break;

		// Secondary texture S clamp mode.

        case 'c':
            ClampS++;
            if (ClampS > CLAMP_BORDER_COLOR)
                ClampS = CLAMP_WRAP;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_SCLAMP_MODE, 
                (DWORD)ClampS), "set sec clamp s failed!!")
			break;

		// Secondary texture T wrap mode.

        case 'W':
            WrapT++;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_TWRAP_MODE, 
                (DWORD)(WrapT & 1)), "set sec wrap t failed!!")
			break;

		// Secondary texture T clamp mode.

        case 'C':
            ClampT++;
            if (ClampT > CLAMP_BORDER_COLOR)
                ClampT = CLAMP_WRAP;

            ATTEMPT (R128_SetTextureState (1, TEXSTATE_TCLAMP_MODE, 
                (DWORD)ClampT), "set sec clamp t failed!!")
			break;

		// Toggle the secondary texture.

        case 't':
        case 'T':
			TSelect++;
			TSelect &= 0x1;

			if (TSelect)
			{
				ATTEMPT (R128_SetTexture (1, &tex3info),
					"failed to set the first secondary texture!!")
			}
			else
			{
				ATTEMPT (R128_SetTexture (1, &tex2info),
					"failed to set the second secondary texture!!")
			}

			break;

		} // switch
	} // while 

exit_app:

    // Free the textures.

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

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


/****************************************************************************
 * DrawRect                                                                 *
 *  Function: Draw a multi-textured rectangle.                              *
 *    Inputs: none                                                          *
 *   Outputs: none                                                          *
 ****************************************************************************/

void DrawRect (void)
{
    TLVERTEX2 rect[4];
	PRIMDATA rectstrip;

    // Set rect vertices:

    // Vertex 0:

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

    // Vertex 1:

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

    // Vertex 2:

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

    // Vertex 3:

    rect[3].x = (float)R128_AdapterInfo.yres;
    rect[3].y = (float)R128_AdapterInfo.yres;
    rect[3].z = 0.5f;
    rect[3].rhw = 1.0f;
    rect[3].diffuse = 0x00ffffff;
    rect[3].specular = 0x00000000;
    rect[3].s1 = 2.0f;
    rect[3].t1 = 0.0f;
    rect[3].s2 = 3.0f;
    rect[3].t2 = 0.0f;

	rectstrip.numverts = 4;
	rectstrip.verts = rect;

    R128_DrawTriangleStrip (&rectstrip);
}
