// Copyright 2018 RED Software, LLC. All Rights Reserved.
#include "stdafx.h"
#include "Renderer.h"

#if defined(_DX9)
//#pragma comment(lib, "NiBinaryShaderLibDX9.lib")
//#pragma comment(lib, "NSBShaderLibDX9.lib")
//#pragma comment(lib, "NiD3DXEffectShaderLibDX9.lib")
#endif

Renderer::Renderer() 
: mTerrainEffect(nullptr)
, mTrailEffect(nullptr)
, mBrightEffect(nullptr)
{
}

Renderer::~Renderer()
{
	if (mTrailEffect)
		mTrailEffect->Release();

	if (mTerrainEffect)
		mTerrainEffect->Release();

	if (mBrightEffect)
		mBrightEffect->Release();
}

Renderer * Renderer::Create(unsigned int uiWidth, unsigned int uiHeight, 
	unsigned int uiUseFlags, NiWindowRef kWndDevice, NiWindowRef kWndFocus, 
	unsigned int uiAdapter, DeviceDesc eDesc, FrameBufferFormat eFBFormat, 
	DepthStencilFormat eDSFormat, PresentationInterval ePresentationInterval, 
	SwapEffect eSwapEffect, unsigned int uiFBMode, unsigned int uiBackBufferCount, 
	unsigned int uiRefreshRate)
{
	// *bad*
	if ( CreateDirect3D9() == -1 )
	{
		return nullptr;
	}

	Renderer* r = NiNew Renderer;
	assert(r);

	ms_kD3DCriticalSection.Unlock();

	const bool bSuccess = r->Initialize(uiWidth, uiHeight, uiUseFlags, kWndDevice,
		kWndFocus, uiAdapter, eDesc, eFBFormat, eDSFormat,
		ePresentationInterval, eSwapEffect, uiFBMode, uiBackBufferCount,
		uiRefreshRate);

	if (!bSuccess)
	{
		NiDelete r;
		r = nullptr;
	}
	else
	{
		// TODO: what does this do, is it needed, and if so why?
		// NiStream::UnregisterLoader("NiPersistentSrcTextureRendererData");
		// NiStream::RegisterLoader("NiPersistentSrcTextureRendererData", NiDX9PersistentSrcTextureRendererData::CreateObject );
	}

	return r;
}

bool Renderer::Init()
{
	// TODO: implement shaders
	/*
	if (CreateEffect("./Script/Resource/Brightness.fx", &mBrightEffect) == false || mBrightEffect == 0)
	{
		assert(0);
		return false;
	}
	if (CreateEffect("./Script/Resource/TerrainShader.fx", &mTerrainEffect) == false || mTerrainEffect == 0)
	{
		assert(0);
		return false;
	}
	if (CreateEffect("./Script/Resource/TrailShader.fx", &mTrailEffect) == false || mTrailEffect == 0)
	{
		assert(0);
		return false;
	}

	*/

	return true;
}

bool Renderer::CreateEffect(const std::string& pathName, LPD3DXEFFECT* effect)
{
	return true; // make this do stuff
}

LPDIRECT3DVERTEXBUFFER9 Renderer::CreateVertexBuffer(unsigned int vertexCount, unsigned int vertexStride, const void* data)
{
	LPDIRECT3DVERTEXBUFFER9 vb = 0;
	unsigned int length = vertexCount * vertexStride;

	HRESULT ret = m_pkD3DDevice9->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &vb, 0);

	if (FAILED(ret) || vb == 0)
		return 0;

	if (data)
	{
		void* p = 0;
		HRESULT ret = vb->Lock(0, length, &p, 0);

		if (SUCCEEDED(ret))
		{
			NiMemcpy(p, static_cast<const void*>(data), length);
		}
		vb->Unlock();
	}
	return vb;
}

LPDIRECT3DINDEXBUFFER9 Renderer::CreateIndexBuffer(unsigned int indexCount, const unsigned short* indexArray)
{
	assert(m_pkD3DDevice9);

	LPDIRECT3DINDEXBUFFER9 ib = 0;
	unsigned int length = indexCount * sizeof(unsigned short);

	HRESULT ret = m_pkD3DDevice9->CreateIndexBuffer(length, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ib, 0);

	if (FAILED(ret) || ib == 0)
		return 0;

	if (indexArray)
	{
		void* p = 0;
		HRESULT ret = ib->Lock(0, length, &p, 0);

		if (SUCCEEDED(ret))
		{
			NiMemcpy(p, static_cast<const void*>(indexArray), length);
		}
		ib->Unlock();
	}
	return ib;
}

void Renderer::OnLostDevice()
{
	if (mTerrainEffect)
		mTerrainEffect->OnLostDevice();
	if (mTrailEffect)
		mTrailEffect->OnLostDevice();
	if (mBrightEffect)
		mBrightEffect->OnLostDevice();
}

void Renderer::OnResetDevice()
{
	if (mTerrainEffect)
		mTerrainEffect->OnResetDevice();
	if (mTrailEffect)
		mTrailEffect->OnResetDevice();
	if (mBrightEffect)
		mBrightEffect->OnResetDevice();
}