//
// Asura_Chunk_Water.cpp
//
// Created by Richard Rice - 06/01/2005
// 
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "ChunkSystem/Asura_Chunk_Water.h"

#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Asura_TextureManagement.h"
#include "Rendering/Asura_Water.h"

#include "Rendering/Asura_PlatformRenderWater.h"

////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------**
** Asura_Chunk_WaterPacket **
**-------------------------*/

#define ASURA_CHUNK_WATERPACKET_VERSION 0

DEBUGVAR float dbg_fWaterLevelTolerance = 0.5f;
bool Asura_Chunk_WaterPacket::Process(Asura_Handle iFileHandle) const
{
	if(Version > ASURA_CHUNK_WATERPACKET_VERSION)
	{
		Asura_Assert(0,"Unrecognised version for Asura_Chunk_WaterPacket");
		return false;
	}

	Asura_Water_Packet* pxPacket = Asura_Water_System::AllocateWaterPacket();
	if(!pxPacket) return false;

	pxPacket->m_iModuleIndex = m_iModuleIndex;

	//allocate , and fill in the platform packet data
	pxPacket->m_pxPlatformPacket = new Asura_Platform_Water_Packet;
	pxPacket->m_pxPlatformPacket->SetVertexCount(m_iNumberOfVertices);

	for(int i=0;i<m_iNumberOfVertices;i++)
	{
		Asura_Chunk_WaterPacket_Vertex xVert;
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,xVert,Asura_Chunk_WaterPacket_Vertex);

		pxPacket->m_pxPlatformPacket->AddVertex(xVert.m_xPosition.x,xVert.m_xPosition.y,xVert.m_xPosition.z,
												xVert.m_fRed,xVert.m_fGreen,xVert.m_fBlue,
												xVert.m_fU,xVert.m_fV);
		if(!i)
		{
			Asura_Assert(pxPacket->m_fYPosition == Asura_Maths::LargeFloat, "Y position already initialised?");
			pxPacket->m_fYPosition = xVert.m_xPosition.y;
		}
#ifdef ASURA_ASSERT
		else
		{
			const float fDiff = Asura_Maths::Abs(pxPacket->m_fYPosition - xVert.m_xPosition.y);
			Asura_Assertf(fDiff < dbg_fWaterLevelTolerance, ("Water Packet is not level (%.2f : %.2f)", pxPacket->m_fYPosition, xVert.m_xPosition.y) );
		}
#endif
	}

	pxPacket->m_pxPlatformPacket->Close();	// You MUST close packets to flush any left over vertices !

	return true;
}

#ifdef ASURA_TOOLS
void Asura_Chunk_WaterPacket::Create(Asura_SaveBlock* pxSaveBlock,int iModuleIndex,int iNumVerts,Asura_Chunk_WaterPacket_Vertex* pxVerts)
{
	//determine size of chunk
	int iChunkSize = sizeof(Asura_Chunk_WaterPacket);
	iChunkSize += sizeof(Asura_Chunk_WaterPacket_Vertex)*iNumVerts;

	//allocate chunk
	Asura_Chunk_WaterPacket* pxChunk = (Asura_Chunk_WaterPacket*) pxSaveBlock->GetAccessPointer(iChunkSize);

	//and fill it in
	pxChunk->ID = ASURA_CHUNK_WATERPACKET;
	ASURA_CHUNK_VERIFY(pxChunk->ID, int);
	pxChunk->Size = iChunkSize;
	ASURA_CHUNK_VERIFY(pxChunk->Size, int);
	pxChunk->Version = ASURA_CHUNK_WATERPACKET_VERSION;
	ASURA_CHUNK_VERIFY(pxChunk->Version, int);
	pxChunk->Flags = 0;
	ASURA_CHUNK_VERIFY(pxChunk->Flags, int);

	pxChunk->m_iModuleIndex = iModuleIndex;
	ASURA_CHUNK_VERIFY(pxChunk->m_iModuleIndex, int);
	
	pxChunk->m_iNumberOfVertices = iNumVerts;
	ASURA_CHUNK_VERIFY(pxChunk->m_iNumberOfVertices, int);

	//output the verts
	char* pcChunkBuffer = (char*)(pxChunk+1);

	for(int i=0;i<iNumVerts;i++)
	{
		Asura_Chunk_WaterPacket_Vertex xVert = pxVerts[i];
		ASURA_CHUNK_ARRAY_VERIFY(xVert.m_xPosition,float,3);
		ASURA_CHUNK_VERIFY(xVert.m_fRed,float);
		ASURA_CHUNK_VERIFY(xVert.m_fGreen,float);
		ASURA_CHUNK_VERIFY(xVert.m_fBlue,float);
		ASURA_CHUNK_VERIFY(xVert.m_fU,float);
		ASURA_CHUNK_VERIFY(xVert.m_fV,float);

		ASURA_CHUNK_FILL(pcChunkBuffer,xVert,Asura_Chunk_WaterPacket_Vertex);
	}
	
	Asura_Assert((int)pcChunkBuffer - (int)pxChunk == iChunkSize,"Chunk size incorrect");
}
#endif //ASURA_TOOLS


