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

#include <pr.h>

#if defined (MSGLIDE) || defined (WTGLIDE)
 #include <glide.h>
 #include <pr3dfx.h>
 #include "winutil.h"
 #include <windows.h>
#elif defined (MSDD) || defined (WTDD)
 #include "winutil.h"
 #include <windows.h>
#else
 #ifdef __3DFX__
  #include <glide.h>
  #include <pr3dfx.h>
  #include <fxgui.h>
 #endif
#endif

#include <prgui.h>

/*

       /=========\ /========\ ||        || /========  /=======\
       ||       || ||      || ||        || ||         ||      ||
       ||       || ||      || ||        || ||         ||      ||
       ||       || ||      || ||        || ||         ||      ||
       ||       || ||      || ||   ||   || ||         ||      //
       |=========/ ||      || ||   ||   || |=======   |=====<<
       ||          ||      || ||   ||   || ||         ||      \\
       ||          ||      || ||   ||   || ||         ||       ||
       ||          ||      || ||   ||   || ||         ||       ||
       ||          \========/ \==========/ \========= ||       ||

--------------------------------<===>----------------------------------

    /=======\   /========= |\     || |======\  /========= /=======\
    ||      ||  ||         ||\    || ||    \ \ ||         ||      ||
    ||      ||  ||         || \   || ||     || ||         ||      ||
    ||      ||  ||         ||  \  || ||     || ||         ||      ||
    ||      //  ||         ||   \ || ||     || ||         ||      //
    |======<<   |======    ||\   \|| ||     || |======    |======<<
    ||      \\  ||         || \   || ||     || ||         ||      \\
    ||       || ||         ||  \  || ||     || ||         ||       ||
    ||       || ||         ||   \ || ||    / / ||         ||       ||
    ||       || |========= ||    \|| |======/  |========= ||       ||

Texture Skin Utility

Applies a texture across an entire object.

 Revision History:
 July 4, 1996: Created
 July 6: Added front/back textures
 Dec 22: Added 3Dfx support
*/

PR_DWORD device;
PR_DWORD texnum;
char texturefile[80];                 /* Name of the front texture */
char texturefile2[80];                /* Name of the back texture */
char objectfile[80];                  /* Name of the texture */
PR_OBJECT * object;                   /* Shape definition of the PRO file */
PR_ENTITY * obj1;                     /* One instance of the shape */
PR_LIGHTLIST userlights;              /* We only use 1 light */

PR_OBJECT * planeshape;               /* Shape definiation of the plane box */
PR_ENTITY * tplane;                   /* Instance of the shape */

PR_VIEWPORT viewport;                 /* A single viewport */
PR_CAMERA * newcam;                   /* Our camera */
PR_REAL     camscale;                 /* Used for moving */
PR_REAL     camdist;                  /* distance from object */     
PR_DWORD    map_xofs = 0;             /* center of tmap */
PR_DWORD    map_yofs = 0;
PR_REAL     cenx, ceny, cenz;

PR_MATRIX   plane_matrix;
PR_REAL     trot_x=0, trot_y=0, trot_z=0;    /* Texture Rotation */
PR_REAL     drot_x=0, drot_y=0, drot_z=0;    /* Delta Rotation */
PR_REAL     rot_x=0, rot_y=0, rot_z=0; /* Object Rotation */
PR_REAL     xscale = 0;                /* X scaling factor */
PR_REAL     yscale = 0;                /* Y scaling factor */

PR_DWORD    texture_width = 0;
PR_DWORD    texture_height = 0;
PR_UCHAR    nonwrap = 0;              /* 1 = nonwrapping textures */

PR_UCHAR    backtext = 0;             /* 1 = front/back skin */
PR_REAL     backplane = 0;

PR_DWORD    start_screen, end_screen;

/* Material */
char        matname[80];
PR_DWORD    usemat;
PR_DWORD    matnum;
PR_DWORD    frontmaterial;
PR_DWORD    backmaterial;

void PR_MapObject (PR_OBJECT *obj, PR_REAL xscale, PR_REAL yscale);


#define LSHIFT 42                  /* Key Codes */
#define CTRL 29
#define ALT 56
#define SPACE 57
#define ESC 1

int mouse_mode = 0;
#define MODE_ROBJECT 0
#define MODE_TOBJECT 1
#define MODE_RPLANE 2
#define MODE_SCALE 3
#define MODE_CAMERA 4


/* Button positions */
#define XMINUS 460,60,480,75
#define XPLUS  572,60,592,75
#define XDISPW 440,66
#define XDISPLAY 515,66

#define YMINUS 460,85,480,100
#define YPLUS  572,85,592,100
#define YDISPW 440,91
#define YDISPLAY 515,91

#define ZMINUS 460,110,480,125
#define ZPLUS  572,110,592,125
#define ZDISPW 440,116
#define ZDISPLAY 515,116

#define SXMINUS 460,135,480,150
#define SXPLUS  572,135,592,150
#define SXDISPW 415,141
#define SXDISPLAY 505,141

#define SMINUS 460,160,480,175
#define SPLUS  572,160,592,175
#define SDISPW 415,166

#define SYMINUS 460,185,480,200
#define SYPLUS  572,185,592,200
#define SYDISPW 415,191
#define SYDISPLAY 505,191

#define PMINUS 460,210,480,225
#define PPLUS  572,210,592,225
#define PDISPW 415,216
#define PDISPLAY 505,216

