#include "pch.hpp"
//===========================================================================//
// File:	 3DPrimitives.cpp												 //
// Project:  GameOS					                                         //
// Contents: Functions that draw 3D primitives								 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 27/11/98  AG		Created								 					 //
//																			 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#include "3DRasterizer.hpp"
#include "DXRasterizer.hpp"
#include "DirectX.hpp"
#include "Debugger.hpp"


DWORD FanCalls;
DWORD StripCalls;
float FanLength;
float StripLength;



//
// Application visible function
//
// Draws points - must have already called gos_SetupViewport
//  Note wireframe does not effect points
//
void __stdcall gos_DrawPoints( gos_VERTEX* Vertices, int NumVertices )
{
	LOG_BLOCK("Gos3D::DrawPoints");
	gosASSERT( !RenderDevice && InsideBeginScene && Vertices && NumVertices );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		CheckVertices( Vertices, NumVertices, 1 );
	#endif

	#ifdef LAB_ONLY
		if( gDisableLinesPoints && !InDebugger )
			return;
		PrimitivesRendered+=NumVertices;
		PointsRendered+=NumVertices;
		if( ZoomMode )
		{
			for( int t0=0; t0<NumVertices; t0++ )
			{
				gos_VERTEX nv1=Vertices[t0];
				nv1.x-=(DBMouseX-nv1.x)*ZoomMode;
				nv1.y-=(DBMouseY-nv1.y)*ZoomMode;
				wDrawPrimitive( d3dDevice7, D3DPT_POINTLIST, D3DFVF_TLVERTEX, &nv1, 1,  0 );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawPrimitive( d3dDevice7, D3DPT_POINTLIST, D3DFVF_TLVERTEX, Vertices, NumVertices,  0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}

//
// Application visible function
//
// Draws lines - must have already called gos_SetupViewport
//  Note wireframe does not effect lines
//
void __stdcall gos_DrawLines( gos_VERTEX* Vertices, int NumVertices )
{
	LOG_BLOCK("Gos3D::DrawLines");
	gosASSERT( !RenderDevice && InsideBeginScene && Vertices && NumVertices && (NumVertices&1)==0 );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		CheckVertices( Vertices, NumVertices, 1 );
	#endif

	#ifdef LAB_ONLY
		if( gDisableLinesPoints && !InDebugger )
			return;
		PrimitivesRendered+=NumVertices>>1;
		LinesRendered+=NumVertices>>1;
		if( ZoomMode )
		{
			for( int t0=0; t0<NumVertices; t0+=2 )
			{
				gos_VERTEX nv[2];
				nv[0]=Vertices[t0];
				nv[1]=Vertices[t0+1];
				nv[0].x-=(DBMouseX-nv[0].x)*ZoomMode;
				nv[0].y-=(DBMouseY-nv[0].y)*ZoomMode;
				nv[1].x-=(DBMouseX-nv[1].x)*ZoomMode;
				nv[1].y-=(DBMouseY-nv[1].y)*ZoomMode;
				wDrawPrimitive( d3dDevice7, D3DPT_LINELIST, D3DFVF_TLVERTEX, nv, 2, 0 );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawPrimitive( d3dDevice7, D3DPT_LINELIST, D3DFVF_TLVERTEX, Vertices, NumVertices, 0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}



//
// Application visible function
//
// Draws triangles - must have already called gos_SetupViewport
//
void __stdcall gos_DrawTriangles( gos_VERTEX* Vertices, int NumVertices )
{
	LOG_BLOCK("Gos3D::DrawTriangles");
	gosASSERT( InsideBeginScene && Vertices && NumVertices && (NumVertices%3)==0 );

	if( RenderDevice )
	{
		LOG_BLOCK("Gos3D::DrawTriangles RenderDevice->DrawPrimitive");
		RenderDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, Vertices, NumVertices, 0 );
		return;
	}

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		CheckVertices( Vertices, NumVertices );
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumVertices/3;
		TrianglesRendered+=NumVertices/3;
		if( RenderMode )
		{
			for( int t0=0; t0<NumVertices; t0+=3 )
			{
				DebugTriangle( &Vertices[t0], &Vertices[t0+1], &Vertices[t0+2] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, Vertices, NumVertices, 0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}

//
// Array of indices for a single quad represented as a strip
//
WORD SingleQuadIndexArray[4] = { 1, 0, 2, 3 };


//
// Application visible function
//
// Draws quads - must have already called gos_SetupViewport
//
// 0 3
// 
// 1 2
//
void __stdcall gos_DrawQuads( gos_VERTEX* Vertices, int NumVertices )
{
	LOG_BLOCK("Gos3D::DrawQuads");
	gosASSERT( !RenderDevice && InsideBeginScene && Vertices && NumVertices && (NumVertices&3)==0 );
	gosASSERT( (NumVertices+(NumVertices>>1))<128*6 );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		CheckVertices( Vertices, NumVertices );
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumVertices>>1;
		QuadsRendered+=NumVertices>>2;
		if( RenderMode )
		{
			for( int t0=0; t0<NumVertices; t0+=4 )
			{
				DebugTriangle( &Vertices[t0], &Vertices[t0+1], &Vertices[t0+2] );
				DebugTriangle( &Vertices[t0], &Vertices[t0+2], &Vertices[t0+3] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated

	if( NumVertices<128 )
	{
		wDrawIndexedPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, Vertices, NumVertices, QuadIndex, (NumVertices+(NumVertices>>1)), 0 );
	}
	else
	{
		do
		{
			if( NumVertices>=128 )
			{
				wDrawIndexedPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, Vertices, 128, QuadIndex, 192, 0 );
				NumVertices-=128;
				Vertices+=128;
			}
			else
			{
				wDrawIndexedPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, Vertices, NumVertices, QuadIndex, NumVertices+(NumVertices>>1), 0 );
				NumVertices=0;
			}
		}
		while( NumVertices );
	}
	GameOSFPU();				// Restore current GameOS FPU control word setup
}






//
// Application visible function
//
// Draws a strip - must have already called gos_SetupViewport
//
void __stdcall gos_DrawStrips( gos_VERTEX* Vertices, int NumVertices )
{
	LOG_BLOCK("Gos3D::DrawStrips");
	gosASSERT( !RenderDevice && InsideBeginScene && Vertices && NumVertices>=3 );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		CheckVertices( Vertices, NumVertices );
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumVertices-2;
		StripLength+=NumVertices-2;
		StripCalls++;
		if( RenderMode )
		{
			for( int t0=0; t0<NumVertices-2; t0++ )
			{
				DebugTriangle( &Vertices[t0], &Vertices[t0+1], &Vertices[t0+2] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawPrimitive( d3dDevice7, D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX, Vertices, NumVertices,  0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}


//
// Application visible function
//
// Draws a fan - must have already called gos_SetupViewport
//
void __stdcall gos_DrawFans( gos_VERTEX* Vertices, int NumVertices )
{
	LOG_BLOCK("Gos3D::DrawFans");
	gosASSERT( !RenderDevice && InsideBeginScene && Vertices && NumVertices>=3 );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		CheckVertices( Vertices, NumVertices );
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumVertices-2;
		FanLength+=NumVertices-2;
		FanCalls++;
		if( RenderMode )
		{
			for( int t0=0; t0<NumVertices-2; t0++ )
			{
				DebugTriangle( &Vertices[t0+1], &Vertices[t0+2], &Vertices[0] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawPrimitive( d3dDevice7, D3DPT_TRIANGLEFAN, D3DFVF_TLVERTEX, Vertices, NumVertices, 0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}



//
// Application visible function
//
// This API allows you to pass an array of indices and an array of vertices to be rendered.
//
// The x,y positions must be already transformed into the viewport using the constants returned
// by gos_GetViewport.
//
// The vertex colors in the array may be changed in some wireframe modes. Otherwise the data is
// not altered.
//
void __stdcall gos_RenderIndexedArray( gos_VERTEX* pVertexArray, DWORD NumberVertices, WORD* lpwIndices, DWORD NumberIndices )
{
	LOG_BLOCK("Gos3D::RenderIndexedArray");
	gosASSERT( InsideBeginScene && NumberVertices>0 && NumberIndices>0 && (NumberIndices%3)==0 );

	if( RenderDevice )
	{
		RenderDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, pVertexArray, NumberVertices, lpwIndices, NumberIndices, 0 );
		return;
	}

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		if( gShowVertexData )						// Use ^Break debugger to enable (show vertex data)
		{
			for( int t0=0; t0<NumberIndices; t0+=3 )
			{
				SPEW(( GROUP_DIRECT3D, "Indices %d,%d,%d",lpwIndices[t0],lpwIndices[t0+1],lpwIndices[t0+2] ));
			}
		}
		//
		// Check only the vertices used and all the indices are valid
		//
		for( int t0=0; t0<NumberIndices; t0++ )
		{
			gosASSERT( lpwIndices[t0] < NumberVertices );
			CheckVertices( &pVertexArray[lpwIndices[t0]], 1 );
		}
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumberIndices/3;
		IndexedTriangleLength+=NumberIndices/3;
		IndexedTriangleCalls++;
		if( RenderMode )
		{
			for( int t0=0; t0<NumberIndices; t0+=3 )
			{
				DebugTriangle( &pVertexArray[lpwIndices[t0]], &pVertexArray[lpwIndices[t0+1]], &pVertexArray[lpwIndices[t0+2]] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawIndexedPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, pVertexArray, NumberVertices, lpwIndices, NumberIndices, 0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}



//
// Application visible function
//
// This API allows you to pass an array of indices and an array of vertices to be rendered.
//
// The x,y positions must be already transformed into the viewport using the constants returned
// by gos_GetViewport.
//
// The vertex colors in the array may be changed in some wireframe modes. Otherwise the data is
// not altered.
//
void __stdcall gos_RenderIndexedArray( gos_VERTEX_2UV* pVertexArray, DWORD NumberVertices, WORD* lpwIndices, DWORD NumberIndices )
{
	LOG_BLOCK("Gos3D::RenderIndexedArray(2UV)");
	gosASSERT( !RenderDevice && InsideBeginScene && NumberVertices>0 && NumberIndices>0 && (NumberIndices%3)==0 );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		//
		// Check only the vertices used and all the indices are valid
		//
		for( int t0=0; t0<NumberIndices; t0++ )
		{
			gosASSERT( lpwIndices[t0] < NumberVertices );
			CheckVertices2( &pVertexArray[lpwIndices[t0]], 1 );
		}
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumberIndices/3;
		IndexedTriangleLength+=NumberIndices/3;
		IndexedTriangleCalls++;
		if( RenderMode )
		{
			for( int t0=0; t0<NumberIndices; t0+=3 )
			{
				DebugTriangle_2UV( &pVertexArray[lpwIndices[t0]], &pVertexArray[lpwIndices[t0+1]], &pVertexArray[lpwIndices[t0+2]] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawIndexedPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2, pVertexArray, NumberVertices, lpwIndices, NumberIndices, 0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}


//
// Application visible function
//
// This API allows you to pass an array of indices and an array of vertices to be rendered.
//
// The x,y positions must be already transformed into the viewport using the constants returned
// by gos_GetViewport.
//
// The vertex colors in the array may be changed in some wireframe modes. Otherwise the data is
// not altered.
//
void __stdcall gos_RenderIndexedArray( gos_VERTEX_3UV* pVertexArray, DWORD NumberVertices, WORD* lpwIndices, DWORD NumberIndices )
{
	LOG_BLOCK("Gos3D::RenderIndexedArray(3UV)");
	gosASSERT( !RenderDevice && InsideBeginScene && NumberVertices>0 && NumberIndices>0 && (NumberIndices%3)==0 );

	if( DirtyStates )
		FlushRenderStates();

	#ifdef _ARMOR
		//
		// Check only the vertices used and all the indices are valid
		//
		for( int t0=0; t0<NumberIndices; t0++ )
		{
			gosASSERT( lpwIndices[t0] < NumberVertices );
			CheckVertices3( &pVertexArray[lpwIndices[t0]], 1 );
		}
	#endif

	#ifdef LAB_ONLY
		if( gDisablePrimitives && !InDebugger )
			return;
		PrimitivesRendered+=NumberIndices/3;
		IndexedTriangleLength+=NumberIndices/3;
		IndexedTriangleCalls++;
		if( RenderMode )
		{
			for( int t0=0; t0<NumberIndices; t0+=3 )
			{
				DebugTriangle_3UV( &pVertexArray[lpwIndices[t0]], &pVertexArray[lpwIndices[t0+1]], &pVertexArray[lpwIndices[t0+2]] );
			}
			return;
		}
	#endif

	SafeFPU();					// Make sure exceptions cannot be generated
	wDrawIndexedPrimitive( d3dDevice7, D3DPT_TRIANGLELIST, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX3, pVertexArray, NumberVertices, lpwIndices, NumberIndices, 0 );
	GameOSFPU();				// Restore current GameOS FPU control word setup
}


