
#define USING_DESTINY3D_DLL
#define WIN32_LEAN_AND_MEAN
#include "Destiny3D.hpp"
#include "deMath.hpp"
#include "deProfile.hpp"
#include "deConsole.hpp"
#include "tinyptc/tinyptc.h"
#include "windows.h"

#ifdef _DEBUG
#pragma comment(lib, "tinyptc-d")
#else
#pragma comment(lib, "tinyptc")
#endif

#include "../../deScene/deOccludeRaster.hpp"
//#include "deOccludeRaster2.hpp"

#pragma warning (disable : 4305)

// 200x150, 320x240, 400x300, etc
const int BufferWidth = 128;
const int BufferHeight = 128;

#define SHOW_HIERARCHY (1)
#if SHOW_HIERARCHY
#define SHOW_HIERARCHY_ONLY (0)
#endif

#if SHOW_HIERARCHY
 #if !SHOW_HIERARCHY_ONLY
  const int ImageWidth = int(BufferWidth + 1+BufferWidth/2 + 1+BufferWidth/4);
 #else
  const int ImageWidth = int(1+BufferWidth/2 + 1+BufferWidth/4);
 #endif
 const int ImageHeight = BufferHeight+3;
#else
 const int ImageWidth = BufferWidth;
 const int ImageHeight = BufferHeight;
#endif
const int ImageSize = ImageWidth*ImageHeight;
static int pixel[ImageSize];
static deOccludeRasterizer occluder;

static inline EvaluatePixel(int & pixelout, DWORD pixelin)
{
	if (pixelin == 0xffffffff)
		pixelout = 0x606060;
	else
	{
		//pixelin = pow(255,(double)pixelin/0x3fffffff);
#if OCCLUDE_16BIT
		pixelin >>= 8;
#else
		pixelin >>= 24;
#endif
		//pixelin = BYTE(pow(255, pixelin/255.0));
		pixelin = 255 - pixelin;
		pixelin = BYTE(255*log(pixelin)/log(255));
		pixelout = (pixelin) | (pixelin << 8) | (pixelin << 16);
	}
}

