// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h


#ifndef __S_4D_VERTEX_H_INCLUDED__
#define __S_4D_VERTEX_H_INCLUDED__

#include "SoftwareDriver2_compile_config.h"
#include "SoftwareDriver2_helper.h"
#include "irrAllocator.h"
#include "EPrimitiveTypes.h"

namespace irr
{

namespace video
{

//! sVec2 used in BurningShader texture coordinates
struct sVec2
{
	f32 x;
	f32 y;

	sVec2 () {}

	sVec2 ( f32 s) : x ( s ), y ( s ) {}
	sVec2 ( f32 _x, f32 _y )
		: x ( _x ), y ( _y ) {}

	void set ( f32 _x, f32 _y )
	{
		x = _x;
		y = _y;
	}

	// f = a * t + b * ( 1 - t )
	void interpolate(const sVec2& burning_restrict a, const sVec2& burning_restrict b, const ipoltype t)
	{
		x = (f32)(b.x + ( ( a.x - b.x ) * t ));
		y = (f32)(b.y + ( ( a.y - b.y ) * t ));
	}

	sVec2 operator-(const sVec2& other) const
	{
		return sVec2(x - other.x, y - other.y);
	}

	sVec2 operator+(const sVec2& other) const
	{
		return sVec2(x + other.x, y + other.y);
	}

	void operator+=(const sVec2& other)
	{
		x += other.x;
		y += other.y;
	}

	sVec2 operator*(const f32 s) const
	{
		return sVec2(x * s , y * s);
	}

	void operator*=( const f32 s)
	{
		x *= s;
		y *= s;
	}

	void operator=(const sVec2& other)
	{
		x = other.x;
		y = other.y;
	}

};

#include "irrpack.h"

//! sVec2Pack is Irrlicht S3DVertex,S3DVertex2TCoords,S3DVertexTangents Texutre Coordinates.
// Start address is not 4 byte aligned
struct sVec2Pack
{
	f32 x, y;
};

//! sVec3Pack used in BurningShader, packed direction
struct sVec3Pack
{
	f32 x, y, z;
	//f32 _can_pack;

	sVec3Pack() {}
	sVec3Pack(f32 _x, f32 _y, f32 _z)
		: x(_x), y(_y), z(_z) {}

	// f = a * t + b * ( 1 - t )
	void interpolate(const sVec3Pack& burning_restrict v0, const sVec3Pack& burning_restrict v1, const ipoltype t)
	{
		x = (f32)(v1.x + ((v0.x - v1.x) * t));
		y = (f32)(v1.y + ((v0.y - v1.y) * t));
		z = (f32)(v1.z + ((v0.z - v1.z) * t));
	}

	sVec3Pack operator-(const sVec3Pack& other) const
	{
		return sVec3Pack(x - other.x, y - other.y, z - other.z);
	}

	sVec3Pack operator+(const sVec3Pack& other) const
	{
		return sVec3Pack(x + other.x, y + other.y, z + other.z);
	}

	sVec3Pack operator*(const f32 s) const
	{
		return sVec3Pack(x * s, y * s, z * s);
	}

	void operator+=(const sVec3Pack& other)
	{
		x += other.x;
		y += other.y;
		z += other.z;
	}

	void operator=(const sVec3Pack& other)
	{
		x = other.x;
		y = other.y;
		z = other.z;
	}

}  PACK_STRUCT;

#include "irrunpack.h"

//! sVec4 used in Driver,BurningShader, direction/color
struct sVec4
{
	union
	{
		struct { f32 x, y, z, w; };
		struct { f32 a, r, g, b; };
	};

	sVec4 () {}
	sVec4 ( f32 _x, f32 _y, f32 _z, f32 _w )
		: x ( _x ), y ( _y ), z( _z ), w ( _w ){}

