
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_Platform_ScreenShot_System.cpp
// Author : Andy Tate
// Date   : 8-Sep-2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

#if defined(ASURA_USE_SCREENSHOT_SYSTEM)

// This file's header...
#include "Debugging/Asura_ScreenShot_System.h"

// Asura independent header-files...
#include "Core/Asura_Stream.h"
#include "Rendering/Asura_Render.h"

#include "Debugging/Asura_Logfile.h"

// Asura platform header-files...
#include "Rendering/Asura_PS3_Graphics.h"
#include "Rendering/Asura_PS3_TextureManagement.h"
#include "Rendering/Asura_PS3_Framebuffer.h"

#include "Core/Asura_HalfFloat.h"


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_RenderProgressBar
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_RenderProgressBar (const Asura_Vector_2& xPosition,
														  const Asura_Vector_2& xSize,
														  const u_int uARGB)
{
}

/// End of function 'Asura_ScreenShot_System::Platform_RenderProgressBar'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_GetScreenDimensions
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : Get the dimensions and format of the screen.
//
// Parameters   : Addresses of the position, size and format to be stored,
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_GetScreenDimensions (Asura_IntVector_2* pxPosition,
															Asura_IntVector_2* pxSize,
															u_int* puFormat)
{
	// Do we need to get the position?
	if (NULL != pxPosition)
	{
		// Yes - do so...
		pxPosition->iX	= 0;
		pxPosition->iY	= 0;
	}

	// Do we need to get the size?
	if (NULL != pxSize)
	{
		// Yes - do so...
		pxSize->iX	= Asura_PS3_Graphics::GetOutputWidth();
		pxSize->iY	= Asura_PS3_Graphics::GetOutputHeight();
	}

	// Do we need to get the bit-depth?
	if (NULL != puFormat)
	{
		// Decide upon the bit-depth...
		*puFormat	= Asura_PS3_Graphics::GetScreenFormat ();
	}
}

/// End of function 'Asura_ScreenShot_System::Platform_GetScreenDimensions'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_WriteScreenAs24Bit
// Author       : Ben Rowland
// Date         : 07 / 08 / 07
//
// Description  : Write the current screen to the specified stream.
//
// Parameters   : The stream to write to, the position and size of the data to
//				  be written and the data format to be read.
//
// Return value : None.
//
// Notes		: Currently this function is only compatible with a 64 bit 
//				  framebuffer texture, with 16 bit floating point RGBA channels,
//				  and 32 bit using 8 bit unsigned char ARGB channels. If the framebuffer
//				  uses a different pixel format then you will have to add an alternate
//				  case in the if statement
//
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_WriteScreenAs24Bit (Asura_Stream& xStream,
														   const Asura_IntVector_2& xPosition,
														   const Asura_IntVector_2& xSize,
														   const u_int uFormat)
{
	const int	iWidth			= xSize.iX;
	const int	iHeight			= xSize.iY;
	const u_int	uTotalNumBytes	= iWidth * 3 * iHeight;
	
	u_char*		pucOutputBuffer	= new u_char [uTotalNumBytes];
	u_char*		pucDest			= pucOutputBuffer;

	if (!pucOutputBuffer)
	{
		return;
	}
	// get the framebuffer, then get the render target as a texture
	Asura_PS3_Texture* xRenderTarget = Asura_PS3_DeferredRendering::GetOutputBuffer()->GetRTAsTexture(ASURA_RENDER_TARGET_CURRENT_FRONT_BUFFER);

	// we can use this texture to get the raw data, but first we need to know how big that data is
	const CellGcmTexture* xCellTexture = xRenderTarget->GetTexture();
	const u_int uFrameBufferWidth = (xCellTexture->width + 255) & ~255;

	// check the data is in the right format
	if( (xCellTexture->format & CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT) == CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT )
	{
		// data is coming in in 16 bit channels, so read it in as half floats
		Asura_HalfFloat* puSource = static_cast<Asura_HalfFloat*>(xRenderTarget->GetTextureData() );

		// bitmap format has y going in the opposite direction, so we have to start with the bottom row and work up
		// go to bottom left hand corner of specified rectangle
		puSource += (uFrameBufferWidth * (xPosition.iY+xSize.iY) + xPosition.iX) * 4;

		// we need to convert the data into char format for the bitmap
		char red=0;
		char green=0;
		char blue=0;
		// read in the data, one line at a time
		for( int y = 0; y < iHeight; y += 1 )
		{
			// process each pixel
			for( int x = 0; x < iWidth; x++ )
			{
				// within each pixel we have to read in the four half floats,
				// PS3 seems to give weird ranges for buffer, so
				// if the value is larger than 1 we clamp to 1
				float fRed = (float) *(puSource++);
				if(fRed>1.0f)
					fRed=1.0f;
				red = static_cast<u_char>( fRed * 255 );
				float fGreen = (float) *(puSource++);
				if(fGreen>1.0f)
					fGreen=1.0f;
				green = static_cast<u_char>( fGreen * 255 );
				float fBlue = (float) *(puSource++);
				if(fBlue>1.0f)
					fBlue=1.0f;
				blue = static_cast<u_char>( fBlue * 255 );
				// we don't want the alpha so skip over it
				puSource++;
			
				*(pucDest++) = blue;
				*(pucDest++) = green;
				*(pucDest++) = red;
			}
			// move back to the left hand side of the next row up
			puSource -= (uFrameBufferWidth + iWidth) * 4;
		}
			
	}
	else if( ( xCellTexture->format & CELL_GCM_TEXTURE_A8R8G8B8) == CELL_GCM_TEXTURE_A8R8G8B8 )
	{
		// data is coming in in 8 bit channels, so read it in as unsigned chars
		unsigned char* puSource = static_cast<unsigned char*>(xRenderTarget->GetTextureData() );

		// bitmap format has y going in the opposite direction, so we have to start with the bottom row and work up
		// go to bottom left hand corner of specified rectangle
		puSource += (uFrameBufferWidth * (xPosition.iY+xSize.iY) + xPosition.iX) * 4;

		// we need to convert the data into char format for the bitmap
		unsigned char red=0;
		unsigned char green=0;
		unsigned char blue=0;
		// read in the data, one line at a time
		for( int y = 0; y < iHeight; y += 1 )
		{
			// process each pixel
			for( int x = 0; x < iWidth; x++ )
			{
				// alpha channel is first so just ignore that
				puSource++;
				// read in the rgb values
				red = *(puSource++);
				green = *(puSource++);
				blue = *(puSource++);
				
				// put them in the buffer
				*(pucDest++) = blue;
				*(pucDest++) = green;
				*(pucDest++) = red;
			}
			// move back to the left hand side of the next row up
			puSource -= (uFrameBufferWidth + iWidth) * 4;
		}
	}
	else
	{
		Asura_Assert( 0 , "This texture format is not currently supported" );
	}

	// Write all of the data in one go...
	xStream.WriteData	(uTotalNumBytes, pucOutputBuffer);

	// Free-up the memory...
	delete []	(pucOutputBuffer);
}