////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------**
** Asura_Chunk_WaterControl **
**--------------------------*/

// Version history:
//
//     (RAR - 11.01.2005) -  0 - Initial version.
//
//     (RAR - 13.01.2005) -  1 - Added subdivision Y scale, sunlight fall-off.
//
//     (MP  - 25.01.2005) -  2 - Added UV speeds.
//
#define ASURA_CHUNK_WATERCONTROL_VERSION (3)

bool Asura_Chunk_WaterControl::Process(Asura_Handle iFileHandle) const
{
#ifndef ASURA_TOOLS
    // Don't bother dealing with obsolete chunk versions outside of tools.
    Asura_Assert( Version > 0, "Unsupported chunk version." );
#endif

	Asura_Water_System::Env_Water_Controls& xControl = Asura_Water_System::GetEnvController();
	
	ChunkData xData;
    switch( Version )
    {
#ifdef ASURA_TOOLS
        case 0:
		    ASURA_CHUNK_FILEEXTRACT( iFileHandle, xData, ChunkData_V0 );
            break;
#endif

        case 1:
		    ASURA_CHUNK_FILEEXTRACT( iFileHandle, xData, ChunkData_V1 );
            break;

        case 2:
		    ASURA_CHUNK_FILEEXTRACT( iFileHandle, xData, ChunkData_V2 );
            break;

        case ASURA_CHUNK_WATERCONTROL_VERSION:
		    ASURA_CHUNK_FILEEXTRACT( iFileHandle, xData, ChunkData );
            break;

        default:
            Asura_Assert( false, "Unsupported chunk version." );
            return false;
    }

	xControl.m_fWaterCycleScale1 = xData.m_fWaterCycleScale1;
	xControl.m_fWaterCycleScale2 = xData.m_fWaterCycleScale2;
	xControl.m_fWaterCycleScale3 = xData.m_fWaterCycleScale3;

	xControl.m_fXScale1 = xData.m_fXScale1;
	xControl.m_fXScale2 = xData.m_fXScale2;
	xControl.m_fXScale3 = xData.m_fXScale3;

	xControl.m_fZScale1 = xData.m_fZScale1;
	xControl.m_fZScale2 = xData.m_fZScale2;
	xControl.m_fZScale3 = xData.m_fZScale3;

	xControl.m_fYScale1 = xData.m_fYScale1;
	xControl.m_fYScale2 = xData.m_fYScale2;
	xControl.m_fYScale3 = xData.m_fYScale3;

	xControl.m_fFalloff1 = xData.m_fFalloff1;
	xControl.m_fFalloff2 = xData.m_fFalloff2;
	xControl.m_fFalloff3 = xData.m_fFalloff3;

	xControl.m_fThreshold = xData.m_fThreshold;

	xControl.m_fLightOffset = xData.m_fLightOffset;
	xControl.m_fLightScale = xData.m_fLightScale;

	xControl.m_fAlphaLevel = xData.m_fAlphaLevel;
	xControl.m_fSunBrightness = xData.m_fReflection;

	xControl.m_bUseLevelSun = xData.m_bUseLevelSun;
	for(int i=0;i<3;i++)
	{
		xControl.m_afSunDir[i] = xData.m_afSunDir[i];
	}

	for(int i=0;i<2;i++)
	{
		xControl.m_afTexOffset[i] = xData.m_afTexOffset[i];
		xControl.m_afTexScale[i] = xData.m_afTexScale[i];
	}

	xControl.m_uFlags = xData.m_iFlags;

	xControl.m_fHorizonVScale = xData.m_fHorizonVScale;
	xControl.m_fHorizonVOffset = xData.m_fHorizonVOffset;
	xControl.m_fHorizonYScale = xData.m_fHorizonYScale;
	xControl.m_fHorizonBrightness = xData.m_fHorizonBrightness;

#ifdef ASURA_TOOLS
	if(Version >=1)
#endif
	{
		xControl.m_fSubdivisionYScale   = xData.m_fSubdivisionYScale;
		xControl.m_fSunlightFalloffNear = xData.m_fSunlightFalloffNear;
		xControl.m_fSunlightFalloffFar  = xData.m_fSunlightFalloffFar;
	}

    if( Version >= 2 )
    {
        for( u_int u = 0; u < 2; ++u )
        {
            xControl.m_afUVSpeeds[u] = xData.m_afUVSpeeds[u];
        }
    }

    if( Version >= 3 )
	{
		xControl.m_fSunYScale           = xData.m_fSunYScale;
		xControl.m_fHorizonFresnelScale = xData.m_fHorizonFresnelScale;
	}
	else
	{
		xControl.m_fSunYScale           = 1.0f;
		xControl.m_fHorizonFresnelScale = 1.0f;
	}

    //get the texture names , and load if needed
	for(int i=0;i<3;i++)
	{
		const char* pszTextureName = Asura_FileAccess::ReadString(iFileHandle);
#ifdef ASURA_TOOLS
		xControl.m_axToolsTextureNames[i] = pszTextureName;
#endif
		if(*pszTextureName)
		{
			xControl.m_aiTextureID[i] = Asura_Texture_Management::AddTexture(pszTextureName);
		}
		else
		{
			xControl.m_aiTextureID[i] = ASURA_TEXTURE_NONE;
		}
	}

	//read/skip the template name
#ifdef ASURA_TOOLS
	xControl.m_xTemplateName =
#endif
	Asura_FileAccess::ReadString(iFileHandle);

	return true;
}