	// f = a * t + b * ( 1 - t )
	void interpolate(const sVec4& burning_restrict a, const sVec4& burning_restrict b, const ipoltype t)
	{
		x = (f32)(b.x + ( ( a.x - b.x ) * t ));
		y = (f32)(b.y + ( ( a.y - b.y ) * t ));
		z = (f32)(b.z + ( ( a.z - b.z ) * t ));
		w = (f32)(b.w + ( ( a.w - b.w ) * t ));
	}

	sVec4 operator-(const sVec4& other) const
	{
		return sVec4(x - other.x, y - other.y, z - other.z,w - other.w);
	}

	sVec4 operator+(const sVec4& other) const
	{
		return sVec4(x + other.x, y + other.y, z + other.z,w + other.w);
	}

	void operator+=(const sVec4& other)
	{
		x += other.x;
		y += other.y;
		z += other.z;
		w += other.w;
	}

	sVec4 operator*(const f32 s) const
	{
		return sVec4(x * s , y * s, z * s,w * s);
	}

	sVec4 operator*(const sVec4 &other) const
	{
		return sVec4(x * other.x , y * other.y, z * other.z,w * other.w);
	}

	void operator*=(const sVec4 &other)
	{
		x *= other.x;
		y *= other.y;
		z *= other.z;
		w *= other.w;
	}

	void operator=(const sVec4& other)
	{
		x = other.x;
		y = other.y;
		z = other.z;
		w = other.w;
	}

	//outside shader
	void set(f32 _x, f32 _y, f32 _z, f32 _w)
	{
		x = _x;
		y = _y;
		z = _z;
		w = _w;
	}
	void setA8R8G8B8(const u32 argb)
	{
		a = ((argb & 0xFF000000) >> 24) * (1.f / 255.f);
		r = ((argb & 0x00FF0000) >> 16) * (1.f / 255.f);
		g = ((argb & 0x0000FF00) >> 8 ) * (1.f / 255.f);
		b = ((argb & 0x000000FF)      ) * (1.f / 255.f);
	}

	REALINLINE ipoltype dot_xyzw(const sVec4& other) const
	{
		return (ipoltype)x * other.x + (ipoltype)y * other.y + (ipoltype)z * other.z + (ipoltype)w * other.w;
	}

	REALINLINE f32 dot_xyz(const sVec4& other) const
	{
		return x * other.x + y * other.y + z * other.z;
	}

	REALINLINE f32 dot_minus_xyz(const sVec4& other) const
	{
		return -x * other.x + -y * other.y + -z * other.z;
	}

	void mul_xyz(const f32 s)
	{
		x *= s;
		y *= s;
		z *= s;
	}

	f32 length_xyz() const
	{
		return sqrtf(x * x + y * y + z * z);
	}

	void normalize_dir_xyz()
	{
		//const f32 l = core::reciprocal_squareroot(x * x + y * y + z * z);
		f32 l = x * x + y * y + z * z;
		l = l > 0.0000001f ? 1.f / sqrtf(l) : 1.f;
		x *= l;
		y *= l;
		z *= l;
	}


	//unpack sVec3 to aligned during runtime
	sVec4(const sVec3Pack& other)
	{
		x = other.x;
		y = other.y;
		z = other.z;
		w = 0.f;
	}

	void normalize_pack_xyz(sVec3Pack& out, const f32 len, const f32 ofs) const
	{
		//const f32 l = len * core::reciprocal_squareroot ( r * r + g * g + b * b );
		f32 l = x * x + y * y + z * z;

		l = l > 0.0000001f ? len / sqrtf(l) : 0.f;
		out.x = (x*l) + ofs;
		out.y = (y*l) + ofs;
		out.z = (z*l) + ofs;
	}

};

//!during runtime sVec3Pack
typedef sVec4 sVec3Pack_unpack;

//!sVec4 is argb. sVec3Color is rgba
struct sVec3Color
{
	f32 r, g, b,a;

	void set(const f32 s)
	{
		r = s;
		g = s;
		b = s;
		a = s;
	}