int main()
{
	IdeProfileManager* ProfileManager = IdeProfile_GetTheManager();

	memset(pixel, 0xc0, ImageSize * sizeof(int));

	float Near, Far;
	Near = 1.0f;
	Far = 80;
	float Aspect = (float)BufferWidth/BufferHeight;
	occluder.SetFOVClipping(1.0f, Aspect, Near, Far, NULL);
	occluder.SetBufferSize(BufferWidth, BufferHeight);

	deVertex trianglelist1[] =
	{
/**/
//		{0,0,29},{-.2,-.1,1},{.2,-.2,1},	// middle, sloped
		{0,1,10},{-1,-2,10},{1,-1,10},		// middle, flat
		{0,1,10},{1,-1,10},{2,2,21.5},		// right
		{-1,-2,10},{0,1,10},{-2,2,22.5},	// left
		{1,-1,10},{-1,-2,10},{2,-6,25},		// bottom
		{-.2,.2,1},{-.2,.1,1},{-10,20,100},	// off to top left
//		{-48,37,60},{-40,-30,50},{20,15,25},	{20,15,25},{-40,-30,50},{4,-3,5},	// background
		{4,-3,5},{4,3,5},{10,3,30},	{10,3,30},{10,-3,30},{4,-3,5},	// side wall
//		{0,1.5,20},{-2,-5,40},{1,-2,20},	// behind, sloped
/**/
//		{0,.75,20},{-1,-2.5,20},{1,-2,20},	// should be occluded
//		{-3,1,10},{-.4,-.2,1},{-.2,-.1,1},	// needs to be clipped by near plane (2 behind)
//		{-.3,.1,1},{-4,-2,10},{-2,-1,10},	// needs to be clipped by near plane (1 behind)
//		{-4,-2,10},{-3,1,10},{-4,1,10},		// left
//		{-3,1,10},{-2,-1,10},{-2,1,10},		// right
	};
	deVertex Vertices_1[] = 
	{
#if 1
		{0,1,10},		// middle top
		{-1,-2,10},		// middle left
		{1,-1,10},		// middle right

		{2,2,21.5},		// right
		{-2,2,22.5},	// left
		{2,-6,25},		// bottom

		{4,-3,5},		// side 0
		{4,3,5},		// side 1
		{10,3,30},		// side 2
		{10,-3,30},		// side 3

		// off to top left
		{-.2,.2,1},
		{-.2,.1,1},
		{-10,15,100},
		{-30,15,100},

		// background
		{-8,6.1,10},
		{-40,-30,50},
		{20,15,25},
		{48,-37,60},
#else
		{-10,10,20},
		{-10,-10,20},
		{10,10,20},
		{10,-10,20},
		{0,10,10},
		{0,-10,10},
		{0,10,30},
		{0,-10,30},
#endif
	};
	WORD Indices_1[] = 
	{
#if 1
		0,1,2,	// middle, flat
		0,2,3,	// right
		1,0,4,	// left
		2,1,5,	// bottom
		6,7,8,	// side wall right top
		8,9,6,	// side wall right bottom
		10,11,12, // top left 1
		13,11,10, // top left 2
		14,15,16, // background top/left
		16,15,17, // background bottom/right
#else
		0,1,2,
		2,1,3,
		4,5,6,
		6,5,7,
#endif
	};
	deVertex trianglelist2[] =
	{
		{0,.75,20},{-1,-2.5,20},{1,-2,20},	// should be occluded
	};
	deVertex trianglelist3[] =
	{
		{0,.5,7},{-0.5,-1,7},{0.5,-.5,7},	// should not be occluded
	};
	int VisibleNum;

	deConsole_MakeConsole();
	
	long RenderID = 0;
	long ConvertID = 0;
	long MainLoopID = 0;
	long FrameNum = 0;

	occluder.SetPixelCounting(deFALSE);

	deTransform WorldMat;
	//WorldMat.Translation.z -= 10;
	occluder.SetViewTransform(WorldMat);

	if (!ptc_open("test", ImageWidth, ImageHeight)) return 1;
	while (1)
	{
		PROFILE_ID_NAME(&MainLoopID, "Main Loop");
		if (FrameNum == 100)
			ProfileManager->ResetStats();
		if (FrameNum%10 == 0)
		{
			WorldMat.Translation.x += 0.2;
			WorldMat.RotateY(-0.01);
			occluder.SetViewTransform(WorldMat);
		}
		if (FrameNum%1 == 0)
		{
			occluder.ClearBuffer();
			//occluder.RenderIndexedTriangles(deFALSE, trianglelist1, sizeof(trianglelist1)/sizeof(deVertex));
			occluder.RenderIndexedTriangles(deFALSE, Vertices_1, sizeof(Vertices_1)/sizeof(deVertex), Indices_1, sizeof(Indices_1)/sizeof(WORD));
		}
		
		VisibleNum = occluder.RenderIndexedTriangles(deTRUE, trianglelist2, sizeof(trianglelist2)/sizeof(deVertex));
		VisibleNum = occluder.RenderIndexedTriangles(deTRUE, trianglelist3, sizeof(trianglelist3)/sizeof(deVertex));
		FrameNum++;
		if (FrameNum%10 == 4)
		{
			PROFILE_ID_NAME(&ConvertID, "Image Conversion");
			const deOccludeRasterizer::BufferType * buffer = occluder.GetBuffer();
			DWORD pixval;
			int i,x,y;
#if !defined(SHOW_HIERARCHY_ONLY) || !SHOW_HIERARCHY_ONLY
			i = 0;
			for (y = 0; y < BufferHeight; ++y)
			{
				for (x = 0; x < BufferWidth; ++x)
				{
					DE_ASSERT(i < ImageSize);
					pixval = buffer[y*BufferWidth+x];
					EvaluatePixel(pixel[i], pixval);
					++i;
				}
				i += (ImageWidth-BufferWidth);
			}
#endif
#if SHOW_HIERARCHY
			int k, numbufs, accumheight, accumwidth;
			accumwidth = BufferWidth+1;
	#if SHOW_HIERARCHY_ONLY
			accumwidth = 0;
	#endif
			accumheight = 0;
			numbufs = occluder.GetBufferDepth();
			for (k = 0; k < 1; ++k)
			{
				short w,h;
				occluder.GetBufferSize(w,h,k);
				buffer = occluder.GetBuffer(k, deFALSE);
				i = accumwidth;
				for (y = 0; y < h; ++y)
				{
					for (x = 0; x < w; ++x)
					{
						DE_ASSERT(i < ImageSize);
						pixval = buffer[y*w+x];
						EvaluatePixel(pixel[i], pixval);
						++i;
					}
					i += ImageWidth;
					i -= w;
				}
	#if OCCLUDE_MINBUFFER
				buffer = occluder.GetBuffer(k, deTRUE);
				i = accumwidth + (h+1)*ImageWidth;
				for (y = 0; y < h; ++y)
				{
					for (x = 0; x < w; ++x)
					{
						DE_ASSERT(i < ImageSize);
						pixval = buffer[y*w+x];
						EvaluatePixel(pixel[i], pixval);
						++i;
					}
					i += ImageWidth;
					i -= w;
				}
	#endif // OCCLUDE_MINBUFFER
				accumwidth += w+1;
			}
			for (k = 1; k < numbufs; ++k)
			{
				short w,h;
				occluder.GetBufferSize(w,h,k);
				buffer = occluder.GetBuffer(k, deFALSE);
				i = accumwidth + accumheight*ImageWidth;
				for (y = 0; y < h; ++y)
				{
					for (x = 0; x < w; ++x)
					{
						DE_ASSERT(i < ImageSize);
						pixval = buffer[y*w+x];
						EvaluatePixel(pixel[i], pixval);
						++i;
					}
					i += ImageWidth;
					i -= w;
				}
	#if OCCLUDE_MINBUFFER
				buffer = occluder.GetBuffer(k, deTRUE);
				i = ImageWidth-w + (ImageHeight-(h+accumheight+1))*ImageWidth;
				for (y = 0; y < h; ++y)
				{
					for (x = 0; x < w; ++x)
					{
						DE_ASSERT(i < ImageSize);
						pixval = buffer[y*w+x];
						EvaluatePixel(pixel[i], pixval);
						++i;
					}
					i += ImageWidth;
					i -= w;
				}
	#endif // OCCLUDE_MINBUFFER

				accumheight += h+1;
			}
#endif
			{
				PROFILE_ID_NAME(&RenderID, "ptc_update");
				ptc_update(pixel);
			}
		}
		if (FrameNum%4 == 1)
		{
			deConsoleXY(0,0);
			deConsoleOut(ProfileManager->EndFrame(deTRUE));
		}
		else
		{
			ProfileManager->EndFrame(deFALSE);
		}
	}
}

int WINAPI WinMain(
				   HINSTANCE hInstance,  // handle to current instance
				   HINSTANCE hPrevInstance,  // handle to previous instance
				   LPSTR lpCmdLine,      // pointer to command line
				   int nCmdShow          // show state of window
				   )
{
	return main();
}
