home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwwin / rwknight.c_ / rwknight.bin
Text File  |  1995-11-14  |  28KB  |  973 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, 1995. Criterion Software Ltd.
  18.  * All Rights Reserved.
  19.  *
  20.  **********************************************************************/
  21.  
  22. /**********************************************************************
  23.  *
  24.  * Header files.
  25.  *
  26.  **********************************************************************/
  27.  
  28. #include <windows.h>
  29. #include <mmsystem.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33.  
  34. #include "rwlib.h"
  35. #include "rwwin.h"
  36.  
  37. #include "palette.h"
  38. #include "common.h"
  39.  
  40. #include "animate.h"
  41.  
  42. #define DEFINE_GLOBAL
  43. #include "knight.h"
  44. #undef DEFINE_GLOBAL
  45. /**********************************************************************
  46.  *
  47.  * Application constants.
  48.  *
  49.  **********************************************************************/
  50.  
  51. /*
  52.  * Class name for the MS Window's window class.
  53.  */
  54. #define RWKNIGHT_CLASS_NAME       "RwKnightClass"
  55.  
  56. /*
  57.  * Error dialog box title.
  58.  */
  59. #define ERROR_DIALOG_TITLE      "RenderWare Knight Error"
  60.  
  61. /*
  62.  * Maximum size of the viewer's window.
  63.  */
  64. #define MAXIMUM_WINDOW_WIDTH    640
  65. #define MAXIMUM_WINDOW_HEIGHT   480
  66.  
  67. #define DEFAULT_WINDOW_WIDTH    320
  68. #define DEFAULT_WINDOW_HEIGHT   240
  69.  
  70. #define MAXIMUM_CAMERA_WIDTH    (MAXIMUM_WINDOW_WIDTH/2)
  71. #define MAXIMUM_CAMERA_HEIGHT   (MAXIMUM_WINDOW_HEIGHT/2)
  72. /**********************************************************************
  73.  *
  74.  * Forward functions.
  75.  *
  76.  **********************************************************************/
  77.  
  78. extern LRESULT CALLBACK
  79. MainWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
  80.  
  81. /**********************************************************************
  82.  *
  83.  * Type definitions.
  84.  *
  85.  **********************************************************************/
  86.  
  87. /*
  88.  * This enumerated type tells us what kind of action should be taken
  89.  * on mouse events.
  90.  */
  91. typedef enum
  92. {
  93.     MMNoAction,
  94.     MMPanCamera,
  95.     MMPanLight
  96. } MMMode;
  97.  
  98. /**********************************************************************
  99.  *
  100.  * Application global variables.
  101.  *
  102.  **********************************************************************/
  103.  
  104. HANDLE AppInstance;
  105.  
  106. /*
  107.  * This variable tells us what kind of action to take on a mouse move.
  108.  * The action depends on the object that was picked when the mouse button
  109.  * went down, and on the selection of virtual keys that were depressed at
  110.  * that time. By default no action is taken on mouse move.
  111.  */
  112. static MMMode      MouseMoveMode = MMNoAction;
  113.  
  114. /*
  115.  * Global variables used to remember the last mouse X and Y coordinates
  116.  * when involved in a pan, zoom, drag or spin.
  117.  */
  118. static int         LastX;
  119. static int         LastY;
  120.  
  121. static int     Stretching = FALSE;
  122. static int     MaxWindowWidth = DEFAULT_WINDOW_WIDTH;
  123. static int     MaxWindowHeight = DEFAULT_WINDOW_HEIGHT;
  124.  
  125. /*
  126.  * This flag indicates whether the 3D components of the application
  127.  * have been successfully initialized as yet. It is used to guard
  128.  * the message loop handler functions from being invoked before the
  129.  * 3D components of the application are successfully initialized.
  130.  */
  131. static BOOL        ThreeDInitialized = FALSE;
  132.  
  133. /**********************************************************************
  134.  *
  135.  * Functions.
  136.  *
  137.  **********************************************************************/
  138.  
  139. /**********************************************************************/
  140. void SetMaxValues(void)
  141. {
  142.    if (Stretching)
  143.    {
  144.        MaxWindowWidth = MAXIMUM_WINDOW_WIDTH;
  145.        MaxWindowHeight = MAXIMUM_WINDOW_HEIGHT;
  146.    }
  147.    else
  148.    {
  149.        MaxWindowWidth = MAXIMUM_CAMERA_WIDTH;
  150.        MaxWindowHeight = MAXIMUM_CAMERA_HEIGHT;
  151.    }
  152. }
  153.  
  154. /**********************************************************************/
  155.  
  156. /*
  157.  * Perform any necessary MS Windows application initialization. Basically,
  158.  * this means registering the window class for this application.
  159.  */
  160. static BOOL
  161. InitApplication(HANDLE instance)
  162. {
  163.     WNDCLASS windowClass;
  164.  
  165.     windowClass.style         = CS_BYTEALIGNWINDOW;
  166.     windowClass.lpfnWndProc   = (WNDPROC)MainWndProc;
  167.     windowClass.cbClsExtra    = 0; 
  168.     windowClass.cbWndExtra    = 0; 
  169.     windowClass.hInstance     = instance; 
  170.     windowClass.hIcon         = LoadIcon(instance, "RW_ICON");
  171.     windowClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  172.     windowClass.hbrBackground = NULL; 
  173.     windowClass.lpszMenuName  = MAKEINTRESOURCE(KNIGHT_MENU);
  174.     windowClass.lpszClassName = RWKNIGHT_CLASS_NAME;
  175.  
  176.     return RegisterClass(&windowClass);
  177. }
  178.  
  179. /**********************************************************************/
  180.  
  181. /*
  182.  * Perform any necessary initialization for this instance of the
  183.  * application. This simply means creating the application's main
  184.  * window.
  185.  */
  186. static HWND
  187. InitInstance(HANDLE instance)
  188. {
  189.     return CreateWindow(RWKNIGHT_CLASS_NAME, "",
  190.                         WS_OVERLAPPEDWINDOW,
  191.                         CW_USEDEFAULT, CW_USEDEFAULT,
  192.                         DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT,
  193.                         NULL, NULL, instance, NULL);
  194. }
  195.  
  196.  
  197. /**********************************************************************/
  198.  
  199. /*
  200.  * This function initializes the 3D (i.e. RenderWare) components of the
  201.  * application. This function opens the RenderWare library, creates a
  202.  * camera, a scene, a light and a matrix for spinning.
  203.  */
  204. static BOOL
  205. Init3D(HWND window)
  206. {
  207. #ifndef WIN32
  208.     RwOpenArgument args;
  209. #endif
  210.     int i;
  211.     RwRaster *Raster;
  212.     char buffer[64];
  213.  
  214.     if (!CheckDisplayDepth(window))
  215.         return(FALSE);
  216.  
  217. #ifndef WIN32
  218.     args.option = rwWINUSEWING;
  219.  
  220.     if (!RwOpenExt("MSWindows", NULL, 1, &args))
  221. #else
  222.     if (!RwOpen("MSWindows", NULL))
  223. #endif
  224.     {
  225.         MessageBox(window, "Error opening the RenderWare library",
  226.                    ERROR_DIALOG_TITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  227.         return FALSE;
  228.     }
  229.    GetModuleFileName(AppInstance, buffer, sizeof(buffer));
  230.    i = strlen(buffer);
  231.    while(buffer[i] != '\\')
  232.    i--;
  233.    buffer[i+1] = 0;
  234.    strcat(buffer, "TEXTURES");
  235.    RwSetShapePath(buffer, rwREPLACE); 
  236.  
  237.    buffer[i+1] = 0;
  238.    strcat(buffer, "SCRIPTS");
  239.    RwSetShapePath(buffer, rwPOSTCONCAT);
  240.    RwSetShapePath(".", rwPOSTCONCAT);
  241.  
  242.     /*
  243.      * Label the window with information about the version of
  244.      * RenderWare being used. Its rather unlikely that
  245.      * RwGetSystemInfo() or RwGetDeviceInfo() will fail so we ignore its
  246.      * return value.
  247.      */
  248.     SetWindowText(window, "RenderWare Animated Knight");
  249.  
  250.     MainCamera = RwCreateCamera(MAXIMUM_CAMERA_WIDTH, MAXIMUM_CAMERA_HEIGHT, NULL);
  251.     if (!MainCamera)
  252.     {
  253.         /*
  254.          * As with RwOpen(), the most common cause for a failure to create
  255.          * a camera is insufficient memory so we will explicitly check for
  256.          * this condition and report it. Otherwise a general error is issued.
  257.          */
  258.         if (RwGetError() == E_RW_NOMEM)
  259.         {
  260.             MessageBox(window,
  261.                        "Insufficient memory to create the RenderWare camera",
  262.                        ERROR_DIALOG_TITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  263.         }
  264.         else
  265.         {
  266.             MessageBox(window, "Error creating the Main RenderWare camera",
  267.                        ERROR_DIALOG_TITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  268.         }
  269.         RwClose();
  270.  
  271.         return FALSE;
  272.     }
  273.     FlyCamera = RwCreateCamera(MAXIMUM_CAMERA_WIDTH, MAXIMUM_CAMERA_HEIGHT, NULL);
  274.     if (!FlyCamera)
  275.     {
  276.             MessageBox(window, "Error creating the Flying RenderWare camera",
  277.                        ERROR_DIALOG_TITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  278.             RwDestroyCamera(MainCamera);        
  279.             RwClose();
  280.                 
  281.             return FALSE;
  282.     }
  283.     Camera = MainCamera;        
  284.  
  285.  
  286.     /* load the palette */
  287.  
  288.     CheckAndReadPalette("rwknight.pal");
  289.  
  290.     /* now add the backdrop */
  291.     Raster = RwReadRaster("cast256.bmp", 0L);
  292.     if (Raster)
  293.     {
  294.         /* Destroy the existing backdrop raster (if any). */
  295.         
  296.         if (RwGetCameraBackdrop(MainCamera))
  297.             RwDestroyRaster(RwGetCameraBackdrop(MainCamera));
  298.  
  299.         /* Set the new backdrop raster. */
  300.         
  301.         RwSetCameraBackdrop(MainCamera, Raster);
  302.         RwSetCameraBackdrop(FlyCamera, Raster);
  303.     }
  304.  
  305.     /*
  306.      * By default, the camera lies on the X-Z plane and points down Z
  307.      * into the screen. We shall retain the camera's orientation, but move
  308.      * the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
  309.      */
  310.  
  311.     RwVCMoveCamera(MainCamera, CREAL(0.0), CREAL(0.0), CAMERA_DISTANCE);
  312.     RwSetCameraViewwindow(MainCamera, CREAL(0.4), CREAL(0.4));
  313.     RwSetCameraViewwindow(FlyCamera, CREAL(0.4), CREAL(0.4));
  314.  
  315.     /*
  316.      * Create a scene which will contain the clumps to be rendered and the
  317.      * light or lights illuminating those clumps . In this very simple
  318.      * application it would be perfectly acceptable to use the default scene
  319.      * (as returned by RwDefaultScene()) for rendering. However, it is good
  320.      * practice to always create a scene which will be used for your rendering
  321.      * and only use the default scene as a bag for currently unused clumps and
  322.      * lights.
  323.      */
  324.     Scene = RwCreateScene();
  325.     if (!Scene)
  326.     {
  327.         RwDestroyCamera(FlyCamera);
  328.         RwDestroyCamera(MainCamera);
  329.         RwClose();
  330.         MessageBox(window, "Error creating the RenderWare scene",
  331.                    ERROR_DIALOG_TITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  332.         return FALSE;
  333.     }
  334.  
  335.     /*
  336.      * Our scene will be illuminated by a directional light. The illumination
  337.      * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
  338.      */ 
  339.     Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
  340.                           CREAL(1.0));
  341.     if (!Light)
  342.     {
  343.         RwDestroyScene(Scene);
  344.         RwDestroyCamera(FlyCamera);
  345.         RwDestroyCamera(MainCamera);
  346.         RwClose();
  347.         MessageBox(window, "Error creating the RenderWare light",
  348.                    ERROR_DIALOG_TITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
  349.         return FALSE;
  350.     }
  351.  
  352.     /*
  353.      * Add the new light to our scene.
  354.      */
  355.     RwAddLightToScene(Scene, Light);
  356.  
  357.     /*
  358.      * All the 3D components are now successfully initialized, so 
  359.      * work can begin...
  360.      */
  361.     ThreeDInitialized = TRUE;
  362.  
  363.     SetCameraState(window, CAM_MAIN);
  364.     return TRUE;
  365. }
  366.  
  367. /**********************************************************************/
  368.  
  369. /*
  370.  * This function shuts down the 3D (i.e. RenderWare) components of the
  371.  * application in a polite fashion.
  372.  */
  373. static void
  374. TidyUp3D(void)
  375. {
  376.    
  377.     /*
  378.      * Destroy the scene. This will destroy the contents of the scene,
  379.      * i.e. any clumps and lights in that scene. In this case destroying
  380.      * the scene will destroy the light we created in Init3D, and any
  381.      * clumps we have loaded and not already destroyed.
  382.      */
  383.     RwDestroyScene(Scene);
  384.  
  385.     /*
  386.      * Destroy the camera's backdrop (if any). Backdrops are not
  387.      * automatically destroyed by RwDestroyCamera() so we must
  388.      * manually destroy the backdrop.
  389.      */
  390.     if (RwGetCameraBackdrop(MainCamera))
  391.     {
  392.         RwDestroyRaster(RwGetCameraBackdrop(MainCamera));
  393.         RwSetCameraBackdrop(MainCamera, NULL);
  394.         RwSetCameraBackdrop(FlyCamera, NULL);
  395.     }
  396.  
  397.     /*
  398.      * Destroy the camera.
  399.      */
  400.      RwDestroyCamera(FlyCamera);
  401.      RwDestroyCamera(MainCamera);
  402.  
  403.     /*
  404.      * Close the library. This will free up any internal resources and
  405.      * textures loaded.
  406.      */
  407.     RwClose();
  408. }
  409.  
  410. /**********************************************************************/
  411.  
  412. /*
  413.  * Render the scene and copy it to the window and device context
  414.  * given. This function encapsulates the very common RenderWare
  415.  * for rendering and updating the display.
  416.  */
  417. static void
  418. RenderScene(HWND window)
  419. {
  420.     HDC dc;
  421.     
  422.     RwBeginCameraUpdate(Camera, (void *)window);
  423.         RwClearCameraViewport(Camera);
  424.         RwRenderScene(Scene);
  425.         RenderKnight();
  426.     RwEndCameraUpdate(Camera);
  427.  
  428.     dc = GetDC(window);
  429.     RwShowCameraImage(Camera, (void*)dc);
  430.     ReleaseDC(window, dc);
  431.  
  432. }
  433.  
  434. RwClump *
  435. LoadClump(HWND window, char *fileName)
  436. {
  437.     RwClump  *clump;
  438.     char      buffer[128];
  439.  
  440.     clump = RwReadShape(fileName);
  441.     if (!clump)
  442.     {
  443.         /*
  444.          * The load failed. This could be because of errors in the
  445.          * script file, insufficient memory, or the file containing
  446.          * garbage. We will now examine the error code returned to
  447.          * decide whether there was a script file error (in which case
  448.          * an error will be issued to the user), whether memory was
  449.          * exhausted (a different error is issued to the user), or
  450.          * the file contained garbage (in which case we will attempt
  451.          * to load the file as a texture instead of a script).
  452.          */
  453.         switch (RwGetError())
  454.         {
  455.             case E_RW_NOMEM:
  456.                 /*
  457.                  * Ran out of memory...
  458.                  */
  459.                 sprintf(buffer, "Insufficient memory to load script %s",
  460.                         fileName);
  461.                 MessageBox(window, buffer, ERROR_DIALOG_TITLE,
  462.                            MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
  463.                 return NULL;
  464.  
  465.             default:
  466.                 /*
  467.                  * On any other error we will assume there is an error in
  468.                  * the script file.
  469.                  */
  470.                 sprintf(buffer,
  471.                         "Error reading the script file %s",
  472.                         fileName);
  473.                 MessageBox(window, buffer, ERROR_DIALOG_TITLE,
  474.                            MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
  475.                 return NULL;
  476.         }
  477.     }
  478.     return clump;
  479. }   
  480.  
  481. /**********************************************************************/
  482. static void
  483. HandleSize(HWND window, RwInt32 width, RwInt32 height)
  484. {
  485.     RwWinOutputSize winOutputSize;
  486.  
  487.     if (Stretching)
  488.     {
  489.         /* force stretching to use an exact multiple by dividing and remultiplying */
  490.     
  491.         width = (width/2) * 2;
  492.         height = (height/2) * 2;
  493.     }                         
  494.     winOutputSize.width  = width;
  495.     winOutputSize.height = height;
  496.     winOutputSize.camera = MainCamera;
  497.  
  498.     RwDeviceControl(rwWINSETOUTPUTSIZE,(RwInt32)0, &winOutputSize, sizeof(winOutputSize));
  499.         winOutputSize.camera = FlyCamera;
  500.     RwDeviceControl(rwWINSETOUTPUTSIZE,(RwInt32)0, &winOutputSize, sizeof(winOutputSize));
  501.  
  502.     if (Stretching)
  503.     {
  504.         width/= 2;
  505.         height/= 2;
  506.     }
  507.  
  508.     /* Set the camera viewport to match the window's client area.*/
  509.  
  510.     RwSetCameraViewport(MainCamera, 0, 0, width, height );
  511.     RwSetCameraViewport(FlyCamera, 0, 0, width, height );
  512.     RwGetCameraViewport(MainCamera, NULL, NULL, &width, &height );
  513.  
  514.     /* Maintain the view window at a 1:1 aspect ratio. */
  515.  
  516.     if ( width != 0 && height != 0 )
  517.     {
  518.         if (width >= height)
  519.         {
  520.             RwSetCameraViewwindow(MainCamera, CREAL(0.4), RMul(CREAL(0.4), RDiv(INT2REAL(height), INT2REAL(width))));
  521.             RwSetCameraViewwindow(FlyCamera, CREAL(0.4), RMul(CREAL(0.4), RDiv(INT2REAL(height), INT2REAL(width))));
  522.         }
  523.         else
  524.         {
  525.             RwSetCameraViewwindow(MainCamera, RMul(CREAL(0.4), RDiv(INT2REAL(width), INT2REAL(height))), CREAL(0.4));
  526.             RwSetCameraViewwindow(FlyCamera, RMul(CREAL(0.4), RDiv(INT2REAL(width), INT2REAL(height))), CREAL(0.4));
  527.         }
  528.     }
  529.  
  530.     RwSetCameraViewport(MainCamera, 0, 0, width, height);
  531.     RwSetCameraViewport(FlyCamera, 0, 0, width, height);
  532.     RwSetCameraBackdropViewportRect(MainCamera, 0, 0, width, height);
  533.     RwSetCameraBackdropViewportRect(FlyCamera, 0, 0, width, height);
  534.  
  535.     SetBackdrop(MainCamera); /* The camera has changed so reposition the backdrop */
  536.     SetBackdrop(FlyCamera);
  537.  
  538.     RenderScene(window);
  539. }
  540.             
  541. /**********************************************************************/
  542.  
  543. static void
  544. HandleLeftButtonDown(HWND window, int x, int y)
  545. {
  546.     POINT        pos;
  547.  
  548.     if (MouseMoveMode != MMNoAction)
  549.     {
  550.         SetCapture(window);
  551.         pos.x = x;
  552.         pos.y = y;
  553.         ClientToScreen(window, &pos);
  554.         LastX = pos.x;
  555.         LastY = pos.y;
  556.     }
  557. }
  558.  
  559. /**********************************************************************/
  560.  
  561. static void
  562. HandleRightButtonDown(HWND window, int x, int y, WPARAM vKeys)
  563. {
  564.     POINT pos;
  565.  
  566.     if (vKeys & MK_CONTROL)
  567.     {
  568.         MouseMoveMode = MMPanLight;
  569.     }
  570.     else
  571.     {
  572.         MouseMoveMode = MMPanCamera;
  573.     }
  574.     
  575.     if (MouseMoveMode != MMNoAction)
  576.     {
  577.         SetCapture(window);
  578.         pos.x = x;
  579.         pos.y = y;
  580.         ClientToScreen(window, &pos);
  581.         LastX = pos.x;
  582.         LastY = pos.y;
  583.     }
  584. }
  585.  
  586. /**********************************************************************/
  587.  
  588. static void
  589. HandleMouseMove(HWND window, int x, int y)
  590. {
  591.     POINT       pos;
  592.  
  593.     pos.x = x;
  594.     pos.y = y;
  595.     ClientToScreen(window, &pos);
  596.     
  597.     /*
  598.      * MouseMoveMode tells us what kind of action to perform.
  599.      */
  600.     switch (MouseMoveMode)
  601.     {
  602.         case MMNoAction:
  603.             break;
  604.  
  605.         case MMPanCamera:
  606.             RwVCMoveCamera(MainCamera, CREAL(0.0), CREAL(0.0), -CAMERA_DISTANCE);
  607.             RwPanCamera(MainCamera, INT2REAL(LastX - pos.x));
  608.             RwVCMoveCamera(MainCamera, CREAL(0.0), CREAL(0.0), CAMERA_DISTANCE);
  609.             if (CameraState == CAM_MAIN)
  610.                 SetBackdrop(MainCamera);
  611.             break;
  612.  
  613.         case MMPanLight:
  614.  
  615.             RwPushScratchMatrix();
  616.             RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
  617.                                INT2REAL(LastX - pos.x), rwREPLACE);
  618.                                
  619.             RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
  620.                                INT2REAL(LastY - pos.y), rwPOSTCONCAT);
  621.  
  622.             RwTransformLight(Light, RwScratchMatrix(), rwPOSTCONCAT);
  623.             RwPopScratchMatrix();
  624.             break;
  625.     }
  626.  
  627.     if (MouseMoveMode != MMNoAction)
  628.     {
  629.         LastX = pos.x;        
  630.         LastY = pos.y;
  631.     }
  632.     
  633. }
  634.  
  635. /**********************************************************************/
  636.  
  637. static void
  638. HandleLeftButtonUp(void)
  639. {
  640.     if (MouseMoveMode != MMNoAction)
  641.     {
  642.         MouseMoveMode = MMNoAction;
  643.         ReleaseCapture();
  644.     }
  645. }
  646.  
  647. /**********************************************************************/
  648.  
  649. static void
  650. HandleRightButtonUp(void)
  651. {
  652.     if (MouseMoveMode != MMNoAction)
  653.     {
  654.         MouseMoveMode = MMNoAction;
  655.         ReleaseCapture();
  656.     }
  657. }
  658.  
  659. /**********************************************************************/
  660.  
  661. static void
  662. HandlePaint(HWND window)
  663. {
  664.     HDC          dc;
  665.     PAINTSTRUCT  ps;
  666.  
  667.     dc = BeginPaint(window, &ps);
  668.     if (Stretching)
  669.     {
  670.         ps.rcPaint.left/=2;
  671.         ps.rcPaint.top/=2;
  672.         ps.rcPaint.right/=2;
  673.         ps.rcPaint.bottom/=2;
  674.     }
  675.  
  676.     RwDamageCameraViewport(Camera, 
  677.                            (RwInt32)ps.rcPaint.left, 
  678.                            (RwInt32)ps.rcPaint.top, 
  679.                            (RwInt32)(ps.rcPaint.right - ps.rcPaint.left),
  680.                            (RwInt32)(ps.rcPaint.bottom - ps.rcPaint.top));
  681.  
  682.  
  683.     RwShowCameraImage(Camera, (void *)dc);
  684.     EndPaint(window, &ps);
  685. }
  686.  
  687. /**********************************************************************/
  688.  
  689. static void
  690. HandleTimer(HWND window)
  691. {
  692.     AnimateScene();
  693.     AnimateCamera(window);
  694.     /*
  695.      * Re-render the scene and copy the results to the display.
  696.      */
  697.     RenderScene(window);
  698. }
  699.  
  700. /**************************************************************************/
  701. void 
  702. HandleGetMinMaxInfo(MINMAXINFO FAR *minmaxinfo)
  703. {
  704.     minmaxinfo->ptMaxSize.x = MaxWindowWidth;
  705.     minmaxinfo->ptMaxSize.y = MaxWindowHeight;
  706.     minmaxinfo->ptMaxTrackSize.x = MaxWindowWidth;
  707.     minmaxinfo->ptMaxTrackSize.y = MaxWindowHeight;
  708. }
  709.  
  710. /**************************************************************************
  711.     About Dialogue Box Stuff
  712. **************************************************************************/
  713. void
  714. DlgDrawItem(DRAWITEMSTRUCT FAR *dis)
  715. {
  716.      HDC hdcMemory;
  717.      HBITMAP hbmplogo, hbmpOld;
  718.      BITMAP bm;
  719.  
  720.      hbmplogo = LoadBitmap(AppInstance, "CRITERION_LOGO");
  721.      GetObject(hbmplogo, sizeof(BITMAP), &bm);
  722.  
  723.      hdcMemory = CreateCompatibleDC(dis->hDC);
  724.      hbmpOld = SelectObject(hdcMemory, hbmplogo);
  725.  
  726.      BitBlt(dis->hDC, dis->rcItem.left, dis->rcItem.top,
  727.                     dis->rcItem.right - dis->rcItem.left,
  728.                     dis->rcItem.bottom - dis->rcItem.top,
  729.                     hdcMemory, 0, 0, SRCCOPY);
  730.  
  731.      SelectObject(hdcMemory, hbmpOld);
  732.      DeleteDC(hdcMemory);
  733.      DeleteObject(hbmplogo);
  734. }
  735. /**********************************************************************/
  736. BOOL CALLBACK
  737. AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  738. {
  739.      switch(message)
  740.      {
  741.      case WM_INITDIALOG:
  742.           return TRUE;
  743.  
  744.      case WM_COMMAND:
  745.         switch(wParam)
  746.         {
  747.         case IDOK:
  748.         case IDCANCEL:
  749.             EndDialog(hDlg, 0);
  750.             return(TRUE);
  751.         }
  752.         break;
  753.  
  754.     case WM_DRAWITEM:
  755. #ifdef    __WINDOWS_386__
  756.         DlgDrawItem((DRAWITEMSTRUCT FAR *)MK_FP32((void *)lParam));
  757. #else  /* __WINDOWS_386__ */
  758.         DlgDrawItem((DRAWITEMSTRUCT FAR *)lParam);
  759. #endif /* __WINDOWS_386__ */
  760.         return(TRUE);
  761.     }
  762.     return(FALSE);
  763. }
  764. /**********************************************************************/
  765. static void
  766. HandleMenu(HWND window, WPARAM menuItem)
  767. {    
  768.     RECT rect;
  769.  
  770.     switch (menuItem)
  771.     {
  772.         case ID_FILE_EXIT:
  773.             SendMessage(window, WM_CLOSE, 0, 0L);
  774.             break;
  775.         case ID_MODE_STRETCH:
  776.           CheckMenuItem(GetMenu(window), ID_MODE_STRETCH, (Stretching) ? (MF_BYCOMMAND|MF_UNCHECKED) : (MF_BYCOMMAND|MF_CHECKED));
  777.           Stretching = (Stretching) ? FALSE : TRUE;
  778.           SetMaxValues();
  779.           GetWindowRect(window, &rect);
  780.           if (Stretching)
  781.             MoveWindow(window, rect.left, rect.top, 
  782.                       (rect.right - rect.left) * 2, 
  783.                       (rect.bottom - rect.top) * 2, TRUE);
  784.           else
  785.             MoveWindow(window, rect.left, rect.top, 
  786.                       (rect.right - rect.left) / 2, 
  787.                       (rect.bottom - rect.top) / 2, TRUE);
  788.           break;
  789.         case ID_MODE_DEMO:
  790.           CheckMenuItem(GetMenu(window), ID_MODE_DEMO, (!InterActive) ? (MF_BYCOMMAND|MF_UNCHECKED) : (MF_BYCOMMAND|MF_CHECKED));
  791.           InterActive = (InterActive) ? FALSE : TRUE;
  792.          break;
  793.         case ID_MODE_KNIGHT1:
  794.           SetCameraState(window, CAM_FLY1);
  795.           break;
  796.         case ID_MODE_KNIGHT2:
  797.           SetCameraState(window, CAM_FLY2);
  798.           break;
  799.         case ID_MODE_OBSERVER:
  800.           if (CameraState == CAM_KNIGHT1)
  801.             SetCameraState(window, CAM_FLY1);
  802.           else if (CameraState == CAM_KNIGHT2)
  803.             SetCameraState(window, CAM_FLY2);
  804.           break;
  805.         case ID_HELP_ABOUT:
  806.           KillTimer(window, 1);
  807.           DialogBox(AppInstance, "ABOUT", window, MakeProcInstance(AboutDlgProc, AppInstance));
  808.           SetTimer( window, 1, 20, NULL );
  809.           break;
  810.     }
  811. }
  812.  
  813. LRESULT CALLBACK
  814. MainWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
  815. {
  816. #ifdef WIN32
  817.     POINTS point;
  818. #else
  819.     POINT point;
  820. #endif
  821.     switch (message)
  822.     {
  823.         case WM_COMMAND:
  824.             if (LOWORD(lParam) == 0)
  825.                HandleMenu(window, wParam);
  826.             return 0L;
  827.             
  828.         case WM_CREATE:
  829.             SetTimer(window, 1, 20, NULL);
  830.             return 0L;
  831.  
  832.         case WM_GETMINMAXINFO:
  833. #ifdef    __WINDOWS_386__
  834.             HandleGetMinMaxInfo((MINMAXINFO FAR *)MK_FP32((void *)lParam));
  835. #else  /* __WINDOWS_386__ */
  836.             HandleGetMinMaxInfo((MINMAXINFO FAR *)lParam);
  837. #endif /* __WINDOWS_386__ */
  838.             break;            
  839.         case WM_SIZE:
  840.             if (ThreeDInitialized)
  841.                 HandleSize(window, (RwInt32)LOWORD(lParam), (RwInt32)HIWORD(lParam));
  842.             return 0L;
  843.             
  844.         case WM_LBUTTONDOWN:
  845.             if (ThreeDInitialized)
  846.             {
  847. #ifdef WIN32
  848.                 point = MAKEPOINTS(lParam);
  849. #else
  850.                 point = MAKEPOINT(lParam);
  851. #endif
  852.                 HandleLeftButtonDown(window, point.x, point.y);
  853.             }
  854.             return 0L;
  855.  
  856.         case WM_RBUTTONDOWN:
  857.             if (ThreeDInitialized)
  858.             {
  859. #ifdef WIN32
  860.                 point = MAKEPOINTS(lParam);
  861. #else
  862.                 point = MAKEPOINT(lParam);
  863. #endif
  864.                 HandleRightButtonDown(window, point.x, point.y, wParam);
  865.             }
  866.             return 0L;
  867.  
  868.         case WM_MOUSEMOVE:
  869.             if (ThreeDInitialized)
  870.             {
  871.                 if (MouseMoveMode != MMNoAction)
  872.                 {
  873. #ifdef WIN32
  874.                     point = MAKEPOINTS(lParam);
  875. #else
  876.                     point = MAKEPOINT(lParam);
  877. #endif
  878.                     HandleMouseMove(window, point.x, point.y);
  879.                 }
  880.             }
  881.             return 0L;
  882.  
  883.         case WM_LBUTTONUP:
  884.             if (ThreeDInitialized)
  885.                 HandleLeftButtonUp();
  886.             return 0L;
  887.  
  888.         case WM_RBUTTONUP:
  889.             if (ThreeDInitialized)
  890.                 HandleRightButtonUp();
  891.             return 0L;
  892.  
  893.         case WM_PAINT:
  894.             if (ThreeDInitialized)
  895.                 HandlePaint(window);
  896.             return 0L;
  897.  
  898.         case WM_TIMER:
  899.             if (ThreeDInitialized)
  900.                 HandleTimer(window);
  901.             return 0L;
  902.  
  903.         case WM_DESTROY:                  
  904.             KillTimer(window, 1);
  905.             PostQuitMessage(0);
  906.             return 0L;
  907.     }
  908.     return DefWindowProc(window, message, wParam, lParam);
  909. }
  910.  
  911. /**********************************************************************/
  912.  
  913. int PASCAL
  914. WinMain(HANDLE instance, HANDLE prevInstance, LPSTR cmdLine, int cmdShow)
  915. {
  916.     MSG  message;                 
  917.     HWND window;
  918.  
  919.     if (prevInstance)
  920.     {
  921.         MessageBox((HWND)0, "The RenderWare Knight Demonstration is already running...",
  922.                    ERROR_DIALOG_TITLE, MB_OK | MB_APPLMODAL | MB_ICONSTOP);
  923.         return FALSE;
  924.     }
  925.     
  926.     AppInstance = instance;
  927.  
  928.     if (!InitApplication(instance))
  929.     { 
  930.         return FALSE;           
  931.     }
  932.  
  933.     if (!(window = InitInstance(instance)))
  934.     {
  935.         return FALSE;
  936.     }
  937.     SetMaxValues();
  938.     
  939.     if (!Init3D(window))
  940.     {
  941.         DestroyWindow(window);
  942.         return FALSE;
  943.     }
  944.     
  945.     if (AllowStretching(window))
  946.     {
  947.         EnableMenuItem(GetMenu(window), ID_MODE_STRETCH, MF_ENABLED);
  948.     }
  949.  
  950.     if (!LoadKnight(window, instance, Scene))
  951.     {
  952.         TidyUp3D();
  953.         DestroyWindow(window);
  954.         return FALSE;        
  955.     }
  956.     AnimateKnight(1, "BOB1"); /* start the animation */
  957.                 
  958.     ShowWindow(window, cmdShow); 
  959.     UpdateWindow(window);
  960.  
  961.     while (GetMessage(&message, NULL, 0, 0))
  962.     {
  963.         TranslateMessage(&message);
  964.         DispatchMessage(&message);
  965.     }
  966.     TidyUp3D();
  967.  
  968.     UnregisterClass(RWKNIGHT_CLASS_NAME, instance);
  969.  
  970.     return message.wParam;
  971. }
  972.  
  973.