#define SWROBJECT 480,300,572,315
#define SWTOBJECT 480,320,572,335
#define SWRTMAP   480,340,572,355
#define SWSCALE   480,360,572,375
#define SWCAMERA  480,380,572,395

#define ALIGN   450,245,602,260
#define WRAPPER 450,265,602,280
#define SAVE 460,410,592,430
#define QUIT 460,450,592,470

#define DISPWIDTH 410
#define DISPHEIGHT 356
#define DISPLAY 0,0,409,355


void DisplayVars (void)
/* Displays the variables that you can change with the buttons */
{
PR_DWORD i;

  PRGFX_Clip (0, 0, 639, 479);

  for (i = start_screen; i <= end_screen; i++)
    {
     PR_OpenScreen (i);

     PRGFX_SetTextForeground (GUI_GREY1);
     PRGFX_SetTextBackground (GUI_GREY3);
     PRGFX_SetTextTransparent (TEXTFGBG);

     PRGUI_printf (XDISPLAY, "%5.1f  ", trot_x);
     PRGUI_printf (YDISPLAY, "%5.1f  ", trot_y);
     PRGUI_printf (ZDISPLAY, "%5.1f  ", trot_z);
     PRGUI_printf (SXDISPLAY, "%8.2f  ", xscale);
     PRGUI_printf (SYDISPLAY, "%8.2f  ", yscale);

     if (backtext)
       PRGUI_printf (PDISPLAY, "%8.2f  ", backplane);

     if (nonwrap)
       PRGUI_textbutton (WRAPPER, "No Wrap");
     else
       PRGUI_textbutton (WRAPPER, "Wrap");
    }

}


void DrawMode (void)
/* Draws a red box around the movement buttons */
{
PR_DWORD dy, y;
PR_DWORD i;

  PRGUI_HideMouse ();

  for (i = start_screen; i <= end_screen; i++)
    {
     PR_OpenScreen (i);
     for (y = 0; y < 5; y++)
       {
        if (mouse_mode == y) 
          PRGFX_SetColor (GUI_RED);
        else
          PRGFX_SetColor (GUI_BLACK);

        dy = 299 + y * 20;
        PRGFX_Rectangle (479, dy, 573, dy + 17);
       }
    }
  PRGUI_ShowMouse ();
}



void InitMenu (void)
/* Draw the initial menu */
{
block logo;
color pal[256];
PR_DWORD i;

  PRGFX_Clip (0, 0, 639, 479);

  PRGUI_GoStartPath ();
  setlib ("guidata.prl");
  gui_font = wloadfont ("guifont.wfn");
  
  for (i = start_screen; i <= end_screen; i++)
    {
     PR_OpenScreen (i);

     PRGFX_SetColor (GUI_BLACK);
     PRGFX_Bar (0, 0, 639, 479);
  
     PRGFX_SetColor (GUI_GREY1);
     PRGFX_Bar (0, 377, 639, 479-67);

     PRGFX_SetColor (GUI_GREY2);
     PRGFX_Bar (0, 357, 639, 479-77);

     if (PR_OutputDevice.bitdepth == 8)
       logo = wloadpcx ("prbw.pcx", pal);
     else
       logo = wloadpcx ("prcol.pcx", pal);
     if (logo == NULL)
       PRGUI_Error ("Cannot find the Power Render logo file.");
     PRGFX_Clip (0, 0, 639, 479);
     PR_BeginScreen ();
     PRGFX_PutBlock8bit (0, 479-67, logo, pal, 1);
     PR_EndScreen ();
     wfreeblock (logo);

     PRGUI_Button (412, 1, 638, 479);

     PRGFX_SetTextForeground (GUI_GREY1);
     PRGFX_SetTextBackground (GUI_GREY3);
     PRGFX_SetTextTransparent (TEXTFGBG);

     PRGUI_printf (520, 5,  "TEXSKIN 1.0");
     PRGUI_printf (420, 15, "File");
     PRGUI_printf (450, 15, ":");
     PRGUI_printf (460, 15, "%s", objectfile);

     if (backtext)
       {
        PRGUI_printf (420, 25, "Front");
        PRGUI_printf (450, 25, ":");
        PRGUI_printf (460, 25, "%s", texturefile);

        PRGUI_printf (420, 35, "Back");
        PRGUI_printf (450, 35, ":");
        PRGUI_printf (460, 35, "%s", texturefile2);
       }
     else
       PRGUI_printf (420, 25, "Texture: %s", texturefile);

  // X 
  PRGUI_textbutton (XMINUS, "-");
  PRGUI_textbutton (XPLUS, "+");
  PRGUI_printf (XDISPW, "X");

  // Y 
  PRGUI_textbutton (YMINUS, "-");
  PRGUI_textbutton (YPLUS, "+");
  PRGUI_printf (YDISPW, "Y");

  // Z 
  PRGUI_textbutton (ZMINUS, "-");
  PRGUI_textbutton (ZPLUS, "+");
  PRGUI_printf (ZDISPW, "Z");

  // X Scale
  PRGUI_textbutton (SXMINUS, "-");
  PRGUI_textbutton (SXPLUS, "+");
  PRGUI_printf (SXDISPW, "XScale");

  // Y Scale
  PRGUI_textbutton (SYMINUS, "-");
  PRGUI_textbutton (SYPLUS, "+");
  PRGUI_printf (SYDISPW, "YScale");

  // XY Scale
  PRGUI_textbutton (SMINUS, "-");
  PRGUI_textbutton (SPLUS, "+");
  PRGUI_printf (SDISPW, "Scale");


  // Back Plane Z
  if (backtext)
    {
     PRGUI_textbutton (PMINUS, "-");
     PRGUI_textbutton (PPLUS, "+");
     PRGUI_printf (PDISPW, "BackDist");
    }

  PRGUI_textbutton (SWROBJECT, "Rot Object");
  PRGUI_textbutton (SWTOBJECT, "Move Object");
  PRGUI_textbutton (SWRTMAP,   "Rot Plane");
  PRGUI_textbutton (SWSCALE,   "Scale");
  PRGUI_textbutton (SWCAMERA,  "Camera");

  PRGUI_textbutton (QUIT, "Quit");
  PRGUI_textbutton (SAVE, "Save");
  PRGUI_textbutton (ALIGN, "Align to View");
  }

  DisplayVars ();
  mouse_mode = MODE_ROBJECT;
  DrawMode ();
  setlib (NULL);
}


