/*

    Castle Draco

    Copyright Søren Schimkat <www.castle.schimkat.dk>

    This program and it´s source code is released with the following licence:
    
    Permission is granted to anyone to use the program and recompile the 
    sourcecode on any architecture. Noone may redistribute the binarys or
    the sourcecode. For personal interests, you may alter the sourcecode
    if you like - but the altered sourcecode may not be distributed. The 
    sourcecode, parts of the sourcecode or the altered sourcecode may not
    appear in any other programs.
    
*/


#include <irrlicht.h>
#include <audiere.h>
#include <stdio.h>
#include <stdlib.h>



using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
using namespace audiere;

#pragma comment(lib, "Irrlicht.lib")
#pragma comment (lib, "audiere.lib")


bool PlayGame = true;
AudioDevicePtr audiereDevice;
OutputStreamPtr stream;




class MyEventReceiver : public IEventReceiver { 
   public: virtual bool OnEvent(SEvent event) {
      if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) { 
         PlayGame = false;
      }
      return false; 
   } 
}; 



int game(int Renderer, int Resolution, int Depth) {

   //Setting up video device
   video::E_DRIVER_TYPE GameRenderer;
   switch (Renderer) {
      case 1:
         GameRenderer = irr::video::EDT_OPENGL;
         break;
      default:
         GameRenderer = irr::video::EDT_OPENGL;
         break;
   }    

   core::dimension2d<s32> GameResolution;
   switch (Resolution) {
      case 1:
         GameResolution = core::dimension2d<s32>(640, 480);
         break;
      case 2:
         GameResolution = core::dimension2d<s32>(800, 600);
         break;
      case 3:
         GameResolution = core::dimension2d<s32>(1024, 768);
         break;
      case 4:
         GameResolution = core::dimension2d<s32>(1280, 1024);
         break;     
      case 5:
         GameResolution = core::dimension2d<s32>(1600, 1200);
         break;
      default:
         GameResolution = core::dimension2d<s32>(1024, 768);
         break;
   }
    
   int GameDepth;
   switch (Depth) {
      case 1:
         GameDepth = 8;
         break;
      case 2:
         GameDepth = 16;
         break;
      case 3:
         GameDepth = 32;
         break;
      default:
         GameDepth = 32;
         break;
   }   
    
   MyEventReceiver receiver;
   IrrlichtDevice *device = createDevice(GameRenderer, GameResolution, GameDepth, true, true, false, &receiver);
   video::IVideoDriver* driver = device->getVideoDriver();
   driver->setFog(SColor(0, 0, 0, 0), true, 700, 3000);
   device->getCursorControl()->setVisible(false);
   scene::ISceneManager* smgr = device->getSceneManager();
   IGUIEnvironment* guienv = device->getGUIEnvironment();
   smgr->setAmbientLight(video::SColorf(0.8f, 0.8f, 0.8f, 1.0f));



   // Mounting datafile
   device->getFileSystem()->addZipFileArchive("Castle.dat", true, true); 



   // Displaying splash screen
   core::dimension2d<int> Size = device->getVideoDriver()->getScreenSize();
   IGUIImage* img = guienv->addImage(rect<int>(((Size.Width - 512) / 2),
                                              ((Size.Height - 512) / 2),
                                              ((Size.Width  - 512) / 2) + 512,
                                              ((Size.Height - 512) / 2) + 512));
   img->setImage(driver->getTexture("load.jpg"));
	
   
   // Setting some vars
   bool Loading = true;
   const int TerrainTileSize = 3100;
   int TerrainTilePosition[4][2];
   
   
   // Running loadsequence
   while(device->run() && Loading == true) {
      driver->beginScene(true, true, 0);
      guienv->drawAll();
      driver->endScene();


      // Setting up the world with collision detection
      scene::IAnimatedMesh* mesh = 0;
      scene::ISceneNode*    node = 0;
      scene::IMetaTriangleSelector* metaselector = smgr->createMetaTriangleSelector();
	
      mesh = smgr->getMesh("doorway.3ds");
      node = smgr->addOctTreeSceneNode(mesh); 
      node->setPosition(core::vector3df(1900, 0, 2200)); 
      node->setMaterialFlag(video::EMF_FOG_ENABLE, true);
      node->setMaterialFlag(video::EMF_LIGHTING, true);


      scene::ITriangleSelector* selector = smgr->createOctTreeTriangleSelector(mesh->getMesh(0), node, 128);
      node->setTriangleSelector(selector);
      metaselector->addTriangleSelector(selector);
      selector->drop();

   
      // Creating terrain meshes
      scene::ITerrainSceneNode* terrain;
      char watername[10];
      char watertexture[10];
      const int TerrainSize = 3840;
      srand ( time(NULL) );
      
      for (int i = 0; i < 2; i++) {
         for (int j = 0; j < 2; j++) {

            terrain = smgr->addTerrainSceneNode("TerrainHeightmap.bmp");
            terrain->setScale(core::vector3df(30, 1.5f, 30));
            terrain->setMaterialFlag(video::EMF_LIGHTING, true);
            terrain->setMaterialFlag(video::EMF_FOG_ENABLE, true);
            terrain->setMaterialTexture(0, driver->getTexture("TerrainTexture.jpg"));
            terrain->setMaterialTexture(1, driver->getTexture("TerrainBumpmap.jpg"));
            terrain->setMaterialType(video::EMT_DETAIL_MAP);
            terrain->scaleTexture(1.0f, 20.0f);
            terrain->setPosition(core::vector3df(i * TerrainSize, 0, j * TerrainSize));

            // Adding colision detection to the terrain field
            selector = smgr->createTerrainTriangleSelector(terrain, 0);
            terrain->setTriangleSelector(selector);
            metaselector->addTriangleSelector(selector);
            selector->drop();
      
            // Adding water mesh to the terrain field
            sprintf(watername,    "water%d%d",   i, j);
            sprintf(watertexture, "water%d.bmp", rand()%4+1);
            mesh = smgr->addHillPlaneMesh(watername,
                                          core::dimension2d<f32>(50,50),
                                          core::dimension2d<s32>(30,30), 0, 0,
                                          core::dimension2d<f32>(0,0),
                                          core::dimension2d<f32>(10,10));
            node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0), 3.0f, 300.0f, 30.0f);
            node->setPosition(core::vector3df(1800 + (TerrainSize * i), rand()%30+20, 1800 + (TerrainSize * j)));
            node->setMaterialTexture(0, driver->getTexture(watertexture));           
            // node->setMaterialTexture(1, driver->getTexture("stones.jpg"));  
            // node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
            node->setMaterialFlag(video::EMF_FOG_ENABLE, true);
            node->setMaterialFlag(video::EMF_LIGHTING, true); 
            
         }
      }


      // Drawing the sky
      scene::ISceneNode* SkyBoxNode = smgr->addSkyBoxSceneNode(driver->getTexture("top.jpg"),
                                                               driver->getTexture("bottom.jpg"),
                                                               driver->getTexture("left.jpg"),
                                                               driver->getTexture("right.jpg"),
                                                               driver->getTexture("front.jpg"),
                                                               driver->getTexture("back.jpg"), NULL, 0);



      //Create rotating light source
      node = smgr->addLightSceneNode(0, core::vector3df(0,0,0), video::SColor(0, 50, 50, 50), 300.0f);
      scene::ISceneNodeAnimator* anim = 0;
      anim = smgr->createFlyCircleAnimator (core::vector3df(200,500,200),1500.0f, 0.002f);
      node->addAnimator(anim);
      anim->drop();

      // Attatching flare texture to the light source
      node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));
      node->setMaterialFlag(video::EMF_LIGHTING, false);
      node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
      node->setMaterialTexture(0, driver->getTexture("flare.jpg"));


      // Setting up the camera
      scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 150, 800);
      camera->setPosition(core::vector3df(100, 1000, 100));
      camera->setFarValue(6000);
      // camera->setFOV(90 * (f32)core::GRAD_PI2);

      // Attatching crosshair to the camera
      node = smgr->addBillboardSceneNode(camera, core::dimension2d<f32>(5, 5)); 
      node->setPosition(vector3df(0, 0, 100)); 
      node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); 
      node->setMaterialFlag(video::EMF_LIGHTING, false); 
      ITexture * texture = driver->getTexture("crosshair.jpg"); 
      driver->makeColorKeyTexture(texture, position2d<s32>(0, 0));
      node->setMaterialTexture(0, texture); 

      // Attatchning weapon to the camera
      scene::IAnimatedMesh* weaponMesh = smgr->getMesh("weapon.3ds"); 
      scene::IAnimatedMeshSceneNode* weaponNode = smgr->addAnimatedMeshSceneNode(weaponMesh, 
                                                                              camera,
                                                                              -1,
                                                                              core::vector3df(20,-30,20),
                                                                              core::vector3df(-2,-2,10),
                                                                              core::vector3df(0.2,0.2,0.2));
      weaponNode->setMaterialFlag(video::EMF_FOG_ENABLE, true);                                                              
      weaponNode->setMaterialFlag(video::EMF_LIGHTING, true); 
      // weaponNode->setAnimationSpeed(20); 

      // Attatching collision detection to the camera
      scene::ISceneNodeAnimator* anim2 = smgr->createCollisionResponseAnimator(metaselector,
                                                                               camera,
                                                                               core::vector3df(30,100,30),
                                                                               core::vector3df(0,-3.0f,0),
                                                                               core::vector3df(0,50,0));


      camera->addAnimator(anim2);
      anim2->drop();  



      // Loading sounds
      audiereDevice = OpenDevice();
      stream = OpenSound(audiereDevice.get(), "audio/Back.mp3", true);
      stream->setRepeat(true);
      //stream->setVolume(0.5f); // 50% volume
	    


      Loading = false;

   }   



   // Start background sound loop
   stream->play();



   // Entering game loop
   #ifdef DEBUG
      core::vector3df cameraPos; 
      core::vector3df targetPos; 
      int Field = 0;
   #endif

	while(device->run() && PlayGame == true) {

      #ifdef DEBUG
         cameraPos = smgr->getActiveCamera()->getPosition(); 
         targetPos = smgr->getActiveCamera()->getTarget(); 
         if ((((int)cameraPos.X - TerrainTilePosition[0][1]) > 0) and (((int)cameraPos.X - TerrainTilePosition[0][1]) < TerrainTileSize)) {
            Field = ((((int)cameraPos.Z - TerrainTilePosition[0][1]) >= 0) and (((int)cameraPos.Z - TerrainTilePosition[0][1]) < TerrainTileSize)) ? 0 : 2;
         }
         else {
            Field = ((((int)cameraPos.Z - TerrainTilePosition[0][1]) >= 0) and (((int)cameraPos.Z - TerrainTilePosition[0][1]) < TerrainTileSize)) ? 1 : 3;
         }
         printf ("Felt %d\n", Field);  
      #endif

		driver->beginScene(true, true, 0); 
		smgr->drawAll();
		driver->endScene();	

	}
	device->drop();
	
	return 0;
	
}

