#pragma once

#include "skse64/NiObjects.h"
#include "skse64/GameTypes.h"

class BSResourceStream;

struct ID3D11Texture2D1;
struct ID3D11ShaderResourceView1;

// 44
class NiPixelFormat
{
public:
	// 0C
	class NiComponentSpec
	{
	public:
		UInt32	type;		// 00
		UInt32	format;		// 04
		UInt8	bits;		// 08
		UInt8	isSigned;	// 09
		UInt8	pad0A;		// 0A
		UInt8	pad0B;		// 0B
	};

	UInt8	flags;			// 00
	UInt8	bpp;			// 01
	UInt8	srgb;			// 02
	UInt8	pad03;			// 03
	UInt32	format;			// 04
	UInt32	tiling;			// 08
	UInt32	rendererHint;	// 0C
	UInt32	extraData;		// 10

	NiComponentSpec	components[4];	// 14
};


class NiPersistentSrcTextureRendererData : public NiObject
{
public:
	virtual ~NiPersistentSrcTextureRendererData();
};

MAKE_NI_POINTER(NiPersistentSrcTextureRendererData);

class NiDX9PersistentSrcTextureRendererData : public NiPersistentSrcTextureRendererData
{
public:
	virtual ~NiDX9PersistentSrcTextureRendererData();
};

class NiPixelData : public NiObject
{
public:
	virtual ~NiPixelData();

	NiPixelFormat	pixelFormat;		// 08
	void *			unk0C;				// 4C

	UInt8 *			m_pucPixels;		// 50	[mipmapLevels]
	UInt32 *		m_puiWidth;			// 54	[mipmapLevels]
	UInt32 *		m_puiHeight;		// 58	[mipmapLevels]
	UInt32 *		m_puiOffset;		// 5C	[mipmapLevels + 1]

	UInt32			m_uiMipmapLevels;	// 60
	UInt32			m_uiPixelStride;	// 64

	UInt32			unk68;				// 68
	UInt32			m_uiFaces;			// 6C
	UInt8			unk70;				// 70
	UInt8			pad71[3];			// 71

	UInt32 GetWidth(UInt32 mipmapLevel)
	{
		return m_puiWidth[mipmapLevel];
	}

	UInt32 GetHeight(UInt32 mipmapLevel)
	{
		return m_puiHeight[mipmapLevel];
	}

	UInt8 * GetPixels(UInt32 uiMipmapLevel = 0, UInt32 uiFace = 0)
	{
		return m_pucPixels + uiFace*m_puiOffset[uiMipmapLevel] +
			m_puiOffset[uiMipmapLevel];
	};
};

MAKE_NI_POINTER(NiPixelData);

// 14
class Ni2DBuffer : public NiObject
{
public:
	virtual ~Ni2DBuffer();

	UInt32	width;			// 08
	UInt32	height;			// 0C
	void	* rendererData;	// 10
};

// 24
class NiTexture : public NiObject
{
public:
	virtual ~NiTexture();

	virtual void	Unk_25(void);
	virtual void	Unk_26(void);
	virtual void	Unk_27(void);
	virtual void	Unk_28(UInt32 * unk1, UInt32 * unk2, UInt32 * unk3, UInt32 * unk4);
	virtual void	Unk_29(void);
	virtual void	Unk_2A(void);
	virtual void	Unk_2B(void);

	// 28
	class RendererData
	{
	public:
		ID3D11Texture2D1			* texture;		// 00
		UInt64						unk08;			// 08
		ID3D11ShaderResourceView1	* resourceView;	// 10
		UInt16						width;			// 18
		UInt16						height;			// 1A
		UInt8						unk1C;			// 1C
		UInt8						unk1D;			// 1D
		UInt16						unk1E;			// 1E
		UInt32						unk20;			// 20
		UInt32						unk24;			// 24
	};
	
	UInt32				unk10;			// 10 - 6
	UInt32				unk14;			// 14 - 3
	UInt32				unk18;			// 18 - 2
	UInt32				unk1C;			// 1C
	const char			* name;			// 20
	UInt32				unk28;			// 28 - FFFFFF
	UInt32				unk2C;			// 2C
	NiTexture			* prevTexture;	// 30
	NiTexture			* nextTexture;	// 38
	BSResourceStream	* resourceData;	// 40
	RendererData		* rendererData;	// 48
};

// ??
class NiRenderedTexture : public NiTexture
{
public:
	virtual ~NiRenderedTexture();

	MEMBER_FN_PREFIX(NiRenderedTexture);
	DEFINE_MEMBER_FN(ctor, void, 0x00000000);
	DEFINE_MEMBER_FN(UpdateVirtualImage, void, 0x00ECE030, NiRenderedTexture * newTexture);
	DEFINE_MEMBER_FN(AddVirtualImage, UInt8, 0x00ECE0F0, BSFixedString linkageName);
	DEFINE_MEMBER_FN(ReleaseVirtualImage, void, 0x00ECDFC0);
};

// 58
class NiRenderedCubeMap : public NiRenderedTexture
{
public:
	virtual ~NiRenderedCubeMap();

	UInt32	unk3C;	// 3C
	UInt32	unk40;	// 40
	UInt32	unk44;	// 44
	UInt32	unk48;	// 48
	UInt32	unk4C;	// 4C
	UInt32	unk50;	// 50
	UInt32	unk54;	// 54
};

// 34
class NiSourceTexture : public NiTexture
{
public:
	UInt8	flags;	// 50 - C (normal), 8 (rendered)
};

typedef NiTexture * (*_CreateSourceTexture)(const BSFixedString & name);
extern RelocAddr<_CreateSourceTexture> CreateSourceTexture;
