/****************************************************************************
 * RAGE128 Chapter 6 Sample Code                                            *
 *                                                                          *
 * idxstpi.c - This program demonstrates how to draw an indexed triangle    *
 * strip using the CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM Type-3 command packet. *
 * Vertex data is copied into a dedicated vertex buffer, and vertex indices *
 * are copied into the ring buffer as part of the packet.                   *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.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"

#define NUM_TRIS 40
#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;
    int commandbuf_size, size;
    PRIMDATA tristrip;
    float centerx, centery, innerradius, outerradius, angle, deltaangle, 
		  sinval, cosval; 
    DWORD* pBuf = NULL;
    WORD* pvertindex;

    printf ("Rage 128 Sample Code, Chapter 6.\n"
        "IDXSTPI.EXE\n\n"
        "This program demonstrates how to draw an indexed triangle strip using the\n"
        "CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM Type-3 command packet. Vertices are\n"
        "copied into a dedicated vertex buffer and vertex indices are copied\n"
        "into the ring buffer as part of the packet.\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"
        "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_64BM_64VERBM_64INDBM) != CCE_SUCCESS)
    {
        R128_ShutDown ();
        printf ("R128_CCEInit failed!!\n");
        exit (1);
    } // if

	// Set the default 3D context.

    R128_Init3DContext ();

    // Compute command packet size and allocate memory for packet.

    commandbuf_size = (NUM_TRIS + 2)/2;         // two indices per DWORD
    if ((commandbuf_size * 2) < (NUM_TRIS + 2)) // round up
        commandbuf_size++;
    commandbuf_size += 5;                       // HEADER to VC_CNTL fields

    pBuf = (DWORD*) malloc (commandbuf_size * sizeof (DWORD));
    if (!pBuf)
    {
        sprintf (gErrMsg, "pBuf malloc failed!!");
        exitcode = 1;
		goto exit_app;
    }

    // Get vertex buffer pointer.

    tristrip.verts = (LPTLVERTEX2)R128_GetVertexBufferPtr();
    tristrip.numverts = NUM_TRIS + 2;

    // Initialize packet command fields.

    pBuf[0] = CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM;
    pBuf[1] = R128_GetVertexBufferOffset ();
    pBuf[2] = tristrip.numverts;
    pBuf[3] = VC_FORMAT_TLVERTEX2;
    pBuf[4] = CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP |
        CCE_VC_CNTL_PRIM_WALK_IND |
        tristrip.numverts << 16;

    // Set the vertex index write pointer. This is where vertex indices will
    // be copied into the command buffer.

    pvertindex = (WORD*) &pBuf[5];

    // Compute triangle position and size paramters.

	centerx = R128_AdapterInfo.xres/2.0f;
	centery = R128_AdapterInfo.yres/2.0f; 
	outerradius = (centery * 0.9f); 
	innerradius = (centery * 0.45f); 
	angle = 0.0f;
	deltaangle = PI_X_2/((float) NUM_TRIS/2.0f);

    // Set the perimiter vertices.

    for (i=0; i <= (NUM_TRIS/2); i++)
    {
		sinval = (float)sin ((double)angle);
		cosval = (float)cos ((double)angle);

        tristrip.verts[i*2].x = centerx + (sinval * innerradius);
        tristrip.verts[i*2].y = centery - (cosval * innerradius);
        tristrip.verts[i*2].z = 0.5f;
        tristrip.verts[i*2].rhw = 1.0f;
        tristrip.verts[i*2].diffuse = 0x00ffffff;
        tristrip.verts[i*2].specular = 0x00000000;
        tristrip.verts[i*2].s2 = tristrip.verts[i*2].s1 = 0.5f +
            (sinval * 0.25f);
        tristrip.verts[i*2].t2 = tristrip.verts[i*2].t1 = 0.5f +
            (cosval * 0.25f);
        *pvertindex++ = i*2;

        tristrip.verts[(i*2)+1].x = centerx + (sinval * outerradius);
        tristrip.verts[(i*2)+1].y = centery - (cosval * outerradius);
        tristrip.verts[(i*2)+1].z = 0.5f;
        tristrip.verts[(i*2)+1].rhw = 1.0f;
        tristrip.verts[(i*2)+1].diffuse = 0x00808080;
        tristrip.verts[(i*2)+1].specular = 0x00000000;
        tristrip.verts[(i*2)+1].s2 = tristrip.verts[(i*2)+1].s1 = 0.5f +
            (sinval * 0.5f);
        tristrip.verts[(i*2)+1].t2 = tristrip.verts[(i*2)+1].t1 = 0.5f +
            (cosval * 0.5f);
        *pvertindex++ = (i*2)+1;

		angle += deltaangle;
    }

    // Draw the triangle strip:

    // Compute the size of the packet.

    size = (DWORD)pvertindex - (DWORD)&pBuf[5]; // bytesize of indices written.
    if (size & 1) size++;                       // round up if odd number.

    // Convert size to DWORD count.

    size = size / sizeof (DWORD);


    // Adjust size for HEADER, PM4_VC _VLOFF, PM4_VC_VSIZE, PC_FORMAT and
    // VC_CNTL in packet.

    size += 5;

    // Set packet size parameter in packet HEADER.

    pBuf[0] |= ((size - 2) << 16);

    // Submit the packet to draw the batch.

    R128_CCESubmitPackets (pBuf, size);

    // Flush ring buffer in case triangles still queued.

    R128_Flush ();

	// Wait for key press to exit.

    getch ();

exit_app:

    // Free the vertex buffer.

    if (pBuf)
        free (pBuf);

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