	void setA8R8G8B8(const u32 argb)
	{
		r = ((argb & 0x00FF0000) >> 16) * (1.f / 255.f);
		g = ((argb & 0x0000FF00) >> 8 ) * (1.f / 255.f);
		b = ((argb & 0x000000FF)      ) * (1.f / 255.f);
		a = ((argb & 0xFF000000) >> 24) * (1.f / 255.f);
	}

	void setColorf(const video::SColorf & color)
	{
		r = color.r;
		g = color.g;
		b = color.b;
		a = color.a;
	}

	void add_rgb(const sVec3Color& other)
	{
		r += other.r;
		g += other.g;
		b += other.b;
	}

	void mad_rgb(const sVec3Color& other, const f32 v)
	{
		r += other.r * v;
		g += other.g * v;
		b += other.b * v;
	}

	void mad_rgbv(const sVec3Color& v0, const sVec3Color& v1)
	{
		r += v0.r * v1.r;
		g += v0.g * v1.g;
		b += v0.b * v1.b;
	}

	//sVec4 is a,r,g,b, alpha pass
	void sat(sVec4 &dest, const u32 argb) const
	{
		dest.a = ((argb & 0xFF000000) >> 24) * (1.f / 255.f);
		dest.r = r <= 1.f ? r : 1.f;
		dest.g = g <= 1.f ? g : 1.f;
		dest.b = b <= 1.f ? b : 1.f;
	}

	void sat_xyz(sVec3Pack &dest, const sVec3Color& v1) const
	{
		f32 v;
		v = r * v1.r;	dest.x = v < 1.f ? v : 1.f;
		v = g * v1.g;	dest.y = v < 1.f ? v : 1.f;
		v = b * v1.b;	dest.z = v < 1.f ? v : 1.f;
	}

	void sat_xyz(sVec4 &dest, const sVec3Color& v1) const
	{
		f32 v;
		dest.a = 1.f;
		v = r * v1.r;	dest.r = v < 1.f ? v : 1.f;
		v = g * v1.g;	dest.g = v < 1.f ? v : 1.f;
		v = b * v1.b;	dest.b = v < 1.f ? v : 1.f;
	}


};

//internal BurningShaderFlag for a Vertex
enum e4DVertexFlag
{
	VERTEX4D_CLIPMASK				= 0x0000003F,
	VERTEX4D_CLIP_NEAR				= 0x00000001,
	VERTEX4D_CLIP_FAR				= 0x00000002,
	VERTEX4D_CLIP_LEFT				= 0x00000004,
	VERTEX4D_CLIP_RIGHT				= 0x00000008,
	VERTEX4D_CLIP_BOTTOM			= 0x00000010,
	VERTEX4D_CLIP_TOP				= 0x00000020,
	VERTEX4D_INSIDE					= 0x0000003F,

	VERTEX4D_PROJECTED				= 0x00000100,
	VERTEX4D_VAL_ZERO				= 0x00000200,
	VERTEX4D_VAL_ONE				= 0x00000400,

	VERTEX4D_FORMAT_MASK			= 0xFFFF0000,

	VERTEX4D_FORMAT_MASK_TEXTURE	= 0x000F0000,
	VERTEX4D_FORMAT_TEXTURE_1		= 0x00010000,
	VERTEX4D_FORMAT_TEXTURE_2		= 0x00020000,
	VERTEX4D_FORMAT_TEXTURE_3		= 0x00030000,
	VERTEX4D_FORMAT_TEXTURE_4		= 0x00040000,

	VERTEX4D_FORMAT_MASK_COLOR		= 0x00F00000,
	VERTEX4D_FORMAT_COLOR_1			= 0x00100000,
	VERTEX4D_FORMAT_COLOR_2_FOG		= 0x00200000,
	VERTEX4D_FORMAT_COLOR_3			= 0x00300000,
	VERTEX4D_FORMAT_COLOR_4			= 0x00400000,

