// Tools_PSP_VertexFormat.h
//
// Created by SB - 18/01/2007
// Values should match PSP libgu.h
//
// Copyright (C) 2007 Rebellion (Derby), All Rights Reserved.

#ifdef ASURA_USE_PRAGMA_ONCE
# pragma once
#endif

#ifndef __ASURA_PSP_VERTEXFORMAT_H__
#define __ASURA_PSP_VERTEXFORMAT_H__

// Duplicates of SCEGU #defines for Tools

#define ASURA_SCEGU_TEXTURE_NONE		( 0 <<  0 )
#define ASURA_SCEGU_TEXTURE_UBYTE		( 1 <<  0 )
#define ASURA_SCEGU_TEXTURE_USHORT		( 2 <<  0 )
#define ASURA_SCEGU_TEXTURE_FLOAT		( 3 <<  0 )

#define ASURA_SCEGU_COLOR_NONE			( 0 <<  2 )
#define ASURA_SCEGU_COLOR_PF5650		( 4 <<  2 )
#define ASURA_SCEGU_COLOR_PF5551		( 5 <<  2 )
#define ASURA_SCEGU_COLOR_PF4444		( 6 <<  2 )
#define ASURA_SCEGU_COLOR_PF8888		( 7 <<  2 )

#define ASURA_SCEGU_NORMAL_NONE			( 0 <<  5 )
#define ASURA_SCEGU_NORMAL_BYTE			( 1 <<  5 )
#define ASURA_SCEGU_NORMAL_SHORT		( 2 <<  5 )
#define ASURA_SCEGU_NORMAL_FLOAT		( 3 <<  5 )

#define ASURA_SCEGU_VERTEX_NONE			( 0 <<  7 )
#define ASURA_SCEGU_VERTEX_BYTE			( 1 <<  7 )
#define ASURA_SCEGU_VERTEX_SHORT		( 2 <<  7 )
#define ASURA_SCEGU_VERTEX_FLOAT		( 3 <<  7 )

#ifndef ASURA_TOOLS

#include "Rendering/Asura_PSP_GU.h"

ASURA_STATIC_ASSERT(ASURA_SCEGU_TEXTURE_NONE == SCEGU_TEXTURE_NONE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_TEXTURE_UBYTE == SCEGU_TEXTURE_UBYTE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_TEXTURE_USHORT == SCEGU_TEXTURE_USHORT);
ASURA_STATIC_ASSERT(ASURA_SCEGU_TEXTURE_FLOAT == SCEGU_TEXTURE_FLOAT);

ASURA_STATIC_ASSERT(ASURA_SCEGU_COLOR_NONE == SCEGU_COLOR_NONE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_COLOR_PF5650 == SCEGU_COLOR_PF5650);
ASURA_STATIC_ASSERT(ASURA_SCEGU_COLOR_PF5551 == SCEGU_COLOR_PF5551);
ASURA_STATIC_ASSERT(ASURA_SCEGU_COLOR_PF4444 == SCEGU_COLOR_PF4444);
ASURA_STATIC_ASSERT(ASURA_SCEGU_COLOR_PF8888 == SCEGU_COLOR_PF8888);

ASURA_STATIC_ASSERT(ASURA_SCEGU_NORMAL_NONE == SCEGU_NORMAL_NONE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_NORMAL_BYTE == SCEGU_NORMAL_BYTE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_NORMAL_SHORT == SCEGU_NORMAL_SHORT);
ASURA_STATIC_ASSERT(ASURA_SCEGU_NORMAL_FLOAT == SCEGU_NORMAL_FLOAT);

ASURA_STATIC_ASSERT(ASURA_SCEGU_VERTEX_NONE == SCEGU_VERTEX_NONE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_VERTEX_BYTE == SCEGU_VERTEX_BYTE);
ASURA_STATIC_ASSERT(ASURA_SCEGU_VERTEX_SHORT == SCEGU_VERTEX_SHORT);
ASURA_STATIC_ASSERT(ASURA_SCEGU_VERTEX_FLOAT == SCEGU_VERTEX_FLOAT);

#endif

// Masks for easy checking of SCE #defines

