#include <conio.h>
#include <stdlib.h>

#include <pr.h>
#include <prgui.h>

#include <prsound.h>

#ifdef __3DFX__
#include <pr3dfx.h>
#include <glide.h>
#endif

#ifdef WIN32
#include <winutil.h>
#endif


/* Power Render Example 8

   Description:  Demonstrates 3D Sound.

   Controls:
   Click and drag the left mouse button to move the objects along the
   x/y axis.

   Click and drag the right mouse button to move the objects along the
   z axis.

   Press space to toggle which object you are moving.

   Press ESC to quit.
*/

                                             
PR_VIEWPORT viewport;                  /* Our viewport structure */
PR_CAMERA *camera;                     /* One camera */
PR_LIGHTLIST userlights;               /* Holds a list of lights */

PR_OBJECT *object_shape;               /* The shape loaded */
PR_ENTITY *ball1;                     
PR_ENTITY *ball2;                     
PR_DWORD  device=0;                    /* Display device */

PR_DWORD active_entity = 0;
PR_ENTITY *active_ptr;


PR_DWORD WAVtest;
PR_DWORD WAVtest2;
PR_3DSOUND *test;
PR_3DSOUND *test2;


void InitializeDevices (void)
{
  /* Attempt to find the device */

  #ifdef __3DFX__
  if ((device == DEVICE_3DFX) || (device == DEVICE_ANY))
    device = PR_Detect3Dfx ();
  #endif

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  if ((device == DEVICE_SVGA) || (device == DEVICE_ANY))
    device = PR_DetectSVGA ();   

  if ((device == DEVICE_VGA) || (device == DEVICE_ANY))
    device = PR_DetectVGA ();   
#endif

  /* Attempt to initialize the device */
  #ifdef __3DFX__
  if (device == DEVICE_3DFX)
    {
     PR_Initialize3Dfx ();
     atexit (PR_Shutdown3Dfx);
    }
  #endif

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  if (device == DEVICE_SVGA)
    {
     PR_InitializeSVGA ();
     atexit (PR_ShutdownSVGA);
    }
  else if (device == DEVICE_VGA)
    {
     PR_InitializeVGA ();
    }
#endif
}



PR_DWORD ticks;
void TimerFunc (void)
{
  ticks++;
  AUpdateAudio ();
}


#if defined (MSDD) || defined (WTDD)
void PR_RestoreAll (void)
{
HRESULT ddrval;

 ddrval = IDirectDrawSurface2_Restore (wgtpdds);

 if (ddrval != DD_OK)
   return;

  PR_LostSurface = 0;
}
#endif


void main (void)
{
PR_DWORD vwidth, vheight;
PR_REAL cenx, ceny, cenz;
PR_UDWORD BLACK;                       /* Color index/value for black */
PR_UDWORD WHITE;                       /* Color index/value for white */

#if defined (MSGLIDE) || defined (WTGLIDE)
  device = 'y';
#else
  while (kbhit ()) getch ();
  #ifdef __3DFX__
  printf ("Use 3Dfx? (y/n)\n");
  device = getch ();
  #endif
#endif

  PR_Initialize (1000);                /* Maximum 1000 triangles per frame */

  if (device == 'y' || device == 'Y')
    device = DEVICE_3DFX;
  else
    device = DEVICE_SVGA;

  InitializeDevices ();

  PR_AllocMaterials (32);              /* Allocate the materials, */
  PR_AllocTextures (32);               /* textures, */
  PR_AllocShadeTables (2);             /* and shade tables */


  vwidth = 640;
  vheight = 480;
  if (PR_SetMode (vwidth, vheight, 60) != MODE_SUCCESS)
    {
     vwidth = PR_VideoModes[0].width;     /* Initialize the video mode */
     vheight = PR_VideoModes[0].height;
     PR_SetMode (vwidth, vheight, 60);
    }

  PR_OpenViewport (&viewport, 0, 0, vwidth-1, vheight-1, VIEW_PLAIN);
  PR_SetViewport (&viewport);          /* Open a full screen viewport */

  /* Load the object */
  PR_SetTexturePath ("..\\data\\");
  PR_SetTablePath ("..\\data\\");
  object_shape = PR_LoadPRO ("..\\data\\sphere.pro", LOAD_NORMAL);
  PR_CenterObject (object_shape, &cenx, &ceny, &cenz);

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  /* Set the palette from the textures loaded */
  wsetpalette (0, 255, global_palette);
#endif

  /* Create the main entity */
  ball1 = PR_CreateEntity (object_shape, "Ball 1");
  ball2 = PR_CreateEntity (object_shape, "Ball 2");

  PR_PositionEntity (ball1, 100, 0, 0);
  PR_PositionEntity (ball2, -200, 0, 0);


  camera = PR_AllocCamera ();          /* Initialize the camera */
  PR_InitializeCamera (camera);

  PRSND_SetOrigin (0, 0, -900);
  PR_PositionCameraSource (camera, 0, 0, -900);
  PR_PositionCameraTarget (camera, 0, 0, 0);
  PR_SetCameraMode (camera, CAMFLAG_AIM_TARGET); 
  PR_SetActiveCamera (camera);

 /* Initialize the light */
  PR_AllocLights (&scenelights, 1);
  PR_AllocLights (&userlights, 1);
  PR_SetLightPosition (&userlights, 0, 0, 0, -900);
  PR_SetLightOn (&userlights, 0);
  PR_SetLightType (&userlights, 0, DIRECTIONAL_LIGHT);
  PR_SetLightColor (&userlights, 0, 1.0, 1.0, 1.0);
  PR_SetLightStrength (&userlights, 0, 1.0);
  userlights.NumLights = 1;     /* This sets how many lights are actually used */


  PR_OpenScreen (PR_BACKBUFFER);
  BLACK = PRGFX_MakeColor (0, 0, 0);
  WHITE = PRGFX_MakeColor (63, 63, 63);

  installkbd ();
  winittimer ();
  wstarttimer (TimerFunc, TICKS(60));

#ifndef WIN32
  minit ();
#endif

  msetbounds (0, 0, 320, 200);
  msetxy (160, 100);

  /* Set which entity is currently being moved */
  active_entity = 0;
  active_ptr = ball1;

  /* Load a smaller font */
  gui_font = wloadfont ("little.wfn");
  PRGFX_SetTextForeground (WHITE);
  PRGFX_SetTextBackground (BLACK);
  PRGFX_SetTextTransparent (TEXTFGBG);


  /* initialize audio library */
  PRSND_Initialize ();

  PRSND_AllocSounds (2);

  /* open audio device */
  PRSND_OpenAudio (AUDIO_DEVICE_MAPPER,
                   AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO,
                   22050);

  /* load module and waveform file */
  WAVtest = PRSND_LoadSound ("test.wav");
  WAVtest2 = PRSND_LoadSound ("test2.wav");

  PRSND_SetLoopStart (WAVtest, 0);
  PRSND_SetLoopEnd (WAVtest, PRSND_GetLength (WAVtest));
  PRSND_SetLoopMode (WAVtest, 1);

  PRSND_SetLoopStart (WAVtest2, 0);
  PRSND_SetLoopEnd (WAVtest2, PRSND_GetLength (WAVtest2));
  PRSND_SetLoopMode (WAVtest2, 1);

  PRSND_InitializeVoices (2);


  test = PRSND_Alloc3DSound ();

  /* play the waveform through a voice */
  PRSND_Play3DSound (test, WAVtest);
  PRSND_Set3DSoundVolume (test, 64);
  PRSND_Set3DSoundVolumeMode (test, SOUND_3D_VOLUME);
  PRSND_Set3DSoundVolumeFactor (test, 2000);
  PRSND_Set3DSoundPanning (test, 128);
  PRSND_Set3DSoundPanningMode (test, SOUND_3D_PANNING);
  PRSND_Set3DSoundPanningFactor (test, 2200);
  PRSND_Set3DSoundShiftMode (test, SOUND_DOPPLER_ON);
  PRSND_Set3DSoundShiftFactor (test, 0.0005);
  PRSND_Set3DSoundCoordinate (test, 0, 0, 0, ball1);
  PRSND_Set3DSoundShiftSlide (test, 200);
  PRSND_Update3DSound (test);


  test2 = PRSND_Alloc3DSound ();
  /* play the waveform through a voice */
  PRSND_Play3DSound (test2, WAVtest2);
  PRSND_Set3DSoundVolume (test2, 64);
  PRSND_Set3DSoundVolumeMode (test2, SOUND_3D_VOLUME);
  PRSND_Set3DSoundVolumeFactor (test2, 2000);
  PRSND_Set3DSoundPanning (test2, 128);
  PRSND_Set3DSoundPanningMode (test2, SOUND_3D_PANNING);
  PRSND_Set3DSoundPanningFactor (test2, 2200);
  PRSND_Set3DSoundShiftMode (test2, SOUND_DOPPLER_ON);
  PRSND_Set3DSoundShiftFactor (test2, 0.0005);
  PRSND_Set3DSoundCoordinate (test2, 0, 0, 0, ball2);
  PRSND_Set3DSoundShiftSlide (test2, 20);
  PRSND_Update3DSound (test2);


  PRSND_UpdateVoices ();

  /* main program loop */
  while (!kbdon[KEY_ESC])
    {
     #ifdef WIN32
      UpdateMessages ();
     #endif


     #if defined (MSDD) || defined (WTDD)
       if (PR_LostSurface)
         PR_RestoreAll ();
     #endif

     PR_OpenScreen (PR_BACKBUFFER);
     PR_NewFrame ();                   /* Begin a new frame */

     PRGFX_SetColor (BLACK);
     PRGFX_ClearScreen ();             /* Clear the last frame */

     PR_TransformLights (&userlights);

     PRSND_Update3DSound (test);
     PRSND_Update3DSound (test2);
     PRSND_UpdateVoices ();


     if (kbdon[KEY_SPACE])             /* Toggle active entity */
       {
        active_entity = !active_entity;
        if (active_entity == 0)
          active_ptr = ball1;
        else
          active_ptr = ball2;

        while (kbdon[KEY_SPACE]) 
            { 
                         #ifdef WIN32
                          UpdateMessages ();
                         #else
                           wretrace ();                  
                         #endif                 
                        };
       }


     if (mouse.but == 1)
       {
        PR_MoveEntity (active_ptr, mouse.mx - 160, 100 - mouse.my, 0);
        msetxy (160, 100);
       }
     else if (mouse.but == 2)
       {
        PR_MoveEntity (active_ptr, 0, 0, 100 - mouse.my);
        msetxy (160, 100);
       }


     PR_RotateEntity (ball1, -2, 5, 0);  /* Spin the entity */
     PR_TransformEntity (ball1);      /* Transform the entity */
     PR_RenderEntity (ball1);         /* Render the entity */

     PR_RotateEntity (ball2, 2, -5, 0);  /* Spin the entity */
     PR_TransformEntity (ball2);      /* Transform the entity */
     PR_RenderEntity (ball2);         /* Render the entity */

     PR_RenderFrame ();                /* Draw the scene */

     PRGUI_printf (10, 10, "Moving object %i", active_entity);

     PR_Flip (1);                      /* Show the background page */
    }


  PRSND_CloseVoices ();
  PRSND_DeleteAllSounds ();
  PRSND_CloseAudio ();

  /* Free all allocated memory */
  PR_FreeCamera (camera);
  PR_FreeEntity (ball1);
  PR_FreeEntity (ball2);
  PR_FreeObject (object_shape);
  PR_CloseViewport (&viewport);
  PR_DeleteAllShadeTables ();
  PR_DeleteAllTextures ();
  PR_DeleteAllMaterials ();
  PR_ShutDown ();

  uninstallkbd ();
  wstoptimer ();
  wdonetimer ();

  mdeinit ();

#ifndef WIN32
  wsetmode (3);                        /* Go back to text mode */
#endif
}