	VERTEX4D_FORMAT_MASK_LIGHT		= 0x0F000000,
	VERTEX4D_FORMAT_LIGHT_1			= 0x01000000,
	VERTEX4D_FORMAT_LIGHT_2			= 0x02000000,

	VERTEX4D_FORMAT_MASK_TANGENT	= 0xF0000000,
	VERTEX4D_FORMAT_BUMP_DOT3		= 0x10000000,
	VERTEX4D_FORMAT_SPECULAR		= 0x20000000,

};

//! vertex layout
enum e4DVertexType
{
	E4VT_STANDARD = 0,			// EVT_STANDARD, video::S3DVertex.
	E4VT_2TCOORDS = 1,			// EVT_2TCOORDS, video::S3DVertex2TCoords.
	E4VT_TANGENTS = 2,			// EVT_TANGENTS, video::S3DVertexTangents
	E4VT_REFLECTION_MAP = 3,
	E4VT_SHADOW = 4,			// float * 3
	E4VT_NO_TEXTURE = 5,		// runtime if texture missing
	E4VT_LINE = 6,

	E4VT_COUNT
};

enum e4DIndexType
{
	E4IT_16BIT = 1, // EIT_16BIT,
	E4IT_32BIT = 2, // EIT_32BIT,
	E4IT_NONE  = 4, //
};

#ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL
	#define BURNING_MATERIAL_MAX_TEXTURES 4
	#define BURNING_MATERIAL_MAX_COLORS 4
	#define BURNING_MATERIAL_MAX_LIGHT_TANGENT 1

	//ensure handcrafted sizeof(s4DVertex)
	#define sizeof_s4DVertex	128

#else
	#define BURNING_MATERIAL_MAX_TEXTURES 2
	#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR
		#define BURNING_MATERIAL_MAX_COLORS 1
	#else
		#define BURNING_MATERIAL_MAX_COLORS 0
	#endif
	#define BURNING_MATERIAL_MAX_LIGHT_TANGENT 1

	//ensure handcrafted sizeof(s4DVertex)
	#define sizeof_s4DVertex	64
#endif

// dummy Vertex. used for calculation vertex memory size
struct s4DVertex_proxy
{
	sVec4 Pos;
#if BURNING_MATERIAL_MAX_TEXTURES > 0
	sVec2 Tex[BURNING_MATERIAL_MAX_TEXTURES];
#endif
#if BURNING_MATERIAL_MAX_COLORS > 0
	sVec4 Color[BURNING_MATERIAL_MAX_COLORS];
#endif
#if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
	sVec3Pack LightTangent[BURNING_MATERIAL_MAX_LIGHT_TANGENT];
#endif
	u32 flag; // e4DVertexFlag

};


/*!
	Internal BurningVideo Vertex
*/
struct s4DVertex
{
	sVec4 Pos;
#if BURNING_MATERIAL_MAX_TEXTURES > 0
	sVec2 Tex[ BURNING_MATERIAL_MAX_TEXTURES ];
#endif
#if BURNING_MATERIAL_MAX_COLORS > 0
	sVec4 Color[ BURNING_MATERIAL_MAX_COLORS ];
#endif
#if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
	sVec3Pack LightTangent[BURNING_MATERIAL_MAX_LIGHT_TANGENT];
#endif

	u32 flag; // e4DVertexFlag


#if BURNING_MATERIAL_MAX_COLORS < 1 || BURNING_MATERIAL_MAX_LIGHT_TANGENT < 1
	u8 __align [sizeof_s4DVertex - sizeof (s4DVertex_proxy) ];
#endif