#ifdef ASURA_TOOLS
void Asura_Chunk_WaterControl::Create(Asura_SaveBlock* pxSaveBlock)
{
	const Asura_Water_System::Env_Water_Controls& xControl = Asura_Water_System::GetEnvController();

	//determine size of chunk
	int iChunkSize = sizeof(Asura_Chunk_WaterControl);
	iChunkSize += sizeof(ChunkData);
	ASURA_CHUNK_SIZE_STRING(iChunkSize,xControl.m_axToolsTextureNames[0]);
	ASURA_CHUNK_SIZE_STRING(iChunkSize,xControl.m_axToolsTextureNames[1]);
	ASURA_CHUNK_SIZE_STRING(iChunkSize,xControl.m_axToolsTextureNames[2]);
	ASURA_CHUNK_SIZE_STRING(iChunkSize,xControl.m_xTemplateName);

	//allocate chunk
	Asura_Chunk_WaterControl* pxChunk = (Asura_Chunk_WaterControl*) pxSaveBlock->GetAccessPointer(iChunkSize);

	//and fill it in
	pxChunk->ID = ASURA_CHUNK_WATERCONTROL;
	ASURA_CHUNK_VERIFY(pxChunk->ID, int);
	pxChunk->Size = iChunkSize;
	ASURA_CHUNK_VERIFY(pxChunk->Size, int);
	pxChunk->Version = ASURA_CHUNK_WATERCONTROL_VERSION;
	ASURA_CHUNK_VERIFY(pxChunk->Version, int);
	pxChunk->Flags = 0;
	ASURA_CHUNK_VERIFY(pxChunk->Flags, int);

	char* pcChunkBuffer = (char*)(pxChunk+1);

	//fill in the main chunk data
	ChunkData xData;
	
	xData.m_fWaterCycleScale1 = xControl.m_fWaterCycleScale1;
	ASURA_CHUNK_VERIFY(xData.m_fWaterCycleScale1,float);
	xData.m_fWaterCycleScale2 = xControl.m_fWaterCycleScale2;
	ASURA_CHUNK_VERIFY(xData.m_fWaterCycleScale2,float);
	xData.m_fWaterCycleScale3 = xControl.m_fWaterCycleScale3;
	ASURA_CHUNK_VERIFY(xData.m_fWaterCycleScale3,float);

	xData.m_fXScale1 = xControl.m_fXScale1;
	ASURA_CHUNK_VERIFY(xData.m_fXScale1,float);
	xData.m_fXScale2 = xControl.m_fXScale2;
	ASURA_CHUNK_VERIFY(xData.m_fXScale2,float);
	xData.m_fXScale3 = xControl.m_fXScale3;
	ASURA_CHUNK_VERIFY(xData.m_fXScale3,float);

	xData.m_fZScale1 = xControl.m_fZScale1;
	ASURA_CHUNK_VERIFY(xData.m_fZScale1,float);
	xData.m_fZScale2 = xControl.m_fZScale2;
	ASURA_CHUNK_VERIFY(xData.m_fZScale2,float);
	xData.m_fZScale3 = xControl.m_fZScale3;
	ASURA_CHUNK_VERIFY(xData.m_fZScale3,float);

	xData.m_fYScale1 = xControl.m_fYScale1;
	ASURA_CHUNK_VERIFY(xData.m_fYScale1,float);
	xData.m_fYScale2 = xControl.m_fYScale2;
	ASURA_CHUNK_VERIFY(xData.m_fYScale2,float);
	xData.m_fYScale3 = xControl.m_fYScale3;
	ASURA_CHUNK_VERIFY(xData.m_fYScale3,float);


	xData.m_fFalloff1 = xControl.m_fFalloff1;
	ASURA_CHUNK_VERIFY(xData.m_fFalloff1,float);
	xData.m_fFalloff2 = xControl.m_fFalloff2;
	ASURA_CHUNK_VERIFY(xData.m_fFalloff2,float);
	xData.m_fFalloff3 = xControl.m_fFalloff3;
	ASURA_CHUNK_VERIFY(xData.m_fFalloff3,float);

	xData.m_fThreshold = xControl.m_fThreshold;
	ASURA_CHUNK_VERIFY(xData.m_fThreshold,float);

	xData.m_fLightOffset = xControl.m_fLightOffset;
	ASURA_CHUNK_VERIFY(xData.m_fLightOffset,float);
	xData.m_fLightScale = xControl.m_fLightScale;
	ASURA_CHUNK_VERIFY(xData.m_fLightScale,float);

	xData.m_fAlphaLevel = xControl.m_fAlphaLevel;
	ASURA_CHUNK_VERIFY(xData.m_fAlphaLevel,float);
	xData.m_fReflection = xControl.m_fSunBrightness;
	ASURA_CHUNK_VERIFY(xData.m_fAlphaLevel,float);

	xData.m_bUseLevelSun = xControl.m_bUseLevelSun;
	ASURA_CHUNK_VERIFY(xData.m_bUseLevelSun,bool);

	for(int i=0;i<3;i++)
	{
		xData.m_afSunDir[i] = xControl.m_afSunDir[i];
		ASURA_CHUNK_VERIFY(xData.m_afSunDir[i],float);
	}

	for(int i=0;i<2;i++)
	{
		xData.m_afTexOffset[i] = xControl.m_afTexOffset[i];
		ASURA_CHUNK_VERIFY(xData.m_afTexOffset[i],float);

		xData.m_afTexScale[i] = xControl.m_afTexScale[i];
		ASURA_CHUNK_VERIFY(xData.m_afTexScale[i],float);
	}

	xData.m_iFlags = xControl.m_uFlags;
	ASURA_CHUNK_VERIFY(xData.m_iFlags,u_int);

	xData.m_fHorizonVScale = xControl.m_fHorizonVScale;
	ASURA_CHUNK_VERIFY(xData.m_fHorizonVScale,float);
	xData.m_fHorizonVOffset = xControl.m_fHorizonVOffset;
	ASURA_CHUNK_VERIFY(xData.m_fHorizonVOffset,float);
 	xData.m_fHorizonYScale = xControl.m_fHorizonYScale;
	ASURA_CHUNK_VERIFY(xData.m_fHorizonYScale,float);
	xData.m_fHorizonBrightness = xControl.m_fHorizonBrightness;
	ASURA_CHUNK_VERIFY(xData.m_fHorizonBrightness,float);

	xData.m_fSubdivisionYScale = xControl.m_fSubdivisionYScale;
	ASURA_CHUNK_VERIFY(xData.m_fSubdivisionYScale,float);
	xData.m_fSunlightFalloffNear = xControl.m_fSunlightFalloffNear;
	ASURA_CHUNK_VERIFY(xData.m_fSunlightFalloffNear,float);
	xData.m_fSunlightFalloffFar = xControl.m_fSunlightFalloffFar;
	ASURA_CHUNK_VERIFY(xData.m_fSunlightFalloffFar,float);

    for( u_int u = 0; u < 2; ++u )
    {
        xData.m_afUVSpeeds[u] = xControl.m_afUVSpeeds[u];
        ASURA_CHUNK_VERIFY( xData.m_afUVSpeeds[u], float );
    }

	xData.m_fSunYScale           = xControl.m_fSunYScale;
	ASURA_CHUNK_VERIFY(xData.m_fSunYScale,float);
	xData.m_fHorizonFresnelScale = xControl.m_fHorizonFresnelScale;
	ASURA_CHUNK_VERIFY(xData.m_fHorizonFresnelScale,float);

	ASURA_CHUNK_FILL(pcChunkBuffer,xData,ChunkData);

	//output the various strings
	for(int i=0;i<3;i++)
	{
		ASURA_CHUNK_FILL_STRING(pcChunkBuffer,xControl.m_axToolsTextureNames[i])
	}
	ASURA_CHUNK_FILL_STRING(pcChunkBuffer,xControl.m_xTemplateName);

	Asura_Assert((int)pcChunkBuffer - (int)pxChunk == iChunkSize,"Chunk size incorrect");

}
#endif //ASURA_TOOLS