#define ASURA_SCEGU_TEXTURE_MASK		(0x03)
#define ASURA_SCEGU_COLOR_MASK			(0x1c)
#define ASURA_SCEGU_NORMAL_MASK			(0x60)
#define ASURA_SCEGU_VERTEX_MASK			(0x0180)

// Vertex structures
 struct Asura_PSP_Default_Vertex
{
	// (SB - 22/01/07) Default format with 16 bit colour and short normals
	u_short			m_usU;				// 2	2
	u_short			m_usV;				// 2	4
	short			m_usRGB565;			// 2	6
	short			m_asNormal[3];		// 6	12
	float			m_afPosition[3];	// 12	24
};

struct Asura_PSP_SecondPass_Vertex
{
	// (SB - 22/01/07) Default format with 16 bit colour and short normals
	u_short			m_usU;				// 2	2
	u_short			m_usV;				// 2	4
	short			m_usRGBA4444;		// 2	6
	short			m_asNormal[3];		// 6	12
	float			m_afPosition[3];	// 12	24
};

struct Asura_PSP_RGBA8888NoNormal_Vertex
{
	// (SB - 22/01/07) Format with no 32 bit colour and no normal
	u_short			m_usU;				// 2	2
	u_short			m_usV;				// 2	4
	int				m_uRGBA8888;		// 4	8
	float			m_afPosition[3];	// 12	20
};

// Vertex format management/conversion helper class

class Asura_PSP_VertexFormat
{
public:
	class ShortVector3
	{
	public:
		short x, y, z;
	};
	
	class ShortVector2
	{
	public:
		short x, y;
	};

	static unsigned int CalculateVertexSize(const unsigned short usVertexFormat);

	static unsigned int GetSizeOfTexCoord(const unsigned short usVertexFormat);
	static unsigned int GetSizeOfColour(const unsigned short usVertexFormat);
	static unsigned int GetSizeOfNormalComponent(const unsigned short usVertexFormat);
	static unsigned int GetSizeOfVertexComponent(const unsigned short usVertexFormat);

	static ShortVector2& GetTexCoordsFromVertex(const unsigned char* pucVertex, const unsigned short usVertexFormat);
	static int GetColourFromVertex(const unsigned char* pucVertex, const unsigned short usVertexFormat);
	static ShortVector3& GetNormalFromVertex(const unsigned char* pucVertex, const unsigned short usVertexFormat);
	static Asura_Vector_3& GetPositionFromVertex(const unsigned char* pucVertex, const unsigned short usVertexFormat);
	static Asura_Vector_3& GetPositionFromVertex(const unsigned char* pucVertex, const unsigned short usVertexFormat, const size_t xVertexPosOffset);

	static void SetColourInVertex(unsigned char* pucVertex, const unsigned int uColour, const unsigned short usVertexFormat);

	static void ConvertTexcoordToSpecifiedFormat(unsigned char* pucOut, float fCoord, const unsigned short usVertexFormat);
	static void ConvertVertexColourToSpecifiedFormat(unsigned char* pucOut, unsigned int uInput, const unsigned short usVertexFormat);
	static void ConvertNormalComponentToSpecifiedFormat(unsigned char* pucOut, float fComponent, const unsigned short usVertexFormat);
	static void ConvertVertexComponentToSpecifiedFormat(unsigned char* pucOut, float fComponent, const unsigned short usVertexFormat);

	static inline bool PositionsAreEqual(const unsigned char* pucFirst, const unsigned char* pucSecond, const unsigned short usVertexFormat)
	{
		const size_t xVertexPosOffset = GetSizeOfTexCoord(usVertexFormat) * 2 + GetSizeOfColour(usVertexFormat) + GetSizeOfNormalComponent(usVertexFormat) * 3;
		const size_t xVertexPosComponentSize = GetSizeOfVertexComponent(usVertexFormat);
		return PositionsAreEqual(pucFirst, pucSecond, xVertexPosOffset, xVertexPosComponentSize);
	}
	static bool PositionsAreEqual(const unsigned char* pucFirst, const unsigned char* pucSecond, const size_t xVertexPosOffset, const size_t xVertexPosComponentSize);
};

#endif