	// f = a * t + b * ( 1 - t )
	void interpolate(const s4DVertex& burning_restrict b, const s4DVertex& burning_restrict a, const ipoltype t)
	{
		Pos.interpolate ( a.Pos, b.Pos, t );
#if 0
		Tex[0].interpolate(a.Tex[0], b.Tex[0], t);
		Tex[1].interpolate(a.Tex[1], b.Tex[1], t);
		Color[0].interpolate(a.Color[0], b.Color[0], t);
		LightTangent[0].interpolate(a.LightTangent[0], b.LightTangent[0], t);
#endif

		size_t i;
		size_t size;

#if BURNING_MATERIAL_MAX_TEXTURES > 0
		size = (flag & VERTEX4D_FORMAT_MASK_TEXTURE) >> 16;
		for ( i = 0; i!= size; ++i )
		{
			Tex[i].interpolate ( a.Tex[i], b.Tex[i], t );
		}
#endif

#if BURNING_MATERIAL_MAX_COLORS > 0
		size = (flag & VERTEX4D_FORMAT_MASK_COLOR) >> 20;
		for ( i = 0; i!= size; ++i )
		{
			Color[i].interpolate ( a.Color[i], b.Color[i], t );
		}
#endif

#if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
		size = (flag & VERTEX4D_FORMAT_MASK_LIGHT) >> 24;
		for ( i = 0; i!= size; ++i )
		{
			LightTangent[i].interpolate ( a.LightTangent[i], b.LightTangent[i], t );
		}
#endif

	}
};

// ----------------- Vertex Cache ---------------------------

// Buffer is used as pairs of S4DVertex (0 ... ndc, 1 .. dc and projected)
typedef s4DVertex s4DVertexPair;
#define sizeof_s4DVertexPairRel 2
#define s4DVertex_ofs(index)  ((index)*sizeof_s4DVertexPairRel)
#define s4DVertex_proj(index) ((index)*sizeof_s4DVertexPairRel) + 1

struct SAligned4DVertex
{
	SAligned4DVertex()
		:data(0),ElementSize(0),mem(0)	{}

	virtual ~SAligned4DVertex ()
	{
		if (mem)
		{
			delete[] mem;
			mem = 0;
		}
	}

	void resize(size_t element)
	{
		if (element > ElementSize)
		{
			if (mem) delete[] mem;
			size_t byteSize = align_next(element * sizeof_s4DVertex, 4096);
			mem = new u8[byteSize];
		}
		ElementSize = element;
		data = (s4DVertex*)mem;
	}

	s4DVertex* data;	//align to 16 byte
	size_t ElementSize;

private:

