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

#include <pr.h>
#include "prbuild.h"

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

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



/* Power Render Example 10

   Description:  Shows how to build an object from scratch instead of 
                 loading from a file.  A series of macros are used
                 to simply the build process.  (see prbuild.h)
*/

                                             
PR_VIEWPORT viewport;                  /* Our viewport structure */
PR_CAMERA *camera;                     /* One camera */
PR_OBJECT *object_shape;               /* The shape loaded */
PR_ENTITY *entity;                     /* A single entity of the shape */
PR_LIGHTLIST userlights;               /* Holds a list of lights */
PR_DWORD  device=0;                    /* Display device */
PR_DWORD animation_count;

PR_MATERIAL mat;
PR_DWORD cube_mat;
PR_DWORD cube_tab;

void animation_timer (void)
{
 animation_count++;
}


void InitializeDevices (void)
{
#ifdef __MYST__
  if ((device == DEVICE_MYSTIQUE) || (device == DEVICE_ANY))
    device = PR_DetectMystique ();
#endif


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

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  #if defined (MSDD) || defined (WTDD)
    if ((device == DEVICE_D3D) || (device == DEVICE_ANY))
      device = PR_DetectD3D ();   /* Attempt to find the device */
  #endif

  if ((device == DEVICE_SVGA) || (device == DEVICE_ANY))
    device = PR_DetectSVGA ();   /* Attempt to find the device */

  if ((device == DEVICE_VGA) || (device == DEVICE_ANY))
    device = PR_DetectVGA ();   /* Attempt to find the device */
#endif

#ifdef __MYST__
  if (device == DEVICE_MYSTIQUE)
    {
     PR_InitializeMystique ();
     atexit (PR_ShutdownMystique);
    }
#endif

#ifdef __3DFX__
  if (device == DEVICE_3DFX)
    {
     PR_Initialize3Dfx ();
     atexit (PR_Shutdown3Dfx);
    }
#endif

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  #if defined (MSDD) || defined (WTDD)
  if (device == DEVICE_D3D)
    {
     PR_InitializeD3D ();
     atexit (PR_ShutdownD3D);
    }
  #endif
  if (device == DEVICE_SVGA)
    {
     PR_InitializeSVGA ();
     atexit (PR_ShutdownSVGA);
    }
  else if (device == DEVICE_VGA)
    {
     PR_InitializeVGA ();
    }
#endif
}



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

 ddrval = IDirectDrawSurface2_Restore (wgtpdds);

 if (ddrval != DD_OK)
   return;

  PR_LostSurface = 0;
}
#endif


/* Builds a 4 sided face with the texture stretched to fill it
   Texture coordinates are moved slighly inward to avoid overflow
   errors */
#define MAKE_SIDE(v1, v2, v3, v4) {                        \
 PRBUILD_BeginFace();                                      \
 PRBUILD_SetFaceVertices(v1, v2, v3);                      \
 PRBUILD_SetFaceUV(0.01f, 0.01f,  0.99f, 0.01f,  0.99f, 0.99f);  \
 PRBUILD_SetFaceShades(0.0f, 0.0f, 0.0f);                  \
 PRBUILD_EndFace();                                        \
                                                           \
 PRBUILD_BeginFace();                                      \
 PRBUILD_SetFaceVertices(v1, v3, v4);                      \
 PRBUILD_SetFaceUV(0.01f, 0.01f,  0.99f, 0.99f,  0.01f, 0.99f);  \
 PRBUILD_SetFaceShades(0.0f, 0.0f, 0.0f);                  \
 PRBUILD_EndFace();                                        }



