home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwdos / dosknigh.c < prev    next >
C/C++ Source or Header  |  1995-02-15  |  27KB  |  1,114 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     rwknight.c
  4.  *
  5.  * Abstract :
  6.  *
  7.  * This file is a product of Criterion Software Ltd.
  8.  *
  9.  * This file is provided as is with no warranties of any kind and is
  10.  * provided without any obligation on Criterion Software Ltd. to assist
  11.  * in its use or modification.
  12.  *
  13.  * Criterion Software Ltd. will not, under any circumstances, be liable
  14.  * for any lost revenue or other damages arising
  15.  * from the use of this file.
  16.  *
  17.  * Copyright (c) 1994. Criterion Software Ltd.
  18.  * All Rights Reserved.
  19.  *
  20.  **********************************************************************/
  21.  
  22. /**********************************************************************
  23.  *
  24.  * Header files.
  25.  *
  26.  **********************************************************************/
  27.  
  28. #include <i86.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <math.h>    /* Required for floating point */
  32. #include <string.h>
  33.  
  34. #include "rwlib.h"
  35. #include "rwdos.h"
  36. #include "doswrap.h"
  37.  
  38. #include "danimate.h"
  39. #include "palette.h"
  40.  
  41. #define DEFINE_GLOBAL
  42. #include "dknight.h"
  43. #undef DEFINE_GLOBAL
  44.  
  45. /**********************************************************************
  46.  *
  47.  * Application constants.
  48.  *
  49.  **********************************************************************/
  50.  
  51. /*
  52.  * MS Windows compatible defines for dos keys CTRL and SHIFT
  53.  */
  54.  
  55. #define MK_CONTROL 0x4
  56. #define MK_SHIFT 0x2
  57.  
  58. /**********************************************************************
  59.  *
  60.  * Type definitions.
  61.  *
  62.  **********************************************************************/
  63.  
  64. typedef int BOOL;
  65.  
  66. /*
  67.  * This enumerated type tells us what kind of action should be taken
  68.  * on mouse events.
  69.  */
  70. typedef enum
  71. {
  72.     MMNoAction,
  73.     MMPanCamera,
  74.     MMPanLight
  75. } MMMode;
  76.  
  77. /**********************************************************************
  78.  *
  79.  * Application global variables.
  80.  *
  81.  **********************************************************************/
  82.  
  83. /*
  84.  * This variable tells us what kind of action to take on a mouse move.
  85.  * The action depends on the object that was picked when the mouse button
  86.  * went down, and on the selection of virtual keys that were depressed at
  87.  * that time. By default no action is taken on mouse move.
  88.  */
  89. static MMMode      MouseMoveMode = MMNoAction;
  90.  
  91. /*
  92.  * Global variables used to remember the last mouse X and Y coordinates
  93.  * when involved in a pan, zoom, drag or spin.
  94.  */
  95. static int         LastX;
  96. static int         LastY;
  97.  
  98. /*
  99.  * This flag indicates whether the 3D components of the application
  100.  * have been successfully initialized as yet. It is used to guard
  101.  * the message loop handler functions from being invoked before the
  102.  * 3D components of the application are successfully initialized.
  103.  */
  104. static BOOL        ThreeDInitialized = FALSE;
  105.  
  106. /* The size of the screen
  107.  */
  108.  
  109. static int nGScrWidth;
  110. static int nGScrHeight;
  111.  
  112. /* Text colour
  113.  */
  114.  
  115. static int nGTextColour;
  116.  
  117. /*
  118.  * Line clear string
  119.  */
  120.  
  121. static char sGClear[]="                                  ";
  122.  
  123. /****************************************************************************
  124.  Prototypes
  125.  */
  126.  
  127. RwRaster *ReadBackdrop(char *filename);
  128.  
  129. /**********************************************************************
  130.  *
  131.  * Functions.
  132.  *
  133.  **********************************************************************/
  134.  
  135. /****************************************************************************
  136.  DosShiftCtrl
  137.  
  138.  On entry    :
  139.  On exit    : Bit         Meaning
  140.                         0                Right Shift
  141.                         1                Left Shift
  142.                         2                Ctrl
  143.                         3                Alt
  144.                         4       Scroll Lock
  145.                         5                Num Lock
  146.                         6             Caps Lock
  147.                         7                Insert on
  148.  */
  149.  
  150. int DosShiftCtrl(void)
  151. {
  152.     union REGPACK rp;
  153.  
  154.     memset(&rp,0,sizeof(rp));
  155.  
  156.     rp.h.ah=0x02;
  157.     intr(0x16,&rp);
  158.  
  159.     return ((int)rp.h.al);
  160. }
  161.  
  162.  
  163. /****************************************************************************
  164.  DosPrintString
  165.  
  166.  On entry     : xcord
  167.                         : ycord
  168.                         : string
  169.                         : colour
  170.  On exit        :
  171.  */
  172.  
  173. void DosPrintString(int nX,int nY,char *sString,int nCol)
  174. {
  175.     RwPrintChar pcPrint;
  176.  
  177.     pcPrint.x = nX;
  178.     pcPrint.y = nY;
  179.     pcPrint.color = nCol;
  180.  
  181.     for (;(*sString);sString++)  {
  182.         pcPrint.c = (*sString);
  183.     RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(pcPrint));
  184.         pcPrint.x+=8;
  185.     };
  186. }
  187.  
  188. /****************************************************************************
  189.  DosTimer
  190.  
  191.  On entry    :
  192.  On exit    : Timer (in milliseconds)
  193.  */
  194.  
  195. int DosTimer(void)
  196. {
  197.     union REGS r;
  198.     int nTime;
  199.  
  200.     r.h.ah=0;
  201.  
  202.     int386(0x1a,&r,&r);
  203.  
  204.     nTime = ((r.w.cx)<<16)|(r.w.dx);
  205.  
  206.     return (nTime*55);
  207. }
  208.  
  209.  
  210. /****************************************************************************
  211.  DosGetKey
  212.  
  213.  Get the ascii key code of any depressed key. (Do not wait for a key press.
  214.  -> return 0 if no key is pressed)
  215.  
  216.  On entry    :
  217.  On exit     : Key pressed in ascii (or 0 if no key pressed)
  218.  */
  219.  
  220. int DosGetKey(void)
  221. {
  222.     union REGPACK rp;
  223.  
  224.     memset(&rp,0,sizeof(rp));
  225.     rp.h.ah = 0x06;
  226.     rp.h.dl = 0xff;
  227.  
  228.     intr(0x21,&rp);
  229.  
  230.     if (!(rp.w.flags & 0x40 )) {       /* Check Z flag */
  231.         /* Got key */
  232.  
  233.         if (rp.h.al) {
  234.             return ((int)rp.h.al);
  235.         };
  236.  
  237.         memset(&rp,0,sizeof(rp));
  238.         rp.h.ah = 0x06;
  239.         rp.h.dl = 0xff;
  240.         intr(0x21,&rp);
  241.  
  242.         if (!(rp.w.flags & 0x40)) {
  243.             return ((int)rp.h.al);
  244.         };
  245.  
  246.         return (rp.h.al|0x80);
  247.     };
  248.  
  249.     return 0;
  250. }
  251.  
  252.  
  253. /**********************************************************************/
  254.  
  255. /*
  256.  * This function initializes the 3D (i.e. RenderWare) components of the
  257.  * application. This function opens the RenderWare library, creates a
  258.  * camera, a scene, a light and a matrix for spinning.
  259.  */
  260. static BOOL
  261. Init3D()
  262. {
  263.     char windowText[128];
  264.     char version[30];
  265.     int  depth;
  266.     RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  267.     long nError;
  268.     char buffer[256];
  269.     int i;
  270.   RwRaster *Raster;
  271.   RwReal naBlack[] = {CREAL(0.0),CREAL(0.0),CREAL(0.0)};
  272.   int nBlack;
  273.   RwPointerImage piImage;
  274.  
  275.     /*
  276.     * Attempt to open (and initialize) the RenderWare library.
  277.     */
  278.   if (!RwOpen("DOSMOUSE", &nError))
  279.     {
  280.         printf("Unable to access renderware!!\n");
  281.         switch (nError) {
  282.             case E_RW_DOS_MODE_UNAVAILABLE: {
  283.                printf("The installed VESA card is unable to switch to the resolution");
  284.                 printf(" requested.\n");
  285.                 printf("Either install a different video adapter or use a ");
  286.                 printf("supported video mode.");
  287.                 break;
  288.             };
  289.             case E_RW_DOS_NO_VESA_BIOS: {
  290.                 printf("A VESA bios is unavailable on this machine.\n");
  291.                 printf("Either use a VESA compatible Video Adapter or install a ");
  292.                 printf("VESA bios emulation TSR.\n");
  293.                 break;
  294.             };
  295.             case E_RW_DOS_INCOMPATIBLE_BIOS: {
  296.                 printf("The VESA bios on this machine is not of high enough version ");
  297.                 printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
  298.                 printf(" higher VESA bios or TSR.\n");
  299.                 break;
  300.             };
  301.             case E_RW_DOS_NO_MOUSE: {
  302.                 printf("No Microsoft compatible mouse driver present.\n");
  303.                 printf("Install a microsoft compatible mouse driver and try again.\n");
  304.                 break;
  305.             };
  306.             default: {
  307.                 printf("Unknown Error !!!!!!!!!!!!!!!\n");
  308.                 break;
  309.             };
  310.         };
  311.         return FALSE;
  312.     }
  313.  
  314.   /* load the palette */
  315.  
  316.   CheckAndReadPalette("rwknight.pal");
  317.  
  318.   nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
  319.   nBlack = RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack));
  320.  
  321.   /* Rematch the pointer image */
  322.  
  323.   piImage.image = NULL;
  324.   piImage.hotx=0;
  325.   piImage.hoty=0;
  326.   piImage.w = nBlack;
  327.   piImage.h = nGTextColour;
  328.  
  329.   RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
  330.  
  331.     /*--- Only look for scripts and textures in subdirectories under the current
  332.     one. RWSHAPEPATH need not be set then */
  333.  
  334.     RwSetShapePath(".",rwPRECONCAT);
  335.  
  336.     strcpy(buffer,".");
  337.  
  338.     i = strlen(buffer);
  339.     while((buffer[i] != '\\')&&(i>=0)) {
  340.         i--;
  341.     };
  342.  
  343.  
  344.     if (i>=0) {
  345.         buffer[i+1] = 0;
  346.         strcat(buffer, "TEXTURES");
  347.         RwSetShapePath(buffer, rwPOSTCONCAT);
  348.  
  349.         buffer[i+1] = 0;
  350.         strcat(buffer, "SCRIPTS");
  351.         RwSetShapePath(buffer, rwPOSTCONCAT);
  352.     };
  353.  
  354.     RwSetShapePath("SCRIPTS", rwPRECONCAT);
  355.     RwSetShapePath("TEXTURES", rwPRECONCAT);
  356.  
  357.  
  358.     /* Set up display size*/
  359.  
  360.   RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
  361.   RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
  362.  
  363.     /*
  364.      * Label the window with information about the version of
  365.      * RenderWare being used. Its rather unlikely that
  366.      * RwGetSystemInfo() or RwGetDeviceInfo() will fail so we ignore its
  367.      * return value.
  368.      */
  369.     RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
  370.     RwGetDeviceInfo(rwRENDERDEPTH, &depth,sizeof(depth));
  371.     sprintf(windowText, "DosKnight V%s %d-bit Rendering",
  372.             version, depth);
  373.         DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
  374.         DosPrintString(0,nGScrHeight-8,
  375.             "Demo    Knight1 Knight2 Observer",nGTextColour);
  376.  
  377.     MainCamera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
  378.     if (!MainCamera)
  379.     {
  380.         /*
  381.           * As with RwOpen(), the most common cause for a failure to create
  382.           * a camera is insufficient memory so we will explicitly check for
  383.           * this condition and report it. Otherwise a general error is issued.
  384.           */
  385.         if (RwGetError() == E_RW_NOMEM)
  386.         {
  387.             RwClose();
  388.             printf("Insufficient memory to create the RenderWare(tm) main camera\n");
  389.         }
  390.         else
  391.         {
  392.             RwClose();
  393.             printf("Error creating the RenderWare(tm) main camera\n");
  394.         }
  395.         exit(-1);
  396.     }
  397.  
  398.  
  399.     FlyCamera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
  400.     if (!FlyCamera)
  401.     {
  402.         /*
  403.           * As with RwOpen(), the most common cause for a failure to create
  404.           * a camera is insufficient memory so we will explicitly check for
  405.           * this condition and report it. Otherwise a general error is issued.
  406.           */
  407.         if (RwGetError() == E_RW_NOMEM)
  408.         {
  409.             RwClose();
  410.             printf("Insufficient memory to create the RenderWare(tm) main camera\n");
  411.         }
  412.         else
  413.         {
  414.             RwClose();
  415.             printf("Error creating the RenderWare(tm) main camera\n");
  416.         }
  417.         exit(-1);
  418.     }
  419.  
  420.   RwSetCameraViewport(MainCamera, 0, 0, nGScrWidth, nGScrHeight-24);
  421.   RwSetCameraViewport(FlyCamera, 0, 0, nGScrWidth, nGScrHeight-24);
  422.  
  423.   Camera = MainCamera;
  424.  
  425.   /* now add the backdrop */
  426.   Raster = RwReadRaster("cast256.bmp", 0L);
  427.   if (Raster)
  428.   {
  429.       /* Destroy the existing backdrop raster (if any). */
  430.  
  431.       if (RwGetCameraBackdrop(MainCamera))
  432.           RwDestroyRaster(RwGetCameraBackdrop(MainCamera));
  433.  
  434.       /* Set the new backdrop raster. */
  435.  
  436.       RwSetCameraBackdrop(MainCamera, Raster);
  437.       RwSetCameraBackdrop(FlyCamera, Raster);
  438.   }
  439.  
  440.   /*
  441.     * By default, the camera lies on the X-Z plane and points down Z
  442.     * into the screen. We shall retain the camera's orientation, but move
  443.     * the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
  444.     */
  445.  
  446.     RwVCMoveCamera(MainCamera, CREAL(0.0), CREAL(0.0), CAMERA_DISTANCE);
  447.  
  448.   if (nGScrWidth >= nGScrHeight)
  449.   {
  450.       RwSetCameraViewwindow(MainCamera, CREAL(0.4), RMul(CREAL(0.4), RDiv(INT2REAL(nGScrHeight), INT2REAL(nGScrWidth))));
  451.       RwSetCameraViewwindow(FlyCamera, CREAL(0.4), RMul(CREAL(0.4), RDiv(INT2REAL(nGScrHeight), INT2REAL(nGScrWidth))));
  452.   } else {
  453.       RwSetCameraViewwindow(MainCamera, RMul(CREAL(0.4), RDiv(INT2REAL(nGScrWidth), INT2REAL(nGScrHeight))), CREAL(0.4));
  454.       RwSetCameraViewwindow(FlyCamera, RMul(CREAL(0.4), RDiv(INT2REAL(nGScrWidth), INT2REAL(nGScrHeight))), CREAL(0.4));
  455.   };
  456.  
  457.  
  458.   RwSetCameraBackdropViewportRect(MainCamera, 0, 0, nGScrWidth, nGScrHeight);
  459.   RwSetCameraBackdropViewportRect(FlyCamera, 0, 0, nGScrWidth, nGScrHeight);
  460.  
  461.     /*
  462.     * Create a scene which will contain the clumps to be rendered and the
  463.     * light or lights illuminating those clumps . In this very simple
  464.     * application it would be perfectly acceptable to use the default scene
  465.     * (as returned by RwDefaultScene()) for rendering. However, it is good
  466.     * practice to always create a scene which will be used for your rendering
  467.     * and only use the default scene as a bag for currently unused clumps and
  468.     * lights.
  469.     */
  470.  
  471.     Scene = RwCreateScene();
  472.     if (!Scene)
  473.     {
  474.         RwDestroyCamera(Camera);
  475.         RwClose();
  476.         printf("Error creating the RenderWare(tm) scene\n");
  477.         exit(-1);
  478.     }
  479.  
  480.  
  481.  
  482.     /*
  483.      * Our scene will be illuminated by a directional light. The illumination
  484.      * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
  485.      */
  486.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  487.                           CREAL(1.0));
  488.     if (!Light)
  489.     {
  490.         RwDestroyScene(Scene);
  491.         RwDestroyCamera(FlyCamera);
  492.         RwDestroyCamera(MainCamera);
  493.         RwClose();
  494.         printf("Error creating the RenderWare(tm) light\n\n");
  495.         return FALSE;
  496.     }
  497.  
  498.     /*
  499.     * Our scene will be illuminated by a directional light. The illumination
  500.     * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
  501.     */
  502.  
  503.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  504.                       CREAL(1.0));
  505.     if (!Light)
  506.     {
  507.         RwDestroyScene(Scene);
  508.         RwDestroyCamera(Camera);
  509.         RwClose();
  510.         printf("Error creating the RenderWare(tm) light\n");
  511.         exit(-1);
  512.     }
  513.  
  514.     /*
  515.     * Add the new light to our scene.
  516.     */
  517.     RwAddLightToScene(Scene, Light);
  518.  
  519.     /*
  520.      * All the 3D components are now successfully initialized, so
  521.      * work can begin...
  522.      */
  523.     ThreeDInitialized = TRUE;
  524.  
  525.     SetCameraState(CAM_MAIN);
  526.     return TRUE;
  527. }
  528.  
  529. /**********************************************************************/
  530.  
  531. /*
  532.  * This function shuts down the 3D (i.e. RenderWare) components of the
  533.  * application in a polite fashion.
  534.  */
  535. static void
  536. TidyUp3D(void)
  537. {
  538.  
  539.     /*
  540.      * Destroy the scene. This will destroy the contents of the scene,
  541.      * i.e. any clumps and lights in that scene. In this case destroying
  542.      * the scene will destroy the light we created in Init3D, and any
  543.      * clumps we have loaded and not already destroyed.
  544.      */
  545.     RwDestroyScene(Scene);
  546.  
  547.     /*
  548.      * Destroy the camera's backdrop (if any). Backdrops are not
  549.      * automatically destroyed by RwDestroyCamera() so we must
  550.      * manually destroy the backdrop.
  551.      */
  552.     if (RwGetCameraBackdrop(MainCamera))
  553.     {
  554.         RwDestroyRaster(RwGetCameraBackdrop(MainCamera));
  555.         RwSetCameraBackdrop(MainCamera, NULL);
  556.         RwSetCameraBackdrop(FlyCamera, NULL);
  557.     }
  558.  
  559.     /*
  560.      * Destroy the camera.
  561.      */
  562.      RwDestroyCamera(FlyCamera);
  563.      RwDestroyCamera(MainCamera);
  564.  
  565.     /*
  566.      * Close the library. This will free up any internal resources and
  567.      * textures loaded.
  568.      */
  569.     RwClose();
  570. }
  571.  
  572. /**********************************************************************/
  573.  
  574. /*
  575.  * Render the scene and copy it to the window and device context
  576.  * given. This function encapsulates the very common RenderWare
  577.  * for rendering and updating the display.
  578.  */
  579. static void
  580. RenderScene(void)
  581. {
  582.     RwBeginCameraUpdate(Camera,NULL);
  583.     RwClearCameraViewport(Camera);
  584.     RwRenderScene(Scene);
  585.     RenderKnight();
  586.     RwEndCameraUpdate(Camera);
  587.  
  588.     RwShowCameraImage(Camera, NULL);
  589. }
  590.  
  591. /****************************************************************************
  592.  Load a clump
  593.  */
  594.  
  595. RwClump *
  596. LoadClump(char *fileName)
  597. {
  598.     RwClump    *clump;
  599.     RwTexture  *texture;
  600.     char        buffer[128];
  601.     RwErrorCode eCode;
  602.  
  603.     DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  604.     DosPrintString(0,nGScrHeight-24,"Loading File...",nGTextColour);
  605.  
  606.     /*
  607.     * Attempt to load the file as a script file.
  608.     */
  609.     clump = RwReadShape(fileName);
  610.     if (!clump)
  611.         {
  612.         /*
  613.         * The load failed. This could be because of errors in the
  614.         * script file, insufficient memory, or the file containing
  615.         * garbage. We will now examine the error code returned to
  616.         * decide whether there was a script file error (in which case
  617.         * an error will be issued to the user), whether memory was
  618.         * exhausted (a different error is issued to the user), or
  619.         * the file contained garbage (in which case we will attempt
  620.         * to load the file as a texture instead of a script).
  621.         */
  622.         eCode = RwGetError();
  623.  
  624.         switch (eCode)
  625.             {
  626.             case E_RW_NOMEM:
  627.             /*
  628.             * Ran out of memory...
  629.             */
  630.  
  631.             sprintf(buffer, "Insufficient memory : %s",fileName);
  632.             buffer[40]='\0';
  633.             DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  634.             DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
  635.             return NULL;
  636.  
  637.             case E_RW_NOFILE:
  638.             case E_RW_BADOPEN:
  639.             case E_RW_RSPARSE:
  640.             case E_RW_RSREAD:
  641.             case E_RW_READ:
  642.             /*
  643.             * We will (somewhat optimistically) assume that if we
  644.             * had a read or parse error on the stream then the
  645.             * file is not a script file but a texture instead.
  646.             * So attempt to load a texture. Note, as we use
  647.             * RwGetNamedTexture() to get the texture, the texture
  648.             * will not be reloaded if it has been previously loaded
  649.             * into RenderWare.
  650.             */
  651.             texture = RwGetNamedTexture(fileName);
  652.             if (texture)
  653.                 {
  654.                 /*
  655.                 * The file was indeed a texture, so attempt to
  656.                 * create a decal clump using this texture.
  657.                 */
  658.         clump = RwCreateSprite(texture);
  659.             }
  660.             else
  661.                 {
  662.                 /*
  663.                 * The texture load failed, issue an error message
  664.                 * giving the general nature of the problem.
  665.                 */
  666.                 switch (RwGetError())
  667.                 {
  668.                 case E_RW_NOFILE:
  669.                 case E_RW_BADOPEN:
  670.                 /*
  671.                 * Could not open the file...
  672.                 */
  673.                 sprintf(buffer, "Error opening %s", fileName);
  674.                 buffer[40]='\0';
  675.                 DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  676.                 DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
  677.                 return NULL;
  678.  
  679.                 case E_RW_NOMEM:
  680.                 /*
  681.                 * Ran out of memory...
  682.                 */
  683.                 sprintf(buffer,
  684.                     "No mem for texture %s",
  685.                     fileName);
  686.                 buffer[40]='\0';
  687.                 DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  688.                 DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
  689.                 return NULL;
  690.  
  691.                 default:
  692.                 /*
  693.                 * We will not enumerate all the errors, so simply
  694.                 * issue a general failure report.
  695.                 */
  696.                 sprintf(buffer,
  697.                     "Error reading file %s",
  698.                     fileName);
  699.                 buffer[40]='\0';
  700.                 DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  701.                 DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
  702.                 return NULL;
  703.                 }
  704.             }
  705.             break;
  706.  
  707.             default:
  708.             /*
  709.             * On any other error we will assume there is an error in
  710.             * the script file.
  711.             */
  712.             sprintf(buffer,
  713.             "Error in file %s <%i>",fileName,(int)eCode);
  714.             buffer[40]='\0';
  715.  
  716.             DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  717.             DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
  718.             return NULL;
  719.         }
  720.     }
  721.  
  722.  
  723.     /*
  724.     * Return the resulting clump.
  725.     */
  726.     DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
  727.     return clump;
  728. }
  729.  
  730. /**********************************************************************/
  731.  
  732. static void
  733. HandleLeftButtonDown(int x, int y,int vKeys)
  734. {
  735.   /* Stop warnings */
  736.  
  737.   vKeys = vKeys;
  738.  
  739.         if (y>nGScrHeight-8) {
  740.             switch(x>>6) {
  741.                 case 0: {
  742.                     /* Demo */
  743.           InterActive = (InterActive) ? FALSE : TRUE;
  744.                     break;
  745.                 };
  746.                 case 1: {
  747.                     /* Knight1 */
  748.           SetCameraState(CAM_FLY1);
  749.                     break;
  750.                 };
  751.                 case 2: {
  752.                     /* Knight2 */
  753.           SetCameraState(CAM_FLY2);
  754.                     break;
  755.                 };
  756.                 case 3: {
  757.                     /* Observer */
  758.           if (CameraState == CAM_KNIGHT1) {
  759.             SetCameraState(CAM_FLY1);
  760.                     } else if (CameraState == CAM_KNIGHT2) {
  761.             SetCameraState(CAM_FLY2);
  762.                     };
  763.                     break;
  764.                 };
  765.                 default: {
  766.                     break;
  767.                 };
  768.             };
  769.         };
  770.  
  771.         if (MouseMoveMode != MMNoAction)
  772.     {
  773.         LastX = x;
  774.         LastY = y;
  775.     }
  776. }
  777.  
  778. /**********************************************************************/
  779.  
  780. static void
  781. HandleRightButtonDown(int x, int y, int vKeys)
  782. {
  783.     if (vKeys & MK_CONTROL)
  784.     {
  785.         MouseMoveMode = MMPanLight;
  786.     }
  787.     else
  788.     {
  789.         MouseMoveMode = MMPanCamera;
  790.     }
  791.  
  792.     if (MouseMoveMode != MMNoAction)
  793.     {
  794.         LastX = x;
  795.         LastY = y;
  796.     }
  797. }
  798.  
  799. /**********************************************************************/
  800.  
  801. static void
  802. HandleMouseMove( int x, int y)
  803. {
  804.  
  805.     /*
  806.      * MouseMoveMode tells us what kind of action to perform.
  807.      */
  808.     switch (MouseMoveMode)
  809.     {
  810.         case MMNoAction:
  811.             break;
  812.  
  813.         case MMPanCamera:
  814.             RwVCMoveCamera(MainCamera, CREAL(0.0), CREAL(0.0), -CAMERA_DISTANCE);
  815.             RwPanCamera(MainCamera, INT2REAL(LastX - x));
  816.             RwVCMoveCamera(MainCamera, CREAL(0.0), CREAL(0.0), CAMERA_DISTANCE);
  817.             if (CameraState == CAM_MAIN)
  818.                 SetBackdrop(MainCamera);
  819.             break;
  820.  
  821.         case MMPanLight:
  822.  
  823.             RwPushScratchMatrix();
  824.             RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
  825.                                INT2REAL(LastX - x), rwREPLACE);
  826.  
  827.             RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
  828.                                INT2REAL(LastY - y), rwPOSTCONCAT);
  829.  
  830.             RwTransformLight(Light, RwScratchMatrix(),rwPOSTCONCAT);
  831.             RwPopScratchMatrix();
  832.             break;
  833.     }
  834.  
  835.     if (MouseMoveMode != MMNoAction)
  836.     {
  837.         LastX = x;
  838.         LastY = y;
  839.     }
  840.  
  841. }
  842.  
  843. /**********************************************************************/
  844.  
  845. static void
  846. HandleLeftButtonUp(void)
  847. {
  848.     if (MouseMoveMode != MMNoAction)
  849.     {
  850.         MouseMoveMode = MMNoAction;
  851.     }
  852. }
  853.  
  854. /**********************************************************************/
  855.  
  856. static void
  857. HandleRightButtonUp(void)
  858. {
  859.     if (MouseMoveMode != MMNoAction)
  860.     {
  861.         MouseMoveMode = MMNoAction;
  862.     }
  863. }
  864.  
  865. /**********************************************************************/
  866.  
  867. static void
  868. HandleTimer()
  869. {
  870.     AnimateScene();
  871.     AnimateCamera();
  872.     /*
  873.      * Re-render the scene and copy the results to the display.
  874.      */
  875.     RenderScene();
  876. }
  877.  
  878.  
  879. /**********************************************************************/
  880. /*static void
  881. HandleMenu(HWND window, WORD menuItem)
  882. {
  883.     RECT rect;
  884.  
  885.     switch (menuItem)
  886.     {
  887.         case M_EXIT:
  888.             SendMessage(window, WM_CLOSE, 0, 0L);
  889.             break;
  890.         case M_WING:
  891.           CheckMenuItem(MainMenu, M_WING, (WingOn) ? (MF_BYCOMMAND|MF_UNCHECKED) : (MF_BYCOMMAND|MF_CHECKED));
  892.           WingOn = (WingOn) ? FALSE : TRUE;
  893.           GetWindowRect(window, &rect);
  894.           if (WingOn)
  895.             MoveWindow(window, rect.left, rect.top,
  896.                       (rect.right - rect.left) * 2,
  897.                       (rect.bottom - rect.top) * 2, TRUE);
  898.           else
  899.             MoveWindow(window, rect.left, rect.top,
  900.                       (rect.right - rect.left) / 2,
  901.                       (rect.bottom - rect.top) / 2, TRUE);
  902.           break;
  903.         case M_DEMO:
  904.           CheckMenuItem(MainMenu, M_DEMO, (!InterActive) ? (MF_BYCOMMAND|MF_UNCHECKED) : (MF_BYCOMMAND|MF_CHECKED));
  905.           InterActive = (InterActive) ? FALSE : TRUE;
  906.          break;
  907.         case M_KNIGHT1:
  908.           SetCameraState(CAM_FLY1);
  909.           break;
  910.         case M_KNIGHT2:
  911.           SetCameraState(CAM_FLY2);
  912.           break;
  913.         case M_OBSERVER:
  914.           if (CameraState == CAM_KNIGHT1)
  915.             SetCameraState(CAM_FLY1);
  916.           else if (CameraState == CAM_KNIGHT2)
  917.             SetCameraState(CAM_FLY2);
  918.           break;
  919.         case M_ABOUT:
  920.           KillTimer(window, 1);
  921.           DialogBox(AppInstance, "ABOUT", window, MakeProcInstance(AboutDlgProc, AppInstance));
  922.           SetTimer( window, 1, 20, NULL );
  923.           break;
  924.     }
  925. } */
  926.  
  927.  
  928. /**********************************************************************/
  929.  
  930. /*int PASCAL
  931. WinMain(HANDLE instance, HANDLE prevInstance, LPSTR cmdLine, int cmdShow)
  932. {
  933.     MSG  message;
  934.     HWND window;
  935.  
  936.     if (!LoadKnight(window, instance, Scene))
  937.     {
  938.         TidyUp3D();
  939.         DestroyWindow(window);
  940.         return FALSE;
  941.     }
  942.     AnimateKnight(1, "BOB1");
  943.  
  944.     ShowWindow(window, cmdShow);
  945.     UpdateWindow(window);
  946.  
  947.     while (GetMessage(&message, (HWND)0, NULL, NULL))
  948.     {
  949.         TranslateMessage(&message);
  950.         DispatchMessage(&message);
  951.     }
  952.     TidyUp3D();
  953.  
  954.     return message.wParam;
  955. }
  956.  
  957. */
  958.  
  959. void main(int nArgc,char *saArgv[])
  960. {
  961.     int nKey;
  962.     int nOldMouseBut;
  963.     int nDX,nDY;
  964.     int nChange;
  965.     int nCtrlShift;
  966.     RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
  967.     RwReal naBlack[]={CREAL(0.0),CREAL(0.0),CREAL(0.0)};
  968.     RwMousePointer mMouse;
  969.     int nBlack,nWhite;
  970.  
  971.   /* Stop warnings */
  972.  
  973.   nArgc = nArgc;
  974.   saArgv = saArgv;
  975.  
  976.     if (!Init3D())
  977.     {
  978.         exit(-1);
  979.     };
  980.  
  981.   nBlack = RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack));
  982.   nWhite = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
  983.  
  984.     nKey = DosGetKey();
  985.  
  986.   if (!LoadKnight(Scene))
  987.   {
  988.       TidyUp3D();
  989.             exit(-1);
  990.   }
  991.   AnimateKnight(1, "BOB1");
  992.  
  993.     while (nKey!=27) {        /* ESC quits */
  994.  
  995.     RwDeviceControl(rwPOINTERDISPLAY,0,&mMouse,sizeof(mMouse));
  996.         nKey = DosGetKey();
  997.  
  998.         nCtrlShift = DosShiftCtrl();
  999.  
  1000.         nDX =(mMouse.x-LastX);
  1001.         nDY =(mMouse.y-LastY);
  1002.  
  1003.         nChange = (mMouse.buttons&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
  1004.  
  1005.         switch (nChange) {
  1006.             case 0+0:
  1007.             case 2+1:
  1008.             case 8+4:
  1009.             case 8+2+4+1: {
  1010.                 /* No change */
  1011.                 break;
  1012.             };
  1013.             case 2:
  1014.             case 8+2+4: {
  1015.  
  1016.                 /* Left Button Down */
  1017.  
  1018.                 HandleLeftButtonDown(mMouse.x,mMouse.y,nCtrlShift);
  1019.  
  1020.                 break;
  1021.             };
  1022.             case 8:
  1023.             case 8+2+1: {
  1024.                 /* Right Button Down */
  1025.  
  1026.  
  1027.                 HandleRightButtonDown(mMouse.x,mMouse.y,nCtrlShift);
  1028.  
  1029.                 break;
  1030.             };
  1031.             case 8+1: {
  1032.                 /* Right down left Up */
  1033.  
  1034.                 HandleLeftButtonUp();
  1035.                 HandleRightButtonDown(mMouse.x,mMouse.y,nCtrlShift);
  1036.  
  1037.                 break;
  1038.             };
  1039.             case 2+4: {
  1040.                 /* Right up left Down */
  1041.  
  1042.  
  1043.                 HandleRightButtonUp();
  1044.                 HandleLeftButtonDown(mMouse.x,mMouse.y,nCtrlShift);
  1045.  
  1046.  
  1047.                 break;
  1048.             };
  1049.             case 8+2: {
  1050.                 /* Left down RIght Down */
  1051.  
  1052.  
  1053.                 HandleRightButtonDown(mMouse.x,mMouse.y,nCtrlShift);
  1054.                 HandleLeftButtonDown(mMouse.x,mMouse.y,nCtrlShift);
  1055.  
  1056.  
  1057.                 break;
  1058.             };
  1059.             case 1+4: {
  1060.                 /* Left up Right Up */
  1061.  
  1062.  
  1063.                 HandleRightButtonUp();
  1064.                 HandleLeftButtonUp();
  1065.  
  1066.  
  1067.                 break;
  1068.             };
  1069.             case 1:
  1070.             case 8+4+1: {
  1071.                 /* Left up */
  1072.  
  1073.  
  1074.                 HandleLeftButtonUp();
  1075.  
  1076.  
  1077.                 break;
  1078.             };
  1079.             case 4:
  1080.             case 2+4+1: {
  1081.                 /* Right up */
  1082.  
  1083.  
  1084.                 HandleRightButtonUp();
  1085.  
  1086.  
  1087.                 break;
  1088.             };
  1089.         };
  1090.  
  1091.         if (nDX||nDY) {
  1092.             /* Mouse Move  */
  1093.             HandleMouseMove(mMouse.x,mMouse.y);
  1094.         };
  1095.  
  1096.         HandleTimer();
  1097.  
  1098.         LastX = mMouse.x;
  1099.         LastY = mMouse.y;
  1100.         nOldMouseBut = mMouse.buttons;
  1101.     };
  1102.  
  1103.     /*
  1104.     * Tidy up the 3D (RenderWare) components of the application.
  1105.     */
  1106.  
  1107.     TidyUp3D();
  1108.  
  1109.     exit(0);
  1110. }
  1111.  
  1112.  
  1113.  
  1114.