	u8* mem;
};

//#define memcpy_s4DVertexPair(dst,src) memcpy(dst,src,sizeof_s4DVertex * 2)
static REALINLINE void memcpy_s4DVertexPair(void* burning_restrict dst, const void* burning_restrict src)
{
	//test alignment -> if already in aligned data
#if 0
	if (((size_t)dst & 0xC) | ((size_t)src & 0xC))
	{
		int g = 1;
	}
#endif

#if defined(ENV64BIT) && (sizeof_s4DVertex * sizeof_s4DVertexPairRel == 128)
	u64* burning_restrict dst64 = (u64*)dst;
	const u64* burning_restrict src64 = (const u64*)src;

	dst64[0]  = src64[0];
	dst64[1]  = src64[1];
	dst64[2]  = src64[2];
	dst64[3]  = src64[3];
	dst64[4]  = src64[4];
	dst64[5]  = src64[5];
	dst64[6]  = src64[6];
	dst64[7]  = src64[7];

	dst64[8]  = src64[8];
	dst64[9]  = src64[9];
	dst64[10] = src64[10];
	dst64[11] = src64[11];
	dst64[12] = src64[12];
	dst64[13] = src64[13];
	dst64[14] = src64[14];
	dst64[15] = src64[15];

#elif defined(ENV64BIT) && (sizeof_s4DVertex * sizeof_s4DVertexPairRel == 256)
	u64* burning_restrict dst64 = (u64*)dst;
	const u64* burning_restrict src64 = (const u64*)src;

	dst64[0]  = src64[0];
	dst64[1]  = src64[1];
	dst64[2]  = src64[2];
	dst64[3]  = src64[3];
	dst64[4]  = src64[4];
	dst64[5]  = src64[5];
	dst64[6]  = src64[6];
	dst64[7]  = src64[7];

	dst64[8]  = src64[8];
	dst64[9]  = src64[9];
	dst64[10] = src64[10];
	dst64[11] = src64[11];
	dst64[12] = src64[12];
	dst64[13] = src64[13];
	dst64[14] = src64[14];
	dst64[15] = src64[15];

	dst64[16] = src64[16];
	dst64[17] = src64[17];
	dst64[18] = src64[18];
	dst64[19] = src64[19];
	dst64[20] = src64[20];
	dst64[21] = src64[21];
	dst64[22] = src64[22];
	dst64[23] = src64[23];

	dst64[24] = src64[24];
	dst64[25] = src64[25];
	dst64[26] = src64[26];
	dst64[27] = src64[27];
	dst64[28] = src64[28];
	dst64[29] = src64[29];
	dst64[30] = src64[30];
	dst64[31] = src64[31];

#else
	u32* dst32 = (u32*)dst;
	const u32* src32 = (const u32*)src;

	size_t len = sizeof_s4DVertex * sizeof_s4DVertexPairRel;
	while (len >= 32)
	{
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		*dst32++ = *src32++;
		len -= 32;
	}
/*
	while (len >= 4)
	{
		*dst32++ = *src32++;
		len -= 4;
	}
*/
#endif
}


//! hold info for different Vertex Types
struct SVSize
{
	size_t Format;		// e4DVertexFlag VERTEX4D_FORMAT_MASK_TEXTURE
	size_t Pitch;		// sizeof Vertex
	size_t TexSize;	// amount Textures
	size_t TexCooSize;	// sizeof TextureCoordinates
};


// a cache info
struct SCacheInfo
{
	u32 index;
	u32 hit;
};

//must at least hold all possible (clipped) vertices of primitive.
#define VERTEXCACHE_ELEMENT	16			
#define VERTEXCACHE_MISS 0xFFFFFFFF
struct SVertexCache
{
	SVertexCache () {}
	~SVertexCache() {}

	//VertexType
	SVSize vSize[E4VT_COUNT];

	SCacheInfo info[VERTEXCACHE_ELEMENT];
	SCacheInfo info_temp[VERTEXCACHE_ELEMENT];


	// Transformed and lite, clipping state
	// + Clipped, Projected
	SAligned4DVertex mem;

	// source
	const void* vertices;
	u32 vertexCount;

	const void* indices;
	u32 indexCount;
	u32 indicesIndex;
	u32 indicesRun;
	u32 indicesPitch;

	// primitives consist of x vertices
	size_t primitiveHasVertex;

	e4DVertexType vType;		//E_VERTEX_TYPE
	scene::E_PRIMITIVE_TYPE pType;		//scene::E_PRIMITIVE_TYPE
	e4DIndexType iType;		//E_INDEX_TYPE iType

};


// swap 2 pointer
REALINLINE void swapVertexPointer(const s4DVertex** v1, const s4DVertex** v2)
{
	const s4DVertex* b = *v1;
	*v1 = *v2;
	*v2 = b;
}


// ------------------------ Internal Scanline Rasterizer -----------------------------



// internal scan convert
struct sScanConvertData
{
	u32 left;			// major edge left/right
	u32 right;			// !left
	u8 _unused_pack[8];

	f32 invDeltaY[4];	// inverse edge delta for screen space sorted triangle 