/// End of function 'Asura_ScreenShot_System::Platform_WriteScreenAs24Bit'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_AddScreenToFPBuffer
// Author       : Ben Rowland
// Date         : 07 / 08 / 07
//
// Description  : Currently this function is only compatible with a 64 bit 
//				  framebuffer texture, with 16 bit floating point RGBA channels,
//				  and 32 bit using 8 bit unsigned char ARGB channels. If the framebuffer
//				  uses a different pixel format then you will have to add an alternate
//				  case in the if statement
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_AddScreenToFPBuffer (const Asura_IntVector_2& xPosition,
															const Asura_IntVector_2& xSize,
															const u_int uFormat,
															float* pfFPBuffer)
{
	const int	iWidth			= xSize.iX;
	const int	iHeight			= xSize.iY;
	//const u_int	uTotalNumBytes	= iWidth * 3 * iHeight;

	// get the framebuffer, then get the render target as a texture
	Asura_PS3_Texture* xRenderTarget = Asura_PS3_DeferredRendering::GetOutputBuffer()->GetRTAsTexture(ASURA_RENDER_TARGET_CURRENT_FRONT_BUFFER);

	// we can use this texture to get the raw data, but first we need to know how big that data is
	const CellGcmTexture* xCellTexture = xRenderTarget->GetTexture();
	const u_int uFrameBufferWidth = (xCellTexture->width + 255) & ~255;

	// check the data is in the right format
	if( (xCellTexture->format & CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT) == CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT )
	{
		// data is coming in in 16 bit channels
		Asura_HalfFloat* puSource = static_cast<Asura_HalfFloat*>(xRenderTarget->GetTextureData() );	
		
		// bitmap format has y going in the opposite direction, so we have to start with the bottom row and work up
		// go to xPosition
		puSource += (uFrameBufferWidth * (xPosition.iY+xSize.iY) + xPosition.iX) * 4;

		// read in the data, one line at a time
		for( int y = 0; y < iHeight; y += 1 )
		{
			for( int x = 0; x < iWidth; x++ )
			{
				// first of all we have to read in the half floats
				// if the value is larger than one we clamp to 1
				float fRed = (float) *(puSource++);
				if(fRed>1.0f)
					fRed=1.0f;
				float fGreen = (float) *(puSource++);
				if(fGreen>1.0f)
					fGreen=1.0f;
				float fBlue = (float) *(puSource++);
				if(fBlue>1.0f)
					fBlue=1.0f;
				// don't need alpha so just skip it instead
				puSource++;
			
				*(pfFPBuffer++) += fBlue*255.0f;
				*(pfFPBuffer++) += fGreen*255.0f;
				*(pfFPBuffer++) += fRed*255.0f;
			}
			puSource -= (uFrameBufferWidth + iWidth) * 4;
		}
			
	}
	else if( ( xCellTexture->format & CELL_GCM_TEXTURE_A8R8G8B8) == CELL_GCM_TEXTURE_A8R8G8B8 )
	{
		// data is coming in in 8 bit channels, so read it in as unsigned chars
		unsigned char* puSource = static_cast<unsigned char*>(xRenderTarget->GetTextureData() );

		// bitmap format has y going in the opposite direction, so we have to start with the bottom row and work up
		// go to bottom left hand corner of specified rectangle
		puSource += (uFrameBufferWidth * (xPosition.iY+xSize.iY) + xPosition.iX) * 4;

		// we need to convert the data into char format for the bitmap
		unsigned char red=0;
		unsigned char green=0;
		unsigned char blue=0;
		// read in the data, one line at a time
		for( int y = 0; y < iHeight; y += 1 )
		{
			// process each pixel
			for( int x = 0; x < iWidth; x++ )
			{
				// alpha channel is first so just ignore that
				puSource++;
				// read in the rgb values
				red = *(puSource++);
				green = *(puSource++);
				blue = *(puSource++);
				
				// put them in the buffer
				*(pfFPBuffer++) += blue;
				*(pfFPBuffer++) += green;
				*(pfFPBuffer++) += red;
			}
			// move back to the left hand side of the next row up
			puSource -= (uFrameBufferWidth + iWidth) * 4;
		}
	}
	else
	{
		Asura_Assert( 0 , "This texture format is not currently supported" );
	}
}