void Init3D (void)
{
  /* Open the 3D viewport */
  PR_OpenViewport (&viewport, 0, 0, DISPWIDTH-1, DISPHEIGHT-1, VIEW_PLAIN);
  PR_SetViewport (&viewport);

  /* Set up a camera */
  newcam = PR_AllocCamera ();
  PR_InitializeCamera (newcam);
  PR_AddCamera (newcam);
  camdist = -object->bbox.radius * 2;
  camscale = object->bbox.radius / 10;
  PR_PositionCameraSource (newcam, 0, 0, camdist);
  newcam->rotation.y = 180;
  PR_SetCameraMode (newcam, CAMFLAG_ANGLE_BASED);

  obj1 = PR_CreateEntity (object, "OBJ1");
  PR_ScaleEntity (obj1, 1, 1, 1);

  tplane = PR_CreateEntity (planeshape, "TPLANE");
  PR_ScaleEntity (tplane, 1, 1, 1);

  PR_MapObject (object, xscale, yscale);
}


void Display3D (void)
{
PR_DWORD i;
PR_VERTEX_DATA *vert;

  PR_OpenScreen (PR_BACKBUFFER);

  newcam->source.z = camdist;
  PR_SetActiveCamera (newcam);
  PRGFX_Clip (active_viewport.topx,
              active_viewport.topy,
              active_viewport.bottomx,
              active_viewport.bottomy);


  /* Use direct access to draw a wireframe texture box */

  /* Set the vertices based on the size of the texture scale */
  planeshape->segment_list->vertex_list[0].x = -map_xofs / xscale;
  planeshape->segment_list->vertex_list[0].y = -map_yofs / yscale;
  planeshape->segment_list->vertex_list[0].z = 0;

  planeshape->segment_list->vertex_list[1].x = map_xofs / xscale;
  planeshape->segment_list->vertex_list[1].y = -map_yofs / yscale;
  planeshape->segment_list->vertex_list[1].z = 0;

  planeshape->segment_list->vertex_list[2].x = map_xofs / xscale;
  planeshape->segment_list->vertex_list[2].y = map_yofs / yscale;
  planeshape->segment_list->vertex_list[2].z = 0;

  planeshape->segment_list->vertex_list[3].x = -map_xofs / xscale;
  planeshape->segment_list->vertex_list[3].y = map_yofs / yscale;
  planeshape->segment_list->vertex_list[3].z = 0;

  PR_TransformEntity (tplane);

  PRGFX_SetColor (GUI_BLACK);
  if (device == DEVICE_D3D)
    PRGFX_ClearScreen ();
  else
    PRGFX_Bar (active_viewport.topx,
               active_viewport.topy,
               active_viewport.bottomx,
               active_viewport.bottomy);

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

  PR_SetLightPosition (&userlights, 0, newcam->source.x, newcam->source.y, newcam->source.z);
  PR_TransformLights (&userlights);

  PR_TransformEntity (obj1);
  PR_RenderEntity (obj1);
  PR_RenderFrame ();
 
  PRGFX_SetColor (GUI_WHITE);
  /* Draw lines that are completely visible */
  vert = planeshape->segment_list->vertex_data;
  for (i = 0; i < 3; i++)
    {
     if ((!vert[i].flags) && (!vert[i+1].flags))
       PRGFX_Line (vert[i].sx, vert[i].sy,
                   vert[i+1].sx, vert[i+1].sy);
    }

  /* Close poly */
  if ((!vert[3].flags) && (!vert[0].flags))
    PRGFX_Line (vert[3].sx, vert[3].sy,
                vert[0].sx, vert[0].sy);

  PR_Flip (1);
}


void MakePlaneMatrix (PR_REAL dx, PR_REAL dy, PR_REAL dz)
{
  memcpy (tplane->orientation.rot_mat, plane_matrix, sizeof (PR_MATRIX));
  PR_RotateEntity (tplane, dx, dy, dz);
  memcpy (plane_matrix, tplane->orientation.rot_mat, sizeof (PR_MATRIX));
  PR_MatrixMultiply (obj1->orientation.rot_mat,
                     plane_matrix,
                     tplane->orientation.rot_mat);
  PR_MapObject (object, xscale, yscale);
}


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

 ddrval = IDirectDrawSurface2_Restore (wgtpdds);

 if (ddrval != DD_OK)
   return;

  InitMenu ();
  Display3D ();
  PR_LostSurface = 0;
}
#endif


