#pragma once

#ifndef __samplegame_h__
	#define __samplegame_h__

#include <gxframework/gxframework.h>

#include <PxPhysicsAPI.h>
#include <extensions/PxExtensionsAPI.h>

#include <iostream>
#include <sstream>
#include <iomanip>

#pragma warning (disable : 4099) // warning LNK4099: PDB 'vc100.pdb' was not found with...

using namespace Gx;
using namespace physx;

class SampleGame : public Game
{
public:
	SampleGame();

	virtual void initialize();
	virtual void release();

	virtual void input(GxF32 elapsedTime);
	virtual void update(GxF32 elapsedTime);
	virtual void render(GxF32 elapsedTime);
	virtual void reshape(GxU32 width, GxU32 height);


	virtual void printHelp();

protected:
	void initializePhysics();
	void realeasePhysics();

	virtual void customizeScene(PxSceneDesc& desc);

	bool raycastFromCamera(PxVec3& impact, const PxRigidActor* target = NULL);

protected:
	void renderScene(const PxScene* scene);
	void renderRigidActor(const PxRigidActor* actor);
	void renderShape(const PxShape* shape);
	void renderSphereShape(const PxShape* shape);
	void renderPlaneShape(const PxShape* shape);
	void renderCapsuleShape(const PxShape* shape);
	void renderBoxShape(const PxShape* shape);

	PxRigidStatic* createStaticActor(const PxTransform& pose, const PxGeometry& geometry, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL);
	PxRigidDynamic* createDynamicActor(const PxTransform& pose, const PxGeometry& geometry, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);

	void addStackedBoxesAt(const PxVec3& position, GxU32 count, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);
	void addPiramidBoxesAt(const PxVec3& position, GxU32 count, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);
	void addWallBoxesAt(const PxVec3& position, GxU32 countHeight, GxU32 countWidth, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);

	void addBoxAt(const PxVec3& position, GxF32 halfX, GxF32 halfY, GxF32 halfZ, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);
	void addCapsuleAt(const PxVec3& position, GxF32 halfHeight, GxF32 radius, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);
	void addSphereAt(const PxVec3& position, GxF32 radius, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 1);

	void throwBox(const PxVec3& position, GxF32 halfExtents, const PxVec3& initialVelocity, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 4);
	void throwBall(const PxVec3& position, GxF32 radius, const PxVec3& initialVelocity, const PxMaterial* physicsMaterial, Gx::Material* graphicsMaterial = NULL, PxReal density = 4);

protected:
	Mesh* createGraphicsMeshFromConvexMesh(PxConvexMesh* convexMesh);
	Mesh* createGraphicsMeshFromTriangleMesh(PxTriangleMesh* triangleMesh);
	Mesh* createGraphicsMeshFromHeightField(PxHeightField* heightfield, GxF32 heightScale, GxF32 rowScale, GxF32 columnScale);

	PxTriangleMesh* createTriangleMeshFromGraphicsMesh(Mesh* mesh);
	PxConvexMesh* createConvexMeshFromGraphicsMesh(Mesh* mesh);

	PxConvexMesh* createConvexMesh(const PxVec3* verts, PxU32 vertCount);
	PxTriangleMesh* createTriangleMesh(const void* vertices, GxU32 vertexCount, GxU32 vertexStride, const GxU16* indices, GxU32 indexCount);

protected:
	bool connectToPvd;

	void connectToVisualDebugger(const char* ip, GxU16 port = 5425);
	void disconnectFromVisualDebugger();
	
protected:
	PxFoundation* foundation;
	PxPhysics* physics;
	PxCooking* cooking;
	PxScene* scene;

	PxMaterial* defaultPhysicsMaterial;

protected:
	BasicEffect* effect;
	GameCamera* camera;
	GraphicsDevice* graphics;
	ContentManager* content;
	Material flatBlackMaterial;

	GxF32 cameraVelocity;

protected:
	std::string rootDirectory;

protected:
	Mesh* boxMesh;
	Mesh* planeMesh;
	Mesh* shpereMesh;
	Mesh* capsuleMesh;

protected:
	PxMat44 projectionMtx, modelMtx;
	bool mouseCentering;
	bool forceAlpha;
};

#endif /* __samplegame_h__ */