#pragma once
#include "DirectXFramework.h"
#include <fstream>
#include <vector>
#include <ctime>
#include "ColorGradient.h"
#include "DDSTextureLoader.h"
#include "WICTextureLoader.h"
#include "SharedMethods.h"
#include "SceneNode.h"
#include "SceneGraph.h"
#include "MeshNode.h"
#include "SplitMeshNode.h"

typedef struct TerrainVertex
{
	XMFLOAT3 Position;
	XMFLOAT3 Normal;
	XMFLOAT2 TexCoord;
	XMFLOAT2 BlendMapTexCoord;
} TerrainVertex;

struct TCBUFFER
{
	XMMATRIX    completeTransformation;
	XMMATRIX	worldTransformation;
	XMFLOAT4	cameraPosition;
	XMVECTOR    lightVector;
	XMFLOAT4    lightColor;
	XMFLOAT4    ambientColor;
	XMFLOAT4    diffuseCoefficient;
	XMFLOAT4	specularCoefficient;
	float		shininess;
	float		opacity;
	float waterHeight;
	float waterShininess;
	XMFLOAT4 waterColor;
	float padding[4];
};

class TerrainNode : public SceneNode
{
public:
	TerrainNode(wstring name, wstring seed, float waterHeight = 150.0f, int widthX = 1023, int widthZ = 1023, int cellSizeX = 10, int cellSizeZ = 10);

	void SetAmbientLight(XMFLOAT4 ambientLight);
	void SetWaterColor(XMFLOAT4 waterColor);
	void SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColor);

	bool virtual Initialise(void);
	void Render(void);
	void virtual Shutdown(void);

	void PopulateTerrain(SceneGraphPointer currentSceneGraph, vector<TerrainPopNode>& nodesForPop, int xStep, int zStep, float heightLower, float heightUpper, float slopeLower, float slopeUpper);

	float GetHeightAtPoint(float x, float z, bool waterCollide = false);
	bool CheckXBoundary(float x);
	bool CheckZBoundary(float z);

protected:
	bool _initError = false;

	int _widthX;
	int _widthZ;

	unsigned int _gridRows;
	unsigned int _gridCols;

	int _cellSizeX;
	int _cellSizeZ;

	float _waterHeight;

	UINT _polygonsCount;
	UINT _indicesCount;
	UINT _vertexCount;

	float _terrainStartX;
	float _terrainStartZ;
	float _terrainEndX;
	float _terrainEndZ;
		
	wstring _seedString;
	unsigned int _seedHash;

	vector<TerrainVertex> _terrainVerts;
	vector<int> _indices;	
	vector<float> _heightValues;

	XMFLOAT4			_ambientLight;
	XMFLOAT4			_directionalLightVector;
	XMFLOAT4			_directionalLightColor;
	XMFLOAT4			_cameraPosition;

	ComPtr<ID3D11Device>			_device;
	ComPtr<ID3D11DeviceContext>		_deviceContext;

	ComPtr<ID3D11Buffer>			_vertexBuffer;
	ComPtr<ID3D11Buffer>			_indexBuffer;

	ComPtr<ID3DBlob>				_vertexShaderByteCode = nullptr;
	ComPtr<ID3DBlob>				_pixelShaderByteCode = nullptr;
	ComPtr<ID3D11VertexShader>		_vertexShader;
	ComPtr<ID3D11PixelShader>		_pixelShader;
	ComPtr<ID3D11InputLayout>		_layout;
	ComPtr<ID3D11Buffer>			_constantBuffer;

	ComPtr<ID3D11ShaderResourceView> _texturesResourceView;
	ComPtr<ID3D11ShaderResourceView> _blendMapResourceView;

	ComPtr<ID3D11RasterizerState>    _defaultRasteriserState;
	ComPtr<ID3D11RasterizerState>    _wireframeRasteriserState;

	ComPtr<ID3D11ShaderResourceView> _snowTest;
	ComPtr<ID3D11ShaderResourceView> _waterNormalMap;
	XMFLOAT4 _waterColor;

	void virtual GenerateTerrainData();
	void GenerateTerrainNormals();
	void GenerateBuffers();
	void BuildShaders();
	void BuildVertexLayout();
	void BuildConstantBuffer();
	void BuildRendererStates();

	void LoadTerrainTextures();
	void GenerateBlendMap();

	float GetHeightValueAt(int index);

	void AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR normal);
	void BuildExtraMaps();
};