void program_loop (void)
/* Controls the user input */
{
PR_DWORD x, y;
PR_DWORD remap = 0;
PR_MATERIAL *m;
PR_DWORD choice, quit = 0;
PR_DWORD ScaleMode, LastScaleMode;

  
  PR_MapObject (object, xscale, yscale);
  Display3D ();
  PRGUI_ShowMouse ();

  while ((!quit) && (!kbdon[ESC]))
   {
#ifdef WIN32
     UpdateMessages ();
#endif

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

        PRGFX_Clip (0, 0, 639, 479);

    PRGUI_DrawMouse ();

    if (PRGUI_HitButton (QUIT))
      {
       PR_OpenScreen (PR_FRONTBUFFER);
       quit = !PRGUI_ChoiceDialog ("Are you sure you want to quit?",
                    NULL, NULL, "Yes", "No");
      }

    if ((PRGUI_HitButton (WRAPPER)) && ((texture_width == 256) || (device == DEVICE_3DFX)))
    /* Toggle the wrap/nonwrap switch */
      {
       PRGUI_HideMouse (); 
       nonwrap = !nonwrap;

       m = &PR_ObjectMaterialList[frontmaterial];
       if (nonwrap)
         m->render_method = T_TEXTURED;
       else
         m->render_method = T_WTEXTURED;

       if (backtext)
         {
          m = &PR_ObjectMaterialList[backmaterial];
          if (nonwrap)
            m->render_method = T_TEXTURED;
          else
            m->render_method = T_WTEXTURED;
         }

       PR_MapObject (object, xscale, yscale);
       Display3D ();
       DisplayVars ();

       noclick ();
       PRGUI_ShowMouse (); 
      }

    if ((PRGUI_HitButton (ALIGN)) || (kbdon[KEY_A]))
    /* Align the texture to the view */
      {
       trot_x = (-rot_x + 360);
       trot_y = (-rot_y + 360);
       trot_z = (-rot_z + 360);

       if (trot_x >= 360)
         trot_x -= 360;
       if (trot_y >= 360)
         trot_y -= 360;
       if (trot_z >= 360)
         trot_z -= 360;

       tplane->orientation.rot.x = trot_x;
       tplane->orientation.rot.y = trot_y;
       tplane->orientation.rot.z = trot_z;

       PR_MatrixTranspose (obj1->orientation.rot_mat, plane_matrix);
       PR_MatrixMultiply (obj1->orientation.rot_mat,
                          plane_matrix,
                          tplane->orientation.rot_mat);


       PRGUI_HideMouse (); 
       PR_MapObject (object, xscale, yscale);
       Display3D ();
       DisplayVars ();
       PRGUI_ShowMouse (); 
      }


    /* Check the mode buttons */
    if ((PRGUI_HitButton (SWTOBJECT) | (kbdon[LSHIFT])) && (mouse_mode != MODE_TOBJECT))
      {
       mouse_mode = MODE_TOBJECT;
       DrawMode ();
      }
    else if ((PRGUI_HitButton (SWRTMAP) | (kbdon[CTRL])) && (mouse_mode != MODE_RPLANE))
      {
       mouse_mode = MODE_RPLANE;
       DrawMode ();
      }
    else if ((PRGUI_HitButton (SWSCALE) | (kbdon[KEY_S])) && (mouse_mode != MODE_SCALE))
      {
       mouse_mode = MODE_SCALE;
       DrawMode ();
      }
    else if ((PRGUI_HitButton (SWROBJECT) | (kbdon[SPACE])) && (mouse_mode != MODE_ROBJECT))
      {
       mouse_mode = MODE_ROBJECT;
       DrawMode ();
      }
    else if ((PRGUI_HitButton (SWCAMERA) | (kbdon[KEY_Z])) && (mouse_mode != MODE_CAMERA))
      {
       mouse_mode = MODE_CAMERA;
       DrawMode ();
      }
      

    /* Check the 3D display window */
    if (PRGUI_HitButton (DISPLAY))
      {
       PRGUI_HideMouse ();
       x = mouse.mx;
       y = mouse.my;

       if (mouse_mode == MODE_TOBJECT)                /* Object slide */
         {
          drot_x = obj1->orientation.location.x;
          drot_y = obj1->orientation.location.y;

          while (mouse.but)
            {
             #ifdef WIN32
              UpdateMessages ();
             #endif

             if (mouse.but == 1)
               {
                obj1->orientation.location.x = drot_x - (x - mouse.mx) * (camscale);
                obj1->orientation.location.y = drot_y + (y - mouse.my) * (camscale);
               }

             PR_MapObject (object, xscale, yscale);
             Display3D ();
            }
         }
       else if (mouse_mode == MODE_ROBJECT)   /* Normal object rotation */
         {

          while (mouse.but)
            {
             #ifdef WIN32
               UpdateMessages ();
             #endif
      
             if (mouse.but == 1)
               {
                rot_x = y - mouse.my;
                rot_y = (x - mouse.mx);
               }
             else if (mouse.but == 2)
                rot_z = (x - mouse.mx);

             msetxy (204, 178);
             x = 204;
             y = 178;

             PR_RotateEntity (obj1, rot_x, rot_y, rot_z);

             if (kbdon[KEY_A])
               {
                trot_x = (-obj1->orientation.rot.x + 360);
                trot_y = (-obj1->orientation.rot.y + 360);
                trot_z = (-obj1->orientation.rot.z + 360);

                if (trot_x >= 360)
                  trot_x -= 360;
                if (trot_y >= 360)
                  trot_y -= 360;
                if (trot_z >= 360)
                  trot_z -= 360;

                tplane->orientation.rot.x = trot_x;
                tplane->orientation.rot.y = trot_y;
                tplane->orientation.rot.z = trot_z;

                PR_MatrixTranspose (obj1->orientation.rot_mat, plane_matrix);

                PR_MapObject (object, xscale, yscale);
                DisplayVars ();
               }

             PR_MatrixMultiply (obj1->orientation.rot_mat,
                                plane_matrix,
                                tplane->orientation.rot_mat);

             Display3D ();
            }
         }
       else if (mouse_mode == MODE_SCALE)     /* Scale */
         {
          drot_x = xscale;
          drot_y = yscale;
          ScaleMode = LastScaleMode = 2;

          while (mouse.but)
            {
             #ifdef WIN32
               UpdateMessages ();
             #endif

             if (mouse.but == 1)
               { 
                if (kbdon[KEY_X])
                  ScaleMode = 0;
                else if (kbdon[KEY_Y])
                  ScaleMode = 1;
                else
                  ScaleMode = 2;

                if (LastScaleMode != ScaleMode)
                  {
                   x = mouse.mx;
                   y = mouse.my;
                   drot_x = xscale;
                   drot_y = yscale;
                  }

                LastScaleMode = ScaleMode;

                if (ScaleMode == 0 || ScaleMode == 2)
                   xscale = drot_x + (y - mouse.my) * (camscale * 10);
                if (ScaleMode == 1 || ScaleMode == 2)
                   yscale = drot_y + (y - mouse.my) * (camscale * 10);
               }

             if (xscale <= 0.05)
               xscale = 0.05;
             if (yscale <= 0.05)
               yscale = 0.05;
             PR_MapObject (object, xscale, yscale);
             Display3D ();
             DisplayVars ();
            }
         }
       else if (mouse_mode == MODE_CAMERA)     /* Camera */
         {
          drot_x = newcam->source.x;
          drot_y = newcam->source.y;
          drot_z = camdist;

          while (mouse.but)
            {
             #ifdef WIN32
               UpdateMessages ();
             #endif
                          
             if (mouse.but == 1)
               { 
                newcam->source.x = drot_x + (x - mouse.mx) * 10;
                newcam->source.y = drot_y - (y - mouse.my) * 10;
                newcam->dest.x = newcam->source.x;
                newcam->dest.y = newcam->source.y;
               }
             else if (mouse.but == 2)
               camdist = drot_z - (y - mouse.my) * camscale;

             Display3D ();
            }
         }

       else if (mouse_mode == MODE_RPLANE)      /* Plane rotation */
         {
          while (mouse.but)
            {
             #ifdef WIN32
               UpdateMessages ();
             #endif

                         drot_x = drot_y = drot_z = 0;

             if (mouse.but == 1)
               {
                drot_x = y - mouse.my;
                drot_y = (x - mouse.mx);
               }
             else if (mouse.but == 2)
                drot_z = x - mouse.mx;

             msetxy (204, 178);
             x = 204;
             y = 178;

             trot_x += drot_x;
             trot_y += drot_y;
             trot_z += drot_z;

             if (trot_x >= 360)
               trot_x -= 360;
             if (trot_y >= 360)
               trot_y -= 360;
             if (trot_z >= 360)
               trot_z -= 360;

             if (trot_x < 0)
               trot_x += 360;
             if (trot_y < 0)
               trot_y += 360;
             if (trot_z < 0)
               trot_z += 360;


             MakePlaneMatrix (drot_x, drot_y, drot_z);                                
             Display3D ();
             DisplayVars ();
            }
         }
       PRGUI_ShowMouse ();
      }


    /* Check the variable buttons */
    if (PRGUI_HitButton (XMINUS))
      {
       trot_x -= 0.5;                   /* Decrement the X rotation, */
       if (trot_x < 0)                  /* Wrap if needed */
         trot_x += 360;

           MakePlaneMatrix (-0.5, 0,0);

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;

       if (mouse.but == 2)              /* Delay depending on which button */
         PRGUI_WaitTicks (1);
      }
    else if (PRGUI_HitButton (XPLUS))
      {
       trot_x += 0.5;                   /* Increment the X rotation, */
       if (trot_x >= 360)               /* Wrap if needed */
         trot_x -= 360;

           MakePlaneMatrix (0.5, 0,0);

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;

       if (mouse.but == 2)              /* Delay depending on which button */
         PRGUI_WaitTicks (1);
      }
    else if (PRGUI_HitButton (YMINUS))
      {
       trot_y -= 0.5;                   /* Decrement the Y rotation, */
       if (trot_y < 0)                  /* Wrap if needed */
         trot_y += 360;

           MakePlaneMatrix (0, -0.5, 0);

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;

       if (mouse.but == 2)              /* Delay depending on which button */
         PRGUI_WaitTicks (1);
      }
    else if (PRGUI_HitButton (YPLUS))
      {
       trot_y += 0.5;                   /* Increment the Y rotation, */
       if (trot_y >= 360)               /* Wrap if needed */
         trot_y -= 360;

           MakePlaneMatrix (0, 0.5, 0);

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;

       if (mouse.but == 2)              /* Delay depending on which button */
         PRGUI_WaitTicks (1);
      }
    else if (PRGUI_HitButton (ZMINUS))
      {
       trot_z -= 0.5;                   /* Decrement the Z rotation, */
       if (trot_z < 0)                  /* Wrap if needed */
         trot_z += 360;

           MakePlaneMatrix (0, 0, -0.5);

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;

       if (mouse.but == 2)              /* Delay depending on which button */
         PRGUI_WaitTicks (1);
      }
    else if (PRGUI_HitButton (ZPLUS))
      {
       trot_z += 0.5;                   /* Increment the Z rotation, */
       if (trot_z >= 360)               /* Wrap if needed */
         trot_z -= 360;

           MakePlaneMatrix (0, 0, 0.5);

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;

       if (mouse.but == 2)              /* Delay depending on which button */
         PRGUI_WaitTicks (1);
      }
    else if (PRGUI_HitButton (SXMINUS))
      {
       xscale -= camscale * 10;                  /* Decrement the x scale */
       if (xscale <= 0.05)
         xscale = 0.05;

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if (PRGUI_HitButton (SXPLUS))
      {
       xscale += camscale * 10;                  /* Increment the x scale */

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if (PRGUI_HitButton (SYMINUS))
      {
       yscale -= camscale * 10;                  /* Decrement the y scale */
       if (yscale <= 0.05)
         yscale = 0.05;

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if (PRGUI_HitButton (SYPLUS))
      {
       yscale += camscale * 10;                  /* Increment the y scale */

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if (PRGUI_HitButton (SMINUS))
      {
       xscale -= camscale * 10;                  /* Decrement the x scale */
       if (xscale <= 0.05)
         xscale = 0.05;
       yscale -= camscale * 10;                  /* Decrement the y scale */
       if (yscale <= 0.05)
         yscale = 0.05;

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if (PRGUI_HitButton (SPLUS))
      {
       xscale += camscale * 10;                  /* Increment the x scale */
       yscale += camscale * 10;                  /* Increment the y scale */

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if ((backtext) && (PRGUI_HitButton (PMINUS)))
      {
       backplane -= camscale;           /* Decrement the Z back plane */

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if ((backtext) && (PRGUI_HitButton (PPLUS)))
      {
       backplane += camscale;           /* Increment the Z back plane */

       PRGUI_HideMouse ();              /* Update the display */
       DisplayVars ();
       PRGUI_ShowMouse ();
       remap = 1;
      }
    else if (PRGUI_HitButton (SAVE))
      {
       choice = !PRGUI_ChoiceDialog ("Are you sure you want to save your changes?",
                     "(Data may be lost)", NULL, "Yes", "No");
       if (choice)
         {
          PRGUI_GoUserPath ();
          PR_SavePRO (objectfile, object, SAVE_USED_MATERIALS);
         }
       noclick ();
      }

    if ((mouse.but != 2) && (remap))
      {
       PRGUI_HideMouse ();
       PR_MapObject (object, xscale, yscale);
       Display3D ();
       PRGUI_ShowMouse ();
       remap = 0;
      }
   }

  PRGUI_HideMouse ();
}



void PR_MapVertex (PR_REAL x, PR_REAL y, PR_REAL z,
                   PR_DWORD *u, PR_DWORD *v,
                   PR_REAL xscale, PR_REAL yscale)
/* Given a 3D point, maps the point onto the x/y plane */
{
  *u = ((int)(x * xscale) + map_xofs);
  *v = ((int)(-y * yscale) + map_yofs);

  if (nonwrap)
    {
     if (*u < 1<<16)
       *u = 1<<16; 
     if (*v < 1<<16)
       *v = 1<<16; 
     if (*u >= (texture_width-1) << 16)
       *u = (texture_width-1) << 16; 
     if (*v >= (texture_height-1) << 16)
       *v = (texture_height-1) << 16;
    }
}


void PR_MapVertexHardware (PR_REAL x, PR_REAL y, PR_REAL z,
                   PR_REAL *u, PR_REAL *v,
                   PR_REAL xscale, PR_REAL yscale)
/* Given a 3D point, maps the point onto the x/y plane */
{
  *u = ((x * xscale) + map_xofs) / 65536.0 * PR_WorldTextures[texnum].xscale;
  *v = ((-y * yscale) + map_yofs) / 65536.0 * PR_WorldTextures[texnum].yscale;

/*  if (PR_OutputDevice == DEVICE_D3D)
    {
     *u /= texture_width;
     *v /= texture_height;
    }*/

  if (nonwrap)
    {
     if (*u < 0)
       *u = 0; 
     if (*v < 0)
       *v = 0; 
     if (*u >= PR_Settings.MaxUV)
       *u = PR_Settings.MaxUV; 
     if (*v >= PR_Settings.MaxUV)
       *v = PR_Settings.MaxUV;
    }
}



void PR_MapSegment (PR_SEGMENT *seg, PR_REAL xscale, PR_REAL yscale)
/* Map all the texture coordinates onto a plane, given a segment and a scale */
{
PR_DWORD facenum;
PR_FACE *polyptr;
PR_VERTEX_DATA *vertptr;
PR_DWORD farthestz;

  vertptr = seg->vertex_data;

  for (facenum = 0; facenum < seg->num_faces; facenum++)
   {
    polyptr = &seg->face_list[facenum];

    if ((usemat) && (matnum != polyptr->material) &&
        (frontmaterial != polyptr->material) && (backmaterial != polyptr->material))
      continue;


    if (PR_Settings.Hardware)
      {
       PR_MapVertexHardware (polyptr->vertex1->vdata->vx,
                         polyptr->vertex1->vdata->vy,
                         polyptr->vertex1->vdata->vz,
                         (PR_REAL *)&polyptr->face_data.u[0],
                         (PR_REAL *)&polyptr->face_data.v[0],
                         xscale, yscale);
       PR_MapVertexHardware (polyptr->vertex2->vdata->vx,
                         polyptr->vertex2->vdata->vy,
                         polyptr->vertex2->vdata->vz,
                         (PR_REAL *)&polyptr->face_data.u[1],
                         (PR_REAL *)&polyptr->face_data.v[1],
                         xscale, yscale);
       PR_MapVertexHardware (polyptr->vertex3->vdata->vx,
                         polyptr->vertex3->vdata->vy,
                         polyptr->vertex3->vdata->vz,
                         (PR_REAL *)&polyptr->face_data.u[2],
                         (PR_REAL *)&polyptr->face_data.v[2],
                         xscale, yscale);
      }
    else
      {
      PR_MapVertex (polyptr->vertex1->vdata->vx,
                    polyptr->vertex1->vdata->vy,
                    polyptr->vertex1->vdata->vz,
                    &polyptr->face_data.u[0], &polyptr->face_data.v[0],
                    xscale, yscale);
      PR_MapVertex (polyptr->vertex2->vdata->vx,
                    polyptr->vertex2->vdata->vy,
                    polyptr->vertex2->vdata->vz,
                    &polyptr->face_data.u[1], &polyptr->face_data.v[1],
                    xscale, yscale);
      PR_MapVertex (polyptr->vertex3->vdata->vx,
                    polyptr->vertex3->vdata->vy,
                    polyptr->vertex3->vdata->vz,
                    &polyptr->face_data.u[2], &polyptr->face_data.v[2],
                    xscale, yscale);
      }

    if (backtext)
      {
       /* Now set the front/back texture */
       if (polyptr->vertex1->vdata->vz > polyptr->vertex2->vdata->vz)
         farthestz = polyptr->vertex1->vdata->vz;
       else
         farthestz = polyptr->vertex2->vdata->vz;
       if (polyptr->vertex3->vdata->vz > farthestz)
         farthestz = polyptr->vertex3->vdata->vz;

       if (farthestz > backplane + newcam->source.z)
         polyptr->material = backmaterial;
       else
         polyptr->material = frontmaterial;
      }
     else
      polyptr->material = frontmaterial;
   }
}




void PR_MapObject (PR_OBJECT *obj, PR_REAL xscale, PR_REAL yscale)
{
PR_DWORD objnum;
PR_DWORD ocamx, ocamy;               /* Store old camera coordinates */
PR_MATRIX temp1;

  PR_OpenScreen (PR_BACKBUFFER);

  ocamx = newcam->source.x;  /* We don't want the camera slide to affect */
  ocamy = newcam->source.y;  /* the vertices */

  newcam->source.x = 0;
  newcam->source.y = 0;
  newcam->dest.x = 0;
  newcam->dest.y = 0;
  PR_NewFrame ();
  PR_SetActiveCamera (newcam);

  memcpy (&temp1, &obj1->orientation.rot_mat, sizeof (PR_MATRIX));
  PR_MatrixTranspose (plane_matrix, obj1->orientation.rot_mat);

  PR_TransformEntity (obj1);

  memcpy (&obj1->orientation.rot_mat, &temp1, sizeof (PR_MATRIX));
  map_xofs = (texture_width/2) << 16;
  map_yofs = (texture_height/2) << 16;

  for (objnum = 0; objnum < obj->num_segments; objnum++)
    PR_MapSegment (&obj->segment_list[objnum], xscale, yscale);

  /* Restore the camera slide position */
  newcam->source.x = ocamx;
  newcam->source.y = ocamy;
  newcam->dest.x = ocamx;
  newcam->dest.y = ocamy;
}


void initialize_lights (void)
{
  /* Initialize the lights */
  PR_AllocLights (&userlights, 1);
  PR_AllocLights (&scenelights, 1);

  PR_SetLightPosition (&userlights, 0, 0, 0, 10000);
  PR_SetLightOn (&userlights, 0);
  PR_SetLightColor (&userlights, 0, 1.0, 1.0, 1.0);
  PR_SetLightType (&userlights, 0, DIRECTIONAL_LIGHT);
  PR_SetLightStrength (&userlights, 0, 1.0);
  userlights.NumLights = 1;
}


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
}



color workpal[256];

void main (int argc, char *argv[])
{
PR_MATERIAL m;
PR_DWORD argnum;

//  PR_SetDebugFile ("debug", REPORT_ERRORS | REPORT_ACTIONS);
  PRGUI_InitPath (argv[0]);
  PRGUI_SetUserPath ();

  if (argc < 3)
    {
     PR_FatalError (
                        "TEXSKIN Utility    version "
                        PR_VERSION_NUMBER
                        "\nCopyright 1997 Egerter Software\n\n"
                        "Usage: \n"
            "TEXSKIN filename.PRO front.IMG [back.IMG] [-m materialname]\n"
            "IMG extension can be one of:\n"
            "PCX, BLK, PAK, LBM, IFF, BMP, 3DF\n", "TEXSKIN");

    }

  printf ("TEXSKIN Utility    version ");
  printf (PR_VERSION_NUMBER);
  printf ("\nCopyright 1997 Egerter Software\n\n");


#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 (7500);

  strcpy (texturefile, argv[2]);

  backtext = 0;
  usemat = 0;
  backmaterial = -1;

  argnum = 3;
  while (argnum < argc)
    {
     if (!strcmp (argv[argnum], "-m"))
      {
       if (argc > argnum)
         {
          strcpy (matname, argv[argnum+1]);
          usemat = 1;
          argnum++;
         }
      }
     else
       {
        strcpy (texturefile2, argv[3]);
        backtext = 1;
       }
     argnum++;
    }


  InitializeDevices ();

  PR_AllocMaterials (256);
  PR_AllocShadeTables (32);
  PR_AllocTextures (256);

  PRGUI_GoStartPath ();
  setlib ("guidata.prl");

#ifndef WIN32
 #ifdef __3DFX__
   if (device == DEVICE_3DFX)
     PRGUI_Initialize3Dfx ();
 #endif
 #ifdef __MYST__
   if (device == DEVICE_MYSTIQUE)
     PRGUI_InitializeMystique ();
#endif
   if (device == DEVICE_SVGA)
   PRGUI_InitializeSVGA ();
#endif

#ifdef WIN32
  #if defined (MSGLIDE) || defined (WTGLIDE)
     PRGUI_Initialize3Dfx ();
  #endif
  #if defined (MSDD) || defined (WTDD)
    if (device == DEVICE_D3D)
      PRGUI_InitializeD3D ();
    else
      PRGUI_InitializeSVGA ();
  #endif
#endif

  if (PR_OutputDevice.pages == 1)
    {
     start_screen = PR_FRONTBUFFER;
     end_screen = PR_FRONTBUFFER;
    }
  else 
    {
     start_screen = PR_FRONTBUFFER;
     end_screen = PR_BACKBUFFER;
    }

  strcpy (objectfile, argv[1]);
  PRGUI_GoUserPath ();
  setlib (NULL);

  if (usemat)
    object = PR_LoadPRO (argv[1], LOAD_NORMAL);
  else
    object = PR_LoadPRO (argv[1], LOAD_IGNORE_MATERIALS | LOAD_IGNORE_TEXTURES |
                                  LOAD_IGNORE_TABLES);

  if (object == NULL)
    PR_FatalError ("An error has occurred when loading the PRO file.", "TEXSKIN");
  PRGUI_GoStartPath ();

  if (usemat)
    {
     matnum = PR_FindMaterial (matname);
     if (matnum == MATERIAL_NOT_FOUND)
       matnum = 0; //PR_FatalError ("The material does not exist in this object", "TEXSKIN");
    }

  planeshape = PR_LoadPRO ("plane.pro", LOAD_IGNORE_MATERIALS |
                LOAD_IGNORE_TEXTURES | LOAD_IGNORE_TABLES);
  if (planeshape == NULL)
     PR_FatalError ("An error has occurred when loading the PLANE.PRO file.", "TEXSKIN");

  /* Initialize the plane object */
  PR_CenterObject (planeshape, &cenx, &ceny, &cenz);
  PR_InitializeFaceNormals (planeshape);
  PR_InitializeVertexNormals (planeshape);

  PR_MatrixIdentity (plane_matrix);

  setlib (NULL);
  PRGUI_GoUserPath ();

  /* Load Texture */
  PR_Settings.LoadPalette = 1;
  PR_LoadTexture (texturefile);
  texnum = PR_FindTexture (texturefile);
  if (PR_WorldTextures[texnum].image == NULL)
    PR_FatalError ("Front Texture Not Found", "TEXSKIN");
  /* Wrapping texture if you used a width of 256 */
  if ((texture_width == 256) || (device == DEVICE_3DFX))
    nonwrap = 0;
  else
    nonwrap = 1;

  PRGUI_InitTimer ();

  /* Set up the textured material */
  memset (&m, 0, sizeof (PR_MATERIAL));
  strcpy (m.name, texturefile);
  m.base_color = 0;
  m.render_shades = 32;
  m.texture_number = texnum;
  m.shadetable = 0;
  m.r = 255;
  m.g = 255;
  m.b = 255;
  m.environment_map = 0;
  if (nonwrap)
    m.render_method = T_TEXTURED;
  else
    m.render_method = T_WTEXTURED;
  frontmaterial = PR_AddMaterial (&m);


  if (backtext)
    {
     texnum = PR_LoadTexture (texturefile2);
     if (PR_WorldTextures[texnum].image == NULL)
       PR_FatalError ("Back Texture Not Found", "TEXSKIN");

     strcpy (m.name, texturefile2);
     if (nonwrap)
       m.render_method = T_TEXTURED;
     else
       m.render_method = T_WTEXTURED;
     m.base_color = 0;
     m.render_shades = 32;
     m.texture_number = texnum;
     m.shadetable = 0;
     m.r = 255;
     m.g = 255;
     m.b = 255;
     m.environment_map = 0;
     backmaterial = PR_AddMaterial (&m);
    }


  texture_width = PR_WorldTextures[texnum].width;
  texture_height = PR_WorldTextures[texnum].height;

#if !defined (MSGLIDE) && !defined (WTGLIDE)
  wsetpalette (6, 255, global_palette);
#endif

  /* Initialize the object */
  if (!usemat)
    PR_SetObjectMaterial (object, frontmaterial);

  trot_x = 0;
  trot_y = 0;
  trot_z = 0;

  rot_x = 0;
  rot_y = 0;
  rot_z = 0;

  xscale = (texture_width / 2.0) / object->bbox.radius * 65536.0;
  yscale = (texture_height / 2.0) / object->bbox.radius * 65536.0;

  installkbd ();

  initialize_lights ();

  InitMenu ();

  Init3D ();
  
  Display3D ();

  PRGUI_GoUserPath ();

  program_loop ();

  uninstallkbd ();
  PRGUI_DeinitTimer ();

#ifndef WIN32
  wsetmode (3);
#endif
}