/// End of function 'Asura_ScreenShot_System::Platform_AddScreenToFPBuffer'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_BeginHiResRender
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_BeginHiResRender (void)
{
}

/// End of function 'Asura_ScreenShot_System::Platform_BeginHiResRender'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_EndHiResRender
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_EndHiResRender (void)
{
}

/// End of function 'Asura_ScreenShot_System::Platform_EndHiResRender'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_TakeScreenShot
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : Takes a lo-res screenshot and saves it as a .bmp in the
//				  specified file.
//
// Parameters   : The name of the file to be saved.
//
// Return value : 0 if failed, 1 if successful.
////////////////////////////////////////////////////////////////////////////////

int Asura_ScreenShot_System::Platform_TakeScreenShot (const char* szFilename)
{
	Asura_IntVector_2	xScreenPosition;
	Asura_IntVector_2	xScreenSize;
	u_int				uScreenFormat;

	// Take the normal screen-shot as a BMP...
	Platform_GetScreenDimensions	(&xScreenPosition, &xScreenSize, &uScreenFormat);
	return							(BMPTakeScreenShot(szFilename,  xScreenPosition, xScreenSize, uScreenFormat));
}

/// End of function 'Asura_ScreenShot_System::Platform_TakeScreenShot'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_NotTakingScreenShot
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_NotTakingScreenShot (void)
{
}

/// End of function 'Asura_ScreenShot_System::Platform_NotTakingScreenShot'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_AllocateFloatBuffer
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : Allocates a floating-point buffer.
//
// Parameters   : The number of floating-point values to allocate.
//
// Return value : A pointer to the buffer allocated.
////////////////////////////////////////////////////////////////////////////////

float* Asura_ScreenShot_System::Platform_AllocateFloatBuffer (u_int uNumFloats)
{
	return	(new float [uNumFloats]);
}

/// End of function 'Asura_ScreenShot_System::Platform_AllocateFloatBuffer'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_FreeFloatBuffer
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : Frees the floating-point buffer previously allocated.
//
// Parameters   : A pointer to the buffer to be deleted.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_FreeFloatBuffer (float* pfBuffer)
{
	delete []	(pfBuffer);
}

/// End of function 'Asura_ScreenShot_System::Platform_FreeFloatBuffer'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ScreenShot_System::Platform_RenderPrompt
// Author       : Andy Tate
// Date         : 8-Sep-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ScreenShot_System::Platform_RenderPrompt (void)
{
}

/// End of function 'Asura_ScreenShot_System::Platform_RenderPrompt'. ///

#endif // #ifdef ASURA_USE_SCREENSHOT_SYSTEM


/// End of file. ///