	f32 x[2];			// x coordinate
	f32 slopeX[2];		// x slope along edges

#if defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) || defined ( SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT )
	f32 w[2];			// w coordinate
	fp24 slopeW[2];		// w slope along edges
#else
	f32 z[2];			// z coordinate
	f32 slopeZ[2];		// z slope along edges
#endif

#if BURNING_MATERIAL_MAX_COLORS > 0
	sVec4 c[BURNING_MATERIAL_MAX_COLORS][2];		// color
	sVec4 slopeC[BURNING_MATERIAL_MAX_COLORS][2];	// color slope along edges
#endif

#if BURNING_MATERIAL_MAX_TEXTURES > 0
	sVec2 t[BURNING_MATERIAL_MAX_TEXTURES][2];		// texture
	sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES][2];	// texture slope along edges
#endif

#if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
	sVec3Pack_unpack l[BURNING_MATERIAL_MAX_LIGHT_TANGENT][2];		// Light Tangent
	sVec3Pack_unpack slopeL[BURNING_MATERIAL_MAX_LIGHT_TANGENT][2];	// tanget slope along edges
#endif
};

// passed to scan Line
struct sScanLineData
{
	s32 y;				// y position of scanline
	u8 _unused_pack[4];
	f32 x[2];			// x start, x end of scanline

#if defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) || defined ( SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT )
	f32 w[2];			// w start, w end of scanline
#else
	f32 z[2];			// z start, z end of scanline
#endif

	s32 x_edgetest;		// slope x
	u8 _unused_pack_1[4];

#if BURNING_MATERIAL_MAX_COLORS > 0
	sVec4 c[BURNING_MATERIAL_MAX_COLORS][2];			// color start, color end of scanline
#endif

#if BURNING_MATERIAL_MAX_TEXTURES > 0
	sVec2 t[BURNING_MATERIAL_MAX_TEXTURES][2];		// texture start, texture end of scanline
#endif

#if BURNING_MATERIAL_MAX_LIGHT_TANGENT > 0
	sVec3Pack_unpack l[BURNING_MATERIAL_MAX_LIGHT_TANGENT][2];		// Light Tangent start, end
#endif
};

// passed to pixel Shader
struct sPixelShaderData
{
	tVideoSample *dst;
	fp24 *z;

	s32 xStart;
	s32 xEnd;
	s32 dx;
	s32 i;
};

/*
	load a color value
*/
REALINLINE void getTexel_plain2 (	tFixPoint &r, tFixPoint &g, tFixPoint &b,const sVec4 &v	)
{
	r = tofix(v.r, FIX_POINT_F32_MUL);
	g = tofix(v.g, FIX_POINT_F32_MUL);
	b = tofix(v.b, FIX_POINT_F32_MUL);
}

#if 0
/*
	load a color value
*/
REALINLINE void getSample_color (	tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b,	const sVec4 &v )
{
	a = tofix ( v.a, FIX_POINT_F32_MUL);
	r = tofix ( v.r, COLOR_MAX * FIX_POINT_F32_MUL);
	g = tofix ( v.g, COLOR_MAX * FIX_POINT_F32_MUL);
	b = tofix ( v.b, COLOR_MAX * FIX_POINT_F32_MUL);
}

/*
	load a color value
*/
REALINLINE void getSample_color ( tFixPoint &r, tFixPoint &g, tFixPoint &b,const sVec4 &v )
{
	r = tofix ( v.r, COLOR_MAX * FIX_POINT_F32_MUL);
	g = tofix ( v.g, COLOR_MAX * FIX_POINT_F32_MUL);
	b = tofix ( v.b, COLOR_MAX * FIX_POINT_F32_MUL);
}
#endif

/*
	load a color value. mulby controls [0;1] or [0;ColorMax]
	aka getSample_color
*/
REALINLINE void vec4_to_fix(tFixPoint &r, tFixPoint &g, tFixPoint &b,const sVec4 &v, const f32 mulby )
{
	r = tofix(v.r, mulby);
	g = tofix(v.g, mulby);
	b = tofix(v.b, mulby);
}

REALINLINE void vec4_to_fix(tFixPoint &a,tFixPoint &r, tFixPoint &g, tFixPoint &b,const sVec4 &v, const f32 mulby)
{
	a = tofix(v.a, mulby);
	r = tofix(v.r, mulby);
	g = tofix(v.g, mulby);
	b = tofix(v.b, mulby);
}


}

}

#endif