void BuildCube (void)
{
  PR_SetMaterialName (&mat, "CUBEFACE");
  PR_SetMaterialMethod (&mat, T_PFLAT_TEXTURED);
  PR_SetMaterialBaseColor (&mat, 0);
  PR_SetMaterialColor (&mat, 255, 255, 255);
  PR_SetMaterialTexture (&mat, PR_LoadTexture("box.pcx"));
  PR_SetMaterialTable (&mat, PR_LoadTable ("box.tab"));
  PR_SetMaterialShades (&mat, 31);
  PR_SetMaterialEnvironmentMap (&mat, 0);
  PR_SetMaterialMipMapState (&mat, FALSE);
  PR_SetMaterialAlpha (&mat, 255);
  cube_mat = PR_AddMaterial (&mat);


/*
  The cube has vertices numbered as follows:

      4------5
     /.     /|
    / .    / |
   0------1  |
   |  7...|..6
   | /    | /
   |/     |/
   3------2

  When building a face, remember to keep the order of the vertices
  clockwise so it will be facing the right direction 
*/


  PRBUILD_BeginObject(object_shape, "CUBE", 1);
  PRBUILD_BeginSegment("MAINSEG", 12, 8);
  PRBUILD_SetSegmentFlags(0);

  PRBUILD_SetVertex(-100.0f, -100.0f, 100.0f);
  PRBUILD_SetVertex(100.0f, -100.0f, 100.0f);
  PRBUILD_SetVertex(100.0f, 100.0f, 100.0f);
  PRBUILD_SetVertex(-100.0f, 100.0f, 100.0f);
  PRBUILD_SetVertex(-100.0f, -100.0f, -100.0f);
  PRBUILD_SetVertex(100.0f, -100.0f, -100.0f);
  PRBUILD_SetVertex(100.0f, 100.0f, -100.0f);
  PRBUILD_SetVertex(-100.0f, 100.0f, -100.0f);

  PRBUILD_SetFaceFrontMaterial(cube_mat);
  PRBUILD_SetFaceBackMaterial(cube_mat);
  PRBUILD_SetFaceFlags(FFLAG_FRONT_VISIBLE);

  MAKE_SIDE (0, 1, 2, 3);
  MAKE_SIDE (1, 5, 6, 2);
  MAKE_SIDE (5, 4, 7, 6);
  MAKE_SIDE (4, 0, 3, 7);
  MAKE_SIDE (4, 5, 1, 0);
  MAKE_SIDE (3, 2, 6, 7);

  PRBUILD_EndSegment ();
  PRBUILD_EndObject();
}


void main (int argc, char *argv[])
{
PR_DWORD vwidth, vheight;
PR_UDWORD BLACK;                       /* Color index/value for black */
PR_DWORD move_count;

#ifndef WIN32
  while (kbhit ())
    getch ();

#if defined (__3DFX__) || defined (__MYST__)
  printf ("Use 3D hardware? (y/n)\n");
  device = getch ();

  if (device == 'y' || device == 'Y')
    device = DEVICE_ANY;
  else
#endif
     device = DEVICE_SVGA;
#else /* We are in windows */

  /* First check for Direct3D/DDraw */
  #if defined(MSDD) || defined(WTDD)
    device = MessageBox(NULL, "Use Direct3D Hardware?", "Power Render Initialization", MB_YESNO);
    if (device == IDYES)
      {
       device = DEVICE_D3D;
       PR_Settings.Hardware = 1;
      }
    else
      { 
       device = DEVICE_SVGA;
       PR_Settings.Hardware = 0;
      }
 
  /* Next look for specific hardware */
  #elif defined (MSGLIDE) || defined (WTGLIDE)
    device = DEVICE_3DFX;
  #elif defined (MSMYST) || defined (WTMYST)
    device = DEVICE_MYST;
  #endif
#endif


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

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


  vwidth = PR_VideoModes[0].width;     /* Initialize the video mode */
  vheight = PR_VideoModes[0].height;
  if (PR_SetMode (vwidth, vheight, 60) != MODE_SUCCESS)
    PR_FatalError ("Cannot set video mode", NULL);


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

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

  /* Create the main entity */
  entity = PR_CreateEntity (object_shape, "TEST ENTITY");

  camera = PR_AllocCamera ();          /* Initialize the camera */
  PR_InitializeCamera (camera);
  PR_PositionCameraSource (camera, 0, 0, 400);
  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, 400);
  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);

  installkbd ();
  animation_count = 0;
  winittimer ();
  wstarttimer (animation_timer, TICKS (60));

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  PR_SetPerspectiveDivisions (TEXTURE_DIVISION_32);
#endif

  /* 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);

     move_count = animation_count;
     animation_count = 0;

     PR_RotateEntity (entity, 0.1f * move_count,
                              1.2f * move_count,
                              0.3f * move_count);  /* Rotate the entity */
     PR_TransformEntity (entity);      /* Transform the entity */
     PR_RenderEntity (entity);         /* Render the entity */

     PR_RenderFrame ();                /* Draw the scene */

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

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

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

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

