home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwwin
/
rfview.c_
/
rfview.bin
Wrap
Text File
|
1995-11-14
|
145KB
|
3,775 lines
/**********************************************************************
*
* File : rfView.c
*
* Abstract : Object viewer rfView.c mostly taken from rwView
*
* This application had been written to be compatible with
* both the fixed and floating-point versions of the
* RenderWare library, i.e., it uses the macros CREAL,
* INT2REAL, RAdd, RDiv, RSub etc. If your application is
* intended for the floating-point version of the library
* only these macros are not necessary.
*
* Please note that this application is intended for
* demonstration purposes only. No support will be
* provided for this code and it comes with no warranty.
*
**********************************************************************
*
* This file is a product of Criterion Software Ltd.
*
* This file is provided as is with no warranties of any kind and is
* provided without any obligation on Criterion Software Ltd. or
* Canon Inc. to assist in its use or modification.
*
* Criterion Software Ltd. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1994, 1995 Criterion Software Ltd.
* All Rights Reserved.
*
* RenderWare is a trademark of Canon Inc.
*
**********************************************************************/
#if defined(__WINDOWS_386__)
/*
* Watcom strangeness...
*/
#define INCLUDE_SHELLAPI_H
#define INCLUDE_COMMDLG_H
#include <windows.h>
#else
#include <windows.h>
#include <shellapi.h>
#include <commdlg.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <rwlib.h>
#include <rwwin.h>
#include "resource.h"
#include "common.h"
#include "pal.h"
#include "settings.h"
#include "object.h"
#include "popmenu.h"
#include "lightprp.h"
#include "clumpprp.h"
#include "color.h"
#include "pick.h"
#define MAIN
#include "rfview.h"
#include "viewdlg.h"
#include "booksub.h"
#include "viewsub.h"
#include "spline.h"
LRESULT CALLBACK
MainWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
/**********************************************************************/
/*
* Perform any necessary Windows application initialization. Basically,
* this means registering the window class for this application.
*/
static BOOL
InitApplication(HANDLE instance)
{
WNDCLASS wndClass;
wndClass.style = CS_BYTEALIGNWINDOW;
wndClass.lpfnWndProc = (WNDPROC)MainWndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = instance;
wndClass.hIcon = NULL;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = NULL;
wndClass.lpszMenuName = MAKEINTRESOURCE(IDR_RWVIEW_MENU);
wndClass.lpszClassName = RWVIEWCLASSNAME;
if (RegisterClass(&wndClass) != (ATOM)0)
return TRUE;
else
return FALSE;
}
/**********************************************************************/
/*
* Perform any necessary initialization for this instance of the
* application. This simply means creating the application's main
* window.
*/
static HWND
InitInstance(HANDLE instance)
{
/*
* Create the MS Window's window instance for this application. The
* initial window size is given by DEFAULT_WINDOW_WIDTH and
* DEFAULT_WINDOW_HEIGHT.
*/
return CreateWindow(RWVIEWCLASSNAME,
WINDOWTITLE,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
DEFAULTWINDOWWIDTH, DEFAULTWINDOWHEIGHT,
NULL, NULL, instance, NULL);
}
/**********************************************************************/
/*
* Ensure that the depth of the output display is acceptable.
* RenderWare will operate correctly at all display depths
* but it works best when running on an 8-bit or 16-bit
* display. If the display depth is not 8-bit or 16-bit we
* will display a message explaining the situation and
* ask the user if she or he wishes to continue.
*/
static BOOL
IsGoodDisplayDepth(HWND window)
{
HDC dc;
int depth;
char colString[10];
char buffer[400];
dc = GetDC(window);
depth = GetDeviceCaps(dc, BITSPIXEL);
ReleaseDC(window, dc);
if ((depth != 8) && (depth != 16))
{
if (depth < 8)
wsprintf(colString, "%d", 1 << depth);
else
strcpy(colString, "true");
wsprintf(buffer,
"Your video adapter is currently running in %s color mode.\n"
"Although the Viewer will operate correctly in this mode,\n"
"we recommend that you change the mode of your video adapter\n"
"to 256 color mode or 65536 color mode.\n"
"Do you wish to continue?",
colString);
if (MessageBox(window, buffer, WINDOWTITLE,
MB_YESNO | MB_APPLMODAL | MB_ICONEXCLAMATION) == IDYES)
return TRUE;
else
return FALSE;
}
else
{
return TRUE;
}
}
/**********************************************************************/
/*
* Reset the camera to its default position and orientation. We could
* use RwResetCamera() instead but we wish to leave the other camera
* settings such as viewwindow alone.
*/
static void
ResetCamera(RwCamera *camera)
{
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),
CREAL(-1.0), CREAL(1.0), CREAL(1.0),
rwREPLACE);
RwTranslateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(0.0),
DEFAULTCAMERADISTANCE, rwPOSTCONCAT);
RwTransformCamera(camera, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
}
/**********************************************************************/
/*
* Size the highlight box to fit the given clump.
*/
static RwClump *
SizeHighlightToFitClump(RwClump *clump)
{
RwV3d bll;
RwV3d fur;
RwReal w;
RwReal h;
RwReal d;
RwReal x;
RwReal y;
RwReal z;
RwGetClumpLocalBBox(clump, &bll, &fur);
/*
* Scale the highlight clump to fit.
*/
w = RSub(fur.x, bll.x);
h = RSub(fur.y, bll.y);
d = RSub(fur.z, bll.z);
x = RAdd(bll.x, RDiv(w, CREAL(2.0)));
y = RAdd(bll.y, RDiv(h, CREAL(2.0)));
z = RAdd(bll.z, RDiv(d, CREAL(2.0)));
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(), w, h, d, rwREPLACE);
RwTranslateMatrix(RwScratchMatrix(), x, y, z, rwPOSTCONCAT);
RwTransformClumpJoint(HighlightClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
return clump;
}
/**********************************************************************/
static void
SelectClump(HWND window, RwClump *clump)
{
/*
* Remember the currently picked object.
*/
SelectedClump = clump;
/*
* Don't spin it until the user has rotated the object.
*/
SpinClump = FALSE;
/*
* Size the highlight to fit.
*/
SizeHighlightToFitClump(clump);
/*
* Update the menus to reflect the picked clump.
*/
EnableMenuItem(GetMenu(window), IDM_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_EDIT_DUPLICATE, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_CAMERA_LOOKAT, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_CAMERA_MOVETO, MF_BYCOMMAND | MF_ENABLED);
switch(GETOBJECTTYPE(clump))
{
case rfIsLight:
EnableMenuItem(GetMenu(window), IDM_LIGHT_PROPERTIES, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_CLUMP_RESET, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(GetMenu(window), IDM_CLUMP_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(GetMenu(window), IDM_FILE_SAVE, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(GetMenu(window), IDM_FILE_SAVEAS, MF_BYCOMMAND | MF_GRAYED);
break;
case rfIsClump: case rfNoMoveClump:
EnableMenuItem(GetMenu(window), IDM_LIGHT_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(GetMenu(window), IDM_CLUMP_RESET, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_CLUMP_PROPERTIES, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_FILE_SAVE, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_FILE_SAVEAS, MF_BYCOMMAND | MF_ENABLED);
break;
case rfIsSprite:
EnableMenuItem(GetMenu(window), IDM_LIGHT_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(GetMenu(window), IDM_CLUMP_RESET, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_CLUMP_PROPERTIES, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_FILE_SAVE, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(GetMenu(window), IDM_FILE_SAVEAS, MF_BYCOMMAND | MF_ENABLED);
break;
}
}
/**********************************************************************/
/*
* This function initializes the 3D (i.e. RenderWare) components of the
* application. This function opens the RenderWare library, creates a
* camera, a scene, a light and a matrix for spinning.
*/
static BOOL
Init3D(HWND window)
{
char shapePath[RWMAXPATHLEN];
char *s;
RwRaster *backdrop;
RwRGBColor color;
/*
* Check the display depth and if it is not one of the optimal depths
* for RenderWare (8-bit or 16-bit). If it is not then warn the user
* and check whether they wish to continue or not.
*/
if (!IsGoodDisplayDepth(window)) return FALSE; // CHANGE DISPLAY DEPTH
/*
* Attempt to open (and initialize) the RenderWare library.
* Explicitly specifying the Windows driver.
*/
if (!RwOpen("MSWindows", NULL))
{
MessageBox(window,
"Could not open the RenderWare library",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
return FALSE;
}
/*
arg.option = rwWINUSEDIBS;
arg.value = 0L; // ignored for rwWINUSEDUBS
if (!RwOpenExt("MSWindows", NULL,1,&arg))
{
MessageBox(window,
"Could not open the RenderWare library",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
return FALSE;
}
*/
/*
* Create the camera which will be used for rendering. The initial window
* size the application will create is given by DEFAULT_WINDOW_WIDTH and
* DEFAULT_WINDOW_HEIGHT. However, when we create a camera we have to
* specify the largest size that camera's viewport can ever be. As the
* camera's viewport is the same size as the window's client area we
* have to specify the size as the maximum size of the window.
*
* If we compile with CONSTRAIN_SIZE then we restrict the window size
* (using WM_GETMINMAXINFO) to MAXIMUMWINDOWWIDTH by MAXIMUMWINDOWHEIGHT.
* If CONTRAIN_SIZE is not specified we let the window grow to the full
* size of the screen.
*/
#if defined(CONSTRAIN_SIZE)
Camera = RwCreateCamera(MAXIMUMWINDOWWIDTH, MAXIMUMWINDOWHEIGHT, NULL);
#else
Camera = RwCreateCamera((RwInt32)GetSystemMetrics(SM_CXFULLSCREEN),
(RwInt32)GetSystemMetrics(SM_CYFULLSCREEN), NULL);
#endif
if (Camera == NULL)
{
/*
* As with RwOpen(), the most common cause for a failure to create
* a camera is insufficient memory so we will explicitly check for
* this condition and report it. Otherwise a general error is issued.
*/
if (RwGetError() == E_RW_NOMEM)
{
MessageBox(window,
"Insufficient memory to create the 3D camera",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
}
else
{
MessageBox(window, "Could not create the 3D camera",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
}
RwClose();
return FALSE;
}
/*
* Set the camera's background color to the color saved in the
* initialization file. The initialization file stores the
* colors as a Windows format COLORREF so we need to convert
* it to a RenderWare RwRGBColor.
*/
ColorRefToRGB(BackgroundColor, &color);
RwSetCameraBackColorStruct(Camera, &color);
/*
* Move the camera to its default position.
*/
ResetCamera(Camera);
/*
* If we have read a non-empty backdrop filename from the
* settings file attempt to load that backdrop raster. If
* we don't succeed we don't consider it a fatal error -
* we simply continue.
*/
if (BackdropFileName[0] != '\0')
{
backdrop = RwReadRaster(BackdropFileName,
rwGAMMARASTER | rwDITHERRASTER);
if (backdrop != NULL)
RwSetCameraBackdrop(Camera, backdrop);
}
BirdsEyeCamera = RwCreateCamera(128, 128, NULL);
if (BirdsEyeCamera == NULL)
{
/*
* As with RwOpen(), the most common cause for a failure to create
* a camera is insufficient memory so we will explicitly check for
* this condition and report it. Otherwise a general error is issued.
*/
if (RwGetError() == E_RW_NOMEM)
{
MessageBox(window,
"Insufficient memory to create the bird's eye camera",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
}
else
{
MessageBox(window, "Could not create the bird's eye camera",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
}
RwDestroyCamera(Camera);
RwClose();
return FALSE;
}
/*
* Initialize the bird's eye camera for a nice viewpoint and fixed
* 128 x 128 viewport (the size of a texture).
*/
RwSetCameraPosition(BirdsEyeCamera, CREAL(0.0), CREAL(3.0), CREAL(0.0));
RwPointCamera(BirdsEyeCamera, CREAL(0.0), CREAL(0.0), CREAL(0.0) );
RwSetCameraBackColor(BirdsEyeCamera, CREAL(0.0), CREAL(0.0), CREAL(1.0));
RwSetCameraViewport(BirdsEyeCamera, 0, 0, 128, 128);
/*
* Create the initial scene for the viewer. The initial
* scene consists of a default light and a new texture
* dictionary to store the textures loaded by clumps
* added to the scene.
*/
Scene = CreateViewerScene();
if (Scene == NULL)
{
RwDestroyCamera(Camera);
Camera = NULL;
RwClose();
MessageBox(window, "Could not create the 3D Scene",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
return FALSE;
}
/*
* Create the spin matrix.
*/
SpinMatrix = RwCreateMatrix();
if (SpinMatrix == NULL)
{
DestroyViewerScene(Scene);
Scene = NULL;
RwDestroyCamera(Camera);
Camera = NULL;
RwClose();
MessageBox(window,
"Could not create the RenderWare matrix",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
return FALSE;
}
/*
* Create the highlight clump. The highlight clump is a yellow, wireframe
* box which surrounds the picked clump.
*/
RwModelBegin();
RwClumpBegin();
RwSetSurface(CREAL(0.75), CREAL(0.0), CREAL(0.0));
RwSetSurfaceColor(CREAL(1.0), CREAL(1.0), CREAL(0.0));
RwSetSurfaceGeometrySampling(rwWIREFRAME);
RwBlock(CREAL(1.0), CREAL(1.0), CREAL(1.0));
RwClumpEnd(&HighlightClump);
RwModelEnd();
if (HighlightClump == NULL)
{
DestroyViewerScene(Scene);
Scene = NULL;
RwDestroyCamera(Camera);
Camera = NULL;
RwClose();
MessageBox(window, "Could not create the highlight object",
WINDOWTITLE, MB_OK | MB_ICONSTOP | MB_APPLMODAL);
return FALSE;
}
/*
* Initialize the last opened filename with the first directory
* in the RenderWare search path (if any). This gives us a good
* chance of opening into a directory with interesting scripts
* in it.
*/
RwGetShapePath(shapePath);
if (shapePath[0] == '\0')
{
/*
* The shape path is empty so initialize the last filename
* opened to empty.
*/
LastFileName[0] = '\0';
}
else
{
s = strchr(shapePath, ';');
if (s != NULL)
{
/*
* We have located the end of the first directory.
* So truncate the shape path to this point.
*/
*s = '\0';
}
/*
* Copy the directory to the last filename. Append a backquote
* so we know this is a directory and not a full filename.
*/
strcpy(LastFileName, shapePath);
strcat(LastFileName, "\\");
}
/*
* All the 3D components are now successfully initialized, so
* work can begin...
*/
RwIsOpen = TRUE;
return TRUE;
}
/**********************************************************************/
/*
* This function shuts down the 3D (i.e. RenderWare) components of the
* application in a polite fashion.
*/
static void
TidyUp3D(void)
{
/*
* Destroy the highlight clump.
*/
if (HighlightClump != NULL)
RwDestroyClump(HighlightClump);
/*
* Destroy the spin matrix.
*/
if (SpinMatrix != NULL)
RwDestroyMatrix(SpinMatrix);
/*
* Destroy the scene. This will destroy the scene itself, the contents of
* the scene, i.e. any clumps and lights in that scene and any textures
* loaded by the clumps in the scene.
*/
if (Scene != NULL)
DestroyViewerScene(Scene);
if (Camera != NULL)
{
/*
* Destroy the camera's backdrop (if any). Backdrops are not
* automatically destroyed by RwDestroyCamera() so we must
* manually destroy the backdrop.
*/
if (RwGetCameraBackdrop(Camera))
RwDestroyRaster(RwGetCameraBackdrop(Camera));
/*
* Destroy the camera.
*/
RwDestroyCamera(Camera);
}
/*
* Close the library. This will free up any internal resources and
* textures loaded.
*/
RwClose();
}
/**********************************************************************/
/*
* Attempt to load an object from the given file. The actual object type
* to load is determined from the file extension. This function will
* read RenderWare clumps (.rwx), Backdrops (.bmp), Palettes (.pal) and Splines (.rrc)
*/
static BOOL
LoadObject(HWND window, char *pathName)
{
HCURSOR oldCursor;
RwClump *clump;
RwRaster *backdrop;
char buffer[128];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fName[_MAX_FNAME];
char ext[_MAX_EXT];
RwInt32 numPalEntries;
RwPaletteEntry palEntries[256];
RwInt32 firstEntry;
RwInt32 lastEntry;
int len;
FILE *file;
/*
* We use the file extension to decide what kind of object we
* are reading so we decompose the filename into its components.
*/
_splitpath(pathName, drive, dir, fName, ext);
if (stricmp(ext, ".rwx") == 0)
{
/*
* Its a RenderWare script file so read the clump
* and add it to the viewer's scene.
*/
/*
* This may take some time so show the wait cursor.
*/
oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
clump = ReadClumpObj(pathName);
SetCursor(oldCursor);
if (clump != NULL)
{
AddClumpObjToScene(Scene, clump);
return TRUE;
}
else
{
/*
* The read failed. There are a large number of reasons why this
* could happen. We will issue specific messages for the most
* common errors and a generic catch all for the rest.
*/
switch (RwGetError())
{
case E_RW_NOFILE:
case E_RW_BADOPEN:
/*
* Could not open the file...
*/
sprintf(buffer, "The file %s could not be opened", pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
break;
case E_RW_NOMEM:
/*
* Ran out of memory...
*/
sprintf(buffer, "Insufficient memory to load object %s",
pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
break;
default:
/*
* Generic, catch all error message.
*/
sprintf(buffer, "The 3D object %s could not be read",
pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
break;
}
return FALSE;
}
}
else
if (stricmp(ext, ".bmp") == 0)
{
if(!rfReadSprite)
{
/*
* Its a Windows bitmap file so read the bitmap as a
* raster and make it the backdrop of the camera.
*/
/*
* This may take some time so show the wait cursor.
*/
oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
backdrop = RwReadRaster(pathName, rwGAMMARASTER | rwDITHERRASTER);
SetCursor(oldCursor);
if (backdrop != NULL)
{
if (RwGetCameraBackdrop(Camera) != NULL)
/*
* The camera has an existing backdrop so destroy it.
*/
RwDestroyRaster(RwGetCameraBackdrop(Camera));
RwSetCameraBackdrop(Camera, backdrop);
EnableMenuItem(GetMenu(window), IDM_SCENE_BACKDROPDELETE, MF_BYCOMMAND | MF_ENABLED);
/*
* Update the setting's backdrop filename and flag the fact
* that the settings have changed.
*/
strcpy(BackdropFileName, pathName);
SettingsChanged = TRUE;
UpdateCameraBackdropPosition(Camera);
return TRUE;
}
}
else // load (.bmp) onto a sprite
{
clump = CreateSpriteObj(pathName); // create the sprite
if (clump != NULL)
{
RwAddClumpToScene(Scene, clump);
return TRUE;
}
}
/*
* The read failed. There are a large number of reasons why this
* could happen. We will issue specific messages for the most
* common errors and a generic catch all for the rest.
*/
switch (RwGetError())
{
case E_RW_NOFILE:
case E_RW_BADOPEN:
/*
* Could not open the file...
*/
sprintf(buffer, "The file %s could not be opened", pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
break;
case E_RW_NOMEM:
/*
* Ran out of memory...
*/
sprintf(buffer, "Insufficient memory to load backdrop %s",
pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
break;
default:
/*
* Generic, catch all error message.
*/
sprintf(buffer, "The backdrop %s could not be read",
pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
break;
}
return FALSE;
}
else if (stricmp(ext, ".pal") == 0)
{
/*
* This may take some time so show the wait cursor.
*/
oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
numPalEntries = ReadPalette(pathName, palEntries);
SetCursor(oldCursor);
if (numPalEntries > 0)
{
/*
* We have successfully read a new palette. Textures are
* not rematched when we load a new palette so they will
* look strange if we simply set the new palette. To avoid
* this potential visual strangeness we discard all textures
* and geometry when we load a new palette. We obviously
* don't want to do this without user confirmation, so ask
* the user if she or he really wishes to change the palette.
*/
if (MessageBox(window,
"In order to load a new palette the viewer must\n"
"discard the contents of the 3D Scene.\n"
"Do you wish to continue?",
WINDOWTITLE,
MB_YESNO | MB_APPLMODAL | MB_ICONQUESTION) == IDYES)
{
/*
* Destroy the current scene.
*/
DestroyViewerScene(Scene);
/*
* It is also necessary to destory the camera's backdrop (as it
* will have been matched against the previous palette).
*/
if (RwGetCameraBackdrop(Camera) != NULL)
{
RwDestroyRaster(RwGetCameraBackdrop(Camera));
RwSetCameraBackdrop(Camera, NULL);
}
/*
* Create the new scene.
*/
Scene = CreateViewerScene();
if (Scene == NULL)
{
/*
* Failing to create the new scene is a fatal error.
* Display an error message and exit.
*/
MessageBox(window, "Could not create the new 3D Scene",
WINDOWTITLE, MB_OK | MB_APPLMODAL | MB_ICONSTOP);
SendMessage(window, WM_CLOSE, 0, 0L);
return FALSE;
}
/*
* As this is a new world there is no picked object yet.
*/
DeselectClump(window);
/*
* Set the new palette.
*/
RwGetDeviceInfo(rwFIRSTPALETTEENTRY, &firstEntry, sizeof(firstEntry));
RwGetDeviceInfo(rwLASTPALETTEENTRY, &lastEntry, sizeof(lastEntry));
if (numPalEntries > ((lastEntry - firstEntry)))
numPalEntries = ((lastEntry - firstEntry));
RwSetPaletteEntries(firstEntry, numPalEntries, palEntries, 0L);
return TRUE;
}
return FALSE;
}
else
{
/*
* Generic, catch all error message.
*/
sprintf(buffer, "The palette %s could not be read",
pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
return FALSE;
}
}
else if (stricmp(ext, ".rrc") == 0) // read a spline
{
file = fopen(pathName, "r");
if (file != NULL) {
/*
* The file should be a spline
*/
coaster = (RollerCoasterType *)malloc(sizeof(RollerCoasterType));
if(coaster!=NULL)
{
/* Read the description of the rollercoaster. */
fgets(coaster->description, sizeof(coaster->description), file);
len = strlen(coaster->description);
if ((len > 0) && (coaster->description[len - 1] == '\n'))
coaster->description[len - 1] = '\0';
coaster->spline = ReadCoasterSpline(file);
if (coaster->spline == NULL)
{
free(coaster);
fclose(file);
return FALSE;
}
/* Create the clumps representing the control points of the spline. */
if (!CreateCoasterControlPointClumps(coaster))
{
free(coaster);
fclose(file);
return FALSE;
}
/* Convert the spline description into a coaster clump. */
coaster->coasterClump = CreateCoasterClump(coaster);
if (coaster->coasterClump == NULL)
{
RwDestroySpline(coaster->spline);
free(coaster);
fclose(file);
return FALSE;
}
RwAddClumpToScene(Scene, coaster->coasterClump);
/* Initialize the spline parameter and spline parameter delta. */
coaster->t = CREAL(0.0);
coaster->tDelta = DEFAULTSPLINEDELTA;
/* Save the filename. */
strcpy(coaster->filename, pathName);
RenderScene(window);
}
}
fclose(file);
return TRUE;
}
else
{
/*
* The file type was unknown so flag an error and fail.
*/
wsprintf(buffer, "The format of %s is unknown", pathName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
return FALSE;
}
}
/**********************************************************************/
/*
* Parse the names of any .rwx files on the command line, read those
* files and add them to the scene. This allows RwView to be associated
* with .rwx files in the file manager and be started automatically when
* a .rwx file is double-clicked.
*/
static BOOL
ReadFromCommandLine(HWND window, char *cmdLine)
{
char *s1;
char *s2;
char fileName[_MAX_PATH];
s1 = &cmdLine[0];
s2 = &fileName[0];
while (*s1)
{
/*
* Extract one file name from the list.
*/
while (*s1 && (*s1 != ' '))
*s2++ = *s1++;
*s2 = '\0';
if (fileName[0])
{
/*
* Attempt to load an object. The actual object type is
* determined by LoadObject() from the extension of the file
* name.
*
* NOTE: We don't include these files in the MRU file list.
*/
if (!LoadObject(window, fileName))
return FALSE;
}
s2 = &fileName[0];
}
return TRUE;
}
/**********************************************************************/
#if defined(CONSTRAIN_SIZE)
/*
* Handle queries about the window's maximum extent. We only do this
* if we are constraining the size of the window.
*/
static void
OnGetMinMaxInfo(MINMAXINFO FAR *minMaxInfo)
{
/*
* Constraint the window to the maximum size defined by the constants
* MAXIMUM_WINDOW_WIDTH and MAXIMUM_WINDOW_HEIGHT.
*/
minMaxInfo->ptMaxSize.x = MAXIMUMWINDOWWIDTH;
minMaxInfo->ptMaxSize.y = MAXIMUMWINDOWHEIGHT;
minMaxInfo->ptMaxTrackSize.x = MAXIMUMWINDOWWIDTH;
minMaxInfo->ptMaxTrackSize.y = MAXIMUMWINDOWHEIGHT;
}
#endif
/**********************************************************************/
/*
* Handle measure item requests. Currently we user ownerdraw items for
* the titles of the popup menus. This function computes the size
* necessary for these items.
*/
static void
OnMeasureItem(HWND window, MEASUREITEMSTRUCT FAR *measureItem)
{
HDC dc;
SIZE size;
switch (measureItem->itemID)
{
case IDM_LIGHTPOPUP_LABEL:
dc = GetDC(window);
MeasurePopupMenuLabel(dc, "Light", &size);
ReleaseDC(window, dc);
measureItem->itemWidth = size.cx;
measureItem->itemHeight = size.cy;
break;
case IDM_CLUMPPOPUP_LABEL:
dc = GetDC(window);
MeasurePopupMenuLabel(dc, "Clump", &size);
ReleaseDC(window, dc);
measureItem->itemWidth = size.cx;
measureItem->itemHeight = size.cy;
break;
case IDM_BACKGROUNDPOPUP_LABEL:
dc = GetDC(window);
MeasurePopupMenuLabel(dc, "Background", &size);
ReleaseDC(window, dc);
measureItem->itemWidth = size.cx;
measureItem->itemHeight = size.cy;
break;
}
}
/**********************************************************************/
static void
OnDrawItem(HWND window, DRAWITEMSTRUCT FAR *drawItem)
{
HDC dc;
RECT rect;
window=window; // avoid warning
/*
* Cache interesting stuff for eash access.
*/
dc = drawItem->hDC;
rect = drawItem->rcItem;
switch (drawItem->itemID)
{
case IDM_LIGHTPOPUP_LABEL:
DrawPopupMenuLabel(dc, &rect, "Light");
break;
case IDM_CLUMPPOPUP_LABEL:
DrawPopupMenuLabel(dc, &rect, "Clump");
break;
case IDM_BACKGROUNDPOPUP_LABEL:
DrawPopupMenuLabel(dc, &rect, "Background");
break;
}
}
/**********************************************************************/
/*
* Handle window resize. The most important job here is to change the
* size of the camera's viewport (if preserving the aspect ratio of
* the viewport is necessary, then the viewwindow should also be
* changed at this point to reflect then new aspect ratio of the
* viewport).
*/
static void
OnSize(HWND window, int w, int h)
{
RwReal vw;
RwReal vh;
/*
* The window has been resized. Therefore, it is necessary to
* to modify the camera's viewport to be the same size as the
* client area of the window.
*/
RwSetCameraViewport(Camera, 0, 0, w, h);
/*
* Preserve the aspect ratio of the image by resizing the
* viewindow size in proportion to to viewport size. Be ensuring
* that the ratios of width to height of the viewport
* and viewwindow are the same the rendered image will not
* be distorted or stretched.
*/
if (w > h)
{
vw = DEFAULTVIEWWINDOWSIZE;
vh = RDiv(RMul(INT2REAL(h), DEFAULTVIEWWINDOWSIZE), INT2REAL(w));
}
else
{
vw = RDiv(RMul(INT2REAL(w), DEFAULTVIEWWINDOWSIZE), INT2REAL(h));
vh = DEFAULTVIEWWINDOWSIZE;
}
RwSetCameraViewwindow(Camera, vw, vh);
if (RwGetCameraBackdrop(Camera) != NULL)
UpdateCameraBackdropPosition(Camera);
/*
* When the viewport has changed size we need to re-render the
* scene for the new viewport size.
*/
RenderScene(window);
}
/**********************************************************************/
/*
* This functions handles the left mouse button going down. Its main
* job is to determine the kind of action to be taken when the mouse
* moves, such as spinning a clump, or panning the camera. This involves
* examining the virtual keys that were depressed when the mouse button
* went down and attempting to pick a clump under the mouse pointer
* position.
*/
static void
OnLButtonDown(HWND window, POINT *point, WPARAM vKeys)
{
RwPickRecord pick;
RwV3d p;
RwV3d o;
/*
* Turn the bird's eye sprite off to ensure we don't pick on it.
*/
RwSetClumpState(BirdsEyeSprite, rwOFF);
/*
* If the left button is depressed anywhere in the client area of the
* window then the animated spin is cancelled.
*/
SpinClump = FALSE;
/*
* The mouse move action is based on whether an object is picked or
* not. Therefore, attempt to pick an object in the scene.
*/
if (RwPickScene(Scene, point->x, point->y, Camera, &pick))
{
switch (pick.type)
{
case rwNAPICKOBJECT:
/*
* No clump was picked. The background was clicked on.
* The action taken depends on whether the camera has
* a backdrop or not. If the camera has a backdrop then
* if CONTROL and SHIFT were held down, the backdrop
* is destroyed, otherwise the backdrop will be scrolled
* on mouse move. If the camera has no backdrop then
* no action will be taken.
*/
DeselectClump(window);
RenderScene(window);
if (RwGetCameraBackdrop(Camera))
{
MouseMoveMode = mmScrollBackdrop;
}
else
{
MouseMoveMode = mmNoAction;
}
break;
case rwPICKCLUMP:
/*
* A clump was picked, so remember which clump was picked
* in order that it may be manipulated later when the
* mouse moves.
*/
SelectClump(window, pick.object.clump.clump);
RenderScene(window);
/*
* When we drag a clump we don't want the origin of the
* clump to jump to the mouse pointer position. We want
* to keep the drag offset by the distance of the initial
* pick from the origin of the clump. So we compute the
* initial pick position and store it away.
*/
GetClumpPositionUnderPointer(SelectedClump, Camera, point->x, point->y, &p);
RwGetClumpOrigin(SelectedClump, &o);
PickOffset.x = RSub(o.x, p.x);
PickOffset.y = RSub(o.y, p.y);
PickOffset.z = RSub(o.z, p.z);
/*
* Determine the exact nature of the manipulation of
* the clump on mouse move by examining the virtual key
* state. If the shift key was depressed, then drag
* the clump, otherwise, spin it.
*/
if (vKeys & MK_SHIFT)
MouseMoveMode = mmDragClump;
else if (vKeys & MK_CONTROL)
MouseMoveMode = mmDragClumpInZ;
else
MouseMoveMode = mmSpinClump;
break;
}
}
/*
* If any form of action is to be taken on mouse move, remember the
* the current x and y position of the mouse and capture future
* mouse movement.
*/
if (MouseMoveMode != mmNoAction)
{
SetCapture(window);
LastX = point->x;
LastY = point->y;
}
/*
* Turn the bird's eye sprite back on.
*/
RwSetClumpState(BirdsEyeSprite, rwON);
}
/**********************************************************************/
/*
* This functions handles the right mouse button going down. Its main
* job is to determine the kind of action to be taken when the mouse
* moves such as panning the camera.
*/
static void
OnRButtonDown(HWND window, POINT *point, WPARAM vKeys)
{
RwPickRecord pick;
RwClump *clump;
if (vKeys & MK_SHIFT)
{
MouseMoveMode = mmMoveAndTurnCamera;
}
else if (vKeys & MK_CONTROL)
{
MouseMoveMode = mmTiltCamera;
}
else
{
/*
* Right mouse button down brings up an appropriate menu
* for the object picked on (on just tracks the camera if
* no object is picked).
*/
if (RwPickScene(Scene, point->x, point->y, Camera, &pick))
{
if (pick.type == rwPICKCLUMP)
{
clump = pick.object.clump.clump;
/*
* The object we picked on becomes the currently
* selected clump and rerender the scene so the
* highlight clump is displayed.
*/
SelectClump(window, clump);
RenderScene(window);
/*
* We have picked on a clump. Does the clump picked
* represent a light or is it just a clump?
*/
if (ISCLUMPLIGHT(clump))
{
/*
* Its a light, so bring up the light pop-up
* menu.
*/
ClientToScreen(window, point);
TrackPopupMenu(LightMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
point->x, point->y, 0, window, NULL);
}
else
{
/*
* Its a clump, so bring up the clump pop-up
* menu.
*/
ClientToScreen(window, point);
TrackPopupMenu(ClumpMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
point->x, point->y, 0, window, NULL);
}
}
else
{
/*
* Its the background menu. Depending on whether we are displaying
* a backdrop or the straight backdrop color we enable and disable
* pop-up menu options.
*/
if (RwGetCameraBackdrop(Camera) == NULL)
{
EnableMenuItem(BackgroundMenu, IDM_BACKGROUNDPOPUP_COLOR, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(BackgroundMenu, IDM_BACKGROUNDPOPUP_DELETE, MF_BYCOMMAND | MF_GRAYED);
}
else
{
if (CenterBackdrop)
EnableMenuItem(BackgroundMenu, IDM_BACKGROUNDPOPUP_COLOR, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(BackgroundMenu, IDM_BACKGROUNDPOPUP_COLOR, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(BackgroundMenu, IDM_BACKGROUNDPOPUP_DELETE, MF_BYCOMMAND | MF_ENABLED);
}
/*
* Display the background menu.
*/
ClientToScreen(window, point);
TrackPopupMenu(BackgroundMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON,
point->x, point->y, 0, window, NULL);
}
}
MouseMoveMode = mmNoAction;
}
/*
* If any form of action is to be taken on mouse move, remember the
* the current x and y position of the mouse and capture future
* mouse movement.
*/
if (MouseMoveMode != mmNoAction)
{
SetCapture(window);
LastX = point->x;
LastY = point->y;
}
}
/**********************************************************************/
/*
* Handle a movement of the mouse. If a previous left or right mouse
* button down event has set a mouse move mode then this function will
* take the necessary actions. For example, pan and zooming the camera,
* panning the light, dragging or spinning a clump etc.
*/
static void
OnMouseMove(HWND window, POINT *point)
{
RwClump *parent;
RwMatrix4d *tmpMatrix;
RwMatrix4d *worldToLocal;
RwV3d up;
RwV3d right;
RwV3d at;
RwReal yDelta;
RwReal xAngle;
RwReal yAngle;
RwInt32 xOffset;
RwInt32 yOffset;
RwV3d p;
RwV3d o;
/*
* MouseMoveMode tells us what kind of action to perform.
*/
switch (MouseMoveMode)
{
case mmNoAction:
break;
case mmScrollBackdrop:
/*
* We are scrolling the camera's backdrop. Movement of the
* mouse in X scrolls the backdrop horizontally. Movement of
* the mouse in Y scrolls the backdrop vertically.
*/
RwGetCameraBackdropOffset(Camera, &xOffset, &yOffset);
xOffset += (LastX - point->x);
yOffset += (LastY - point->y);
RwSetCameraBackdropOffset(Camera, xOffset, yOffset);
break;
case mmMoveAndTurnCamera:
/*
* We are moving and turning the camera. Movement of the
* mouse in the X direction will turns the camera to the left
* and right, and movement of the mouse in the Y direction
* moves the camera forward (along its look at) or back..
*/
yDelta = RDiv(INT2REAL(LastY - point->y), CREAL(50.0));
/*
* Move the camera back to the origin, as we wish to pan about
* the origin of the world and not about the origin of the
* camera.
*/
RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), yDelta);
/*
* Pan the camera by mouse X delta degrees.
*/
RwPanCamera(Camera, RDiv(INT2REAL(LastX - point->x), CREAL(4.0)));
break;
case mmTiltCamera:
RwTiltCamera(Camera, INT2REAL(point->y - LastY));
break;
case mmSpinClump:
/* Only spin clumps and lights */
if((GETOBJECTTYPE(SelectedClump)==rfIsClump) || (GETOBJECTTYPE(SelectedClump)==rfIsLight))
{
if(GETOBJECTTYPE(SelectedClump)==rfNoMoveClump) break; // don't move unmoveable clump
/*
* Compute the angles of spin (simply derived from the mouse move deltas).
*/
yAngle = INT2REAL(point->x - LastX);
xAngle = INT2REAL(point->y - LastY);
/*
* In RwView, a clump is spun about its own, local coordinate system,
* origin, rather than the origin of the world coordinate system. There
* are a number of ways this could be achieved, but the most convenient
* is to simply apply the rotations to the clump's joint (articulation)
* transform.
*
* A further important point is that the axes of rotation must be the
* camera's Look Up and Look Right vector rather than simply
* [CREAL(0.0), CREAL(1.0), CREAL(0.0)] and
* [CREAL(1.0), CREAL(0.0), CREAL(0.0)]. This ensures that, if the camera
* has been panned, tilted, revolved or transformed so that it no longer
* looks down the Z axis, user interaction will still operate correctly,
* i.e. moving the mouse to the left will spin the clump clockwise etc.
*
* Therefore, the first stage is to get the camera's Look Up and
* Look Right vectors.
*/
RwGetCameraLookUp(Camera, &up);
RwGetCameraLookRight(Camera, &right);
/*
* Unfortunately, rotation about the camera's Look Up and Look Right
* vectors is complicated if the clump being manipulated is a child
* clump (i.e. not the root of a clump hierarchy). If this is the
* case, the camera's vectors have to be transformed into the
* coordinate space of the parent of the clump being manipulated.
*/
parent = RwGetClumpParent(SelectedClump);
if (parent != NULL)
{
/*
* Get a handle to a couple of temporary matrices.
*/
tmpMatrix = RwPushScratchMatrix();
worldToLocal = RwPushScratchMatrix();
/*
* Get the parent clump's LTM (which maps local coordinates to
* world space).
*/
RwGetClumpLTM(parent, tmpMatrix);
/*
* Invert it so that it maps world coordinates to the parent's
* local coordinate space.
*/
RwInvertMatrix(tmpMatrix, worldToLocal);
/*
* And transform the camera's vectors into local space.
*/
RwTransformVector(&up, worldToLocal);
RwNormalize(&up);
RwTransformVector(&right, worldToLocal);
RwNormalize(&right);
/*
* Discard the temporary matrices.
*/
RwPopScratchMatrix();
RwPopScratchMatrix();
}
/*
* Apply the rotations.
*/
RwRotateMatrix(SpinMatrix, up.x, up.y, up.z, yAngle, rwREPLACE);
RwRotateMatrix(SpinMatrix, right.x, right.y, right.z, xAngle, rwPOSTCONCAT);
/*
* Apply the resulting, composite transformation to the clump.
*/
RwTransformClumpJoint(SelectedClump, SpinMatrix, rwPOSTCONCAT);
/*
* Does the clump represent a light? If so change the light's
* orientation to match that of the clump.
*/
if (ISCLUMPLIGHT(SelectedClump))
{
RwGetClumpLTM(SelectedClump, RwScratchMatrix());
RwTransformLight(GETCLUMPLIGHT(SelectedClump), RwScratchMatrix(), rwREPLACE);
}
else
{
/*
* If the clump is not representing a light enable the momentum spin.
* (Giving a light momentum is a little strange).
*/
SpinClump = TRUE;
}
}
break;
case mmDragClump:
/* Don't drag splines */
if((GETOBJECTTYPE(SelectedClump)==rfIsSpline)|| (GETOBJECTTYPE(SelectedClump)==rfNoMoveClump)) break;
/*
* Get the 3D position of the mouse pointer on the plane parallel
* to the camera on which the picked clump lies.
*/
GetClumpPositionUnderPointer(SelectedClump, Camera, point->x, point->y, &p);
p.x = RAdd(p.x, PickOffset.x);
p.y = RAdd(p.y, PickOffset.y);
p.z = RAdd(p.z, PickOffset.z);
RwGetClumpOrigin(SelectedClump, &o);
p.x = RSub(p.x, o.x);
p.y = RSub(p.y, o.y);
p.z = RSub(p.z, o.z);
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(), p.x, p.y, p.z, rwREPLACE);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
/*
* Does the clump represent a light? If so change the light's
* orientation to match that of the clump.
*/
if (ISCLUMPLIGHT(SelectedClump))
{
RwGetClumpLTM(SelectedClump, RwScratchMatrix());
RwTransformLight(GETCLUMPLIGHT(SelectedClump), RwScratchMatrix(), rwREPLACE);
}
break;
case mmDragClumpInZ:
/* Don't drag splines in Z */
if((GETOBJECTTYPE(SelectedClump)==rfIsSpline)|| (GETOBJECTTYPE(SelectedClump)==rfNoMoveClump)) break;
RwPushScratchMatrix();
/*
* Compute the amount to translate the object by. This is simply
* derived from the mouse deltas scaled by some arbitrary quantity
* to prevent objects moving too "quickly".
*/
yDelta = RDiv(INT2REAL(LastY - point->y), CREAL(50.0));
/*
* In a similar fashion to spinning a clump we must take into account
* the camera's orientation when dragging a clump. This is done by
* translating along the camera's Look At vector (scaled appropriately)
* rather than the clump's local axes.
*/
RwGetCameraLookAt(Camera, &at);
/*
* See the case for mmSpinClump: for a description of why the
* following is necessary.
*/
parent = RwGetClumpParent(SelectedClump);
if (parent != NULL)
{
tmpMatrix = RwPushScratchMatrix();
worldToLocal = RwPushScratchMatrix();
RwGetClumpLTM(parent, tmpMatrix);
RwInvertMatrix(tmpMatrix, worldToLocal);
RwTransformVector(&at, worldToLocal);
RwNormalize(&at);
RwPopScratchMatrix();
RwPopScratchMatrix();
}
/*
* Perform the translation.
*/
RwTranslateMatrix(RwScratchMatrix(),
RMul(at.x, yDelta), RMul(at.y, yDelta),
RMul(at.z, yDelta), rwREPLACE);
/*
* Apply the resulting, composite transform to the clump.
*/
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
/*
* Does the clump represent a light? If so change the light's
* orientation to match that of the clump.
*/
if (ISCLUMPLIGHT(SelectedClump))
{
RwGetClumpLTM(SelectedClump, RwScratchMatrix());
RwTransformLight(GETCLUMPLIGHT(SelectedClump), RwScratchMatrix(), rwREPLACE);
}
break;
}
if (MouseMoveMode != mmNoAction)
{
/*
* Re-render the scene and copy the results to the display.
*/
RenderScene(window);
/*
* Remember the current X and Y for next time.
*/
LastX = point->x;
LastY = point->y;
}
}
/**********************************************************************/
/*
* Handle the left mouse button comming back up. The basic action is
* to turn off mouse move actions and release mouse capture.
*/
static void
OnLButtonUp(void)
{
/*
* If we were engaged in a mouse move action and the button has come
* back up, then terminate the action and release mouse capture.
*/
if (MouseMoveMode != mmNoAction)
{
MouseMoveMode = mmNoAction;
ReleaseCapture();
}
}
/**********************************************************************/
/*
* Handle the right mouse button comming back up. The basic action is
* to turn of mouse move actions and release mouse capture.
*/
static void
OnRButtonUp(void)
{
/*
* If we were engaged in a mouse move action and the button has come
* back up, then terminate the action and release mouse capture.
*/
if (MouseMoveMode != mmNoAction)
{
MouseMoveMode = mmNoAction;
ReleaseCapture();
}
}
/**********************************************************************/
/*
* Handle an MS Window's drop message, this function will attempt to
* load the file dropped as a RenderWare clump. If that fails, it will
* then attempt to load the file as a raster and make it the camera's
* backdrop.
*/
static void
OnDrop(HWND window, HDROP drop)
{
int i;
int numFiles;
char path[_MAX_PATH];
/*
* Get the number of dropped files.
*/
numFiles = DragQueryFile(drop, (UINT)-1, NULL, 0U);
/*
* Attempt to load each file in turn.
*/
for (i = 0; i < numFiles; i++)
{
/*
* Attempt to load the object whose file was dropped. The
* actual object type to load is determined by LoadObject()
* from the file extenstion.
*/
DragQueryFile(drop, i, path, _MAX_PATH);
if (LoadObject(window, path))
{
/*
* Update the MRU file list and menus.
*/
DeleteMRUFileMenuItems(window);
AddFileToMRUFileList(path);
AppendMRUFileMenuItems(window);
}
else
{
DragFinish(drop);
return;
}
}
DragFinish(drop);
/*
* As new objects have been loaded we must re-render the scene.
*/
RenderScene(window);
}
/**********************************************************************/
/*
* Handle the WM_PAINT message by simply copying the rendering
* already performed (an stored in the camera's image buffer) to the
* output window. There is no need to re-render as nothing in the
* scene has changed since the last render. HandleSize() re-renders
* when the viewport changes and HandleDrop() re-renders when
* clumps are added.
*/
static void
OnPaint(HWND window)
{
HDC dc;
PAINTSTRUCT paintStruct;
dc = BeginPaint(window, &paintStruct);
/*
* The truly optimal thing to do would be to get the damaged area
* of the window that needs updating and set that to be the damaged
* area of the viewport. If this was done then only the portion of
* viewport corresponding to damaged area of the window would be
* copied. However, as WM_PAINTs are rare in comparison to timer
* expiries or mouse moves (where the real rendering effort goes)
* there is little to be gained from damaging only a portion of
* the display. Therefore, we invalidate the entire viewport and
* copy it all to the window.
*/
RwInvalidateCameraViewport(Camera);
/*
* Copy the viewport to the display.
*/
RwShowCameraImage(Camera, (void*)(DWORD)dc);
EndPaint(window, &paintStruct);
}
/*
* Handle menu selections.
*/
static void
OnMenu(HWND window, WPARAM item)
{
OPENFILENAME ofn;
int len;
char fileName[_MAX_PATH];
char directory[_MAX_PATH];
char dir[_MAX_DIR];
char ext[_MAX_EXT];
FARPROC dialogProc;
RwV3d point;
RwV3d right;
RwV3d up;
RwClump *newClump;
RwLight *light;
HCURSOR oldCursor;
RwRGBColor color;
int rfSideCode=rfSideA;
char buffer[128];
RwBool status;
RwTexture *applyTexture;
RwTextureModes rfTexModes;
RwPolygon3d *applyPolygon;
RwClump *rootClump;
RwReal angle=CREAL(0.0);
int i;
RwInt32 rfStart,rfLength,rfRet;
RwPaletteOptions rfGamma;
RwPaletteEntry* rfPalette;
RwCombineOperation combine=rwPOSTCONCAT;
BOOL badret;
short rval=0,gval=0,bval=0;
ClumpUserData * clumpData;
switch (item)
{
// ********************************************** make a clump unMoveable ******************************************
/* clumps can be made unMoveable. Once so, they can only be deleted. They can not be changed back to moveable */
case IDM_NoMoveClump:
if(GETOBJECTTYPE(SelectedClump)==rfIsClump) { // if selected object is a clump
rootClump = RwGetClumpRoot(SelectedClump); // get the clump root
clumpData = RwGetClumpData(rootClump); // get the clump (root) data
clumpData->datatype = rfNoMoveClump; // change object type to NoMoveClump
RwSetClumpData(rootClump,clumpData); // set it
}
break;
// ********************************************** turn all lights on and off ******************************************
case RF_LIGHTSON:
RwForAllLightsInSceneInt(Scene, (RwLightFuncInt)RwSetLightState, rwON);
break;
case RF_LIGHTSOFF:
RwForAllLightsInSceneInt(Scene, (RwLightFuncInt)RwSetLightState, rwOFF);
break;
// ********************************************** splines ******************************************
/* Hide or show the spline track on the current spline */
case IDM_HIDESPLINETRACK:
if (HideSpline)
{
/* We are currently not viewing spline path. So turn it on and uncheck the menu item.*/
HideSpline = FALSE;
CheckMenuItem(GetMenu(window), IDM_HIDESPLINETRACK, MF_BYCOMMAND | MF_UNCHECKED);
EnableCoasterTrack(coaster);
}
else
{
/* We are currently viewing spline path. So turn it off and check the menu item.*/
HideSpline = TRUE;
CheckMenuItem(GetMenu(window), IDM_HIDESPLINETRACK, MF_BYCOMMAND | MF_CHECKED);
DisableCoasterTrack(coaster);
}
RenderScene(window);
break;
/* hide the control points on the current spline */
case IDM_HIDESPLINECONTROLPOINTS:
if (HideControlPoints)
{
/* We are currently not viewing control points. So turn them on and uncheck the menu item.*/
HideControlPoints = FALSE;
CheckMenuItem(GetMenu(window), IDM_HIDESPLINECONTROLPOINTS, MF_BYCOMMAND | MF_UNCHECKED);
EnableCoasterControlPoints(coaster);
}
else
{
/* We are currently viewing control points. So turn them off and check the menu item.*/
HideControlPoints = TRUE;
CheckMenuItem(GetMenu(window), IDM_HIDESPLINECONTROLPOINTS, MF_BYCOMMAND | MF_CHECKED);
DisableCoasterControlPoints(coaster);
}
RenderScene(window);
break;
/* delete a spline */
case IDM_DELSPLINE:
DeleteCoaster(coaster);
RenderScene(window);
break;
/* move the currently selected object on the spline. If the currently selected object is not on the spline,
then place it at the start of the spline (0.0) and move it.*/
case IDM_MOVEOBJECTONSPLINE:
if (TravelSpline)
{
/* We are currently moving on spline so stop moving and uncheck the menu item.
*/
TravelSpline = FALSE;
rfRepeatMode = FALSE;
CheckMenuItem(GetMenu(window), IDM_MOVEOBJECTONSPLINE, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/* We are currently notmoving on spline so start moving and check the menu item. */
TravelSpline = TRUE;
rfRepeatMode = TRUE;
CheckMenuItem(GetMenu(window), IDM_MOVEOBJECTONSPLINE, MF_BYCOMMAND | MF_CHECKED);
}
break;
/* place the currently selected object onto the start of the spline (0.0). Orient it such that Y is up and
z points positively along the spline */
case IDM_PLACEOBJECTONSPLINE: // only place clumps on spline
if (GETOBJECTTYPE(SelectedClump)==rfIsClump)
{
if(GETOBJECTTYPE(SelectedClump)==rfNoMoveClump) break;
coaster->t = (float)0.0;
PositionObjectOnSpline(coaster,SelectedClump);
RenderScene(window);
}
break;
/* accelerate at the start of the spline and decelerate at the end of the spline */
case IDM_SMOOTHEND:
if (UseSmoothEnd)
{
/* We are currently using smooth ends so don't use them and uncheck the menu item.*/
UseSmoothEnd = FALSE;
CheckMenuItem(GetMenu(window), IDM_SMOOTHEND, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/* We are currently not using smooth ends so use them So turn them back on and check the menu item. */
UseSmoothEnd = TRUE;
CheckMenuItem(GetMenu(window), IDM_SMOOTHEND, MF_BYCOMMAND | MF_CHECKED);
}
break;
// ********************************************** camera ******************************************
case ID_BCAM: // bird's eye camera
CurrentCamera = BirdsEyeCamera; CurrentWindow = window;
dialogProc = MakeProcInstance(CameraDlgProc, AppInstance);
if (DialogBox(AppInstance, MAKEINTRESOURCE(IDD_CAMERA),
window, dialogProc)==IDOK)
{
RenderScene(window);
}
FreeProcInstance(dialogProc);
break;
case ID_VCAM: // main camera
CurrentCamera = Camera; CurrentWindow = window;
dialogProc = MakeProcInstance(CameraDlgProc, AppInstance);
if (DialogBox(AppInstance, MAKEINTRESOURCE(IDD_CAMERA),
window, dialogProc)==IDOK)
{
RenderScene(window);
}
FreeProcInstance(dialogProc);
break;
// ********************************************** debug ******************************************
/* Display the DEBUG box. */
case IDM_DEBUG:
dialogProc = MakeProcInstance(DebugDlgProc, AppInstance);
DialogBox(AppInstance, MAKEINTRESOURCE(IDD_DEBUG), window, dialogProc);
FreeProcInstance(dialogProc);
break;
// ********************************************** palette ******************************************
/* build either a red, green, blue or gray ramp beginning at 10 and ending at 242 */
case ID_PALETTE_RED: case ID_PALETTE_GREEN: case ID_PALETTE_BLUE: case ID_PALETTE_GRAY:
rfPalette = (RwPaletteEntry*) malloc(256 * sizeof(RwPaletteEntry));
rfGamma = rwOFF;
switch(item)
{
case ID_PALETTE_RED:
rval=1; gval=0; bval=0;
break;
case ID_PALETTE_GREEN:
rval=0; gval=1; bval=0;
break;
case ID_PALETTE_BLUE:
rval=0; gval=0; bval=1;
break;
case ID_PALETTE_GRAY:
rval=1; gval=1; bval=1;
break;
}
/* build the color ramp from 10 to 242 */
rfStart = 10; rfLength = 232;
for (i=0; i<rfLength; i++)
{
rfPalette[i].r = (unsigned char)((i+10)*rval);
rfPalette[i].g = (unsigned char)((i+10)*gval);
rfPalette[i].b = (unsigned char)((i+10)*bval);
}
rfRet = RwSetPaletteEntries(rfStart,rfLength,(RwPaletteEntry *) rfPalette, rfGamma);
free(rfPalette);
RenderScene(window);
break;
/* build a default palette consisting of several ramps */
case ID_PALETTE_DEFAULT:
rfPalette = (RwPaletteEntry*) malloc(256 * sizeof(RwPaletteEntry));
rfGamma = rwOFF;
RtDefaultPalette(rfPalette);
rfStart = 10; rfLength = 10*MAXLUM;
rfRet = RwSetPaletteEntries(rfStart,rfLength,(RwPaletteEntry *) rfPalette, rfGamma);
free(rfPalette);
RenderScene(window);
break;
// ********************************************** textures ******************************************
// cubic texture map clump
case ID_CUBIC:
RwCubicTexturizeClump(SelectedClump);
RenderScene(window);
break;
// spherical texture map clump
case ID_SPHERICAL:
RwSphericalTexturizeClump(SelectedClump);
RenderScene(window);
break;
// environmental texture map the clump
case ID_ENVIRON:
/* rotate the selected object according to the user rotate values */
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = CREAL(1.0); rfRel.vc.z = CREAL(0.0); angle = (RwReal)rfRot.val; combine = rfRot.combine;
/* build the rotate (local or global) matrix */
RwPushScratchMatrix();
RwGetClumpOrigin(SelectedClump,&rfRel.pos);
rfRel.up.x = CREAL(0.0); rfRel.up.y = CREAL(1.0); rfRel.up.z = CREAL(0.0);
rfRel.at.x = CREAL(0.0); rfRel.at.y = CREAL(0.0); rfRel.at.z = CREAL(1.0);
rfRel.right.x = CREAL(1.0); rfRel.right.y = CREAL(0.0); rfRel.right.z = CREAL(0.0);
if(combine==rwPRECONCAT) {
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.up,RwScratchMatrix());
RwTransformVector(&rfRel.at,RwScratchMatrix());
RwTransformVector(&rfRel.right,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),-rfRel.pos.x,-rfRel.pos.y,-rfRel.pos.z,rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),
(rfRel.vc.x * rfRel.right.x) + (rfRel.vc.y * rfRel.up.x) + (rfRel.vc.z * rfRel.at.x),
(rfRel.vc.x * rfRel.right.y) + (rfRel.vc.y * rfRel.up.y) + (rfRel.vc.z * rfRel.at.y),
(rfRel.vc.x * rfRel.right.z) + (rfRel.vc.y * rfRel.up.z) + (rfRel.vc.z * rfRel.at.z),
angle,rwPOSTCONCAT);
RwTranslateMatrix(RwScratchMatrix(),rfRel.pos.x,rfRel.pos.y,rfRel.pos.z,rwPOSTCONCAT);
}
else {
RwRotateMatrix(RwScratchMatrix(),rfRel.vc.x, rfRel.vc.y, rfRel.vc.z, angle, rwREPLACE);
}
/* rotate the object according to the user rotate value */
if(rfRot.repeat!=1) rfRepeatMode = TRUE;
for (i=0; i<rfRot.repeat; i++) {
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
RwBeginCameraUpdate(Camera,(void *)window); // necessary for EnvMap
RwEnvMapClump(SelectedClump); // perform environment map
RwEndCameraUpdate(Camera);
if(i == rfRot.repeat-1) rfRepeatMode = FALSE;
RenderScene(window);
}
RwPopScratchMatrix();
break;
// LIT the texture to the tagged side of our selected object
case ID_LITA: case ID_LITB: case ID_LITC: case ID_LITD:
switch(item) {
case ID_LITA: rfSideCode = rfSideA; break;
case ID_LITB: rfSideCode = rfSideB; break;
case ID_LITC: rfSideCode = rfSideC; break;
case ID_LITD: rfSideCode = rfSideD; break;
}
applyPolygon = RwFindTaggedPolygon(SelectedClump,rfSideCode);
rfTexModes=RwGetPolygonTextureModes(applyPolygon);
RwSetPolygonTextureModes(applyPolygon,rfTexModes ^ rwLIT);
RenderScene(window);
break;
// Filter the texture to the tagged side of our selected object
case ID_FILTERA: case ID_FILTERB: case ID_FILTERC: case ID_FILTERD:
switch(item) {
case ID_FILTERA: rfSideCode = rfSideA; break;
case ID_FILTERB: rfSideCode = rfSideB; break;
case ID_FILTERC: rfSideCode = rfSideC; break;
case ID_FILTERD: rfSideCode = rfSideD; break;
}
applyPolygon = RwFindTaggedPolygon(SelectedClump,rfSideCode);
rfTexModes=RwGetPolygonTextureModes(applyPolygon);
RwSetPolygonTextureModes(applyPolygon,rfTexModes ^ rwFILTER);
RenderScene(window);
break;
// ForeShorten the texture to the tagged side of our selected object
case ID_FOREA: case ID_FOREB: case ID_FOREC: case ID_FORED:
switch(item) {
case ID_FOREA: rfSideCode = rfSideA; break;
case ID_FOREB: rfSideCode = rfSideB; break;
case ID_FOREC: rfSideCode = rfSideC; break;
case ID_FORED: rfSideCode = rfSideD; break;
}
applyPolygon = RwFindTaggedPolygon(SelectedClump,rfSideCode);
rfTexModes=RwGetPolygonTextureModes(applyPolygon);
RwSetPolygonTextureModes(applyPolygon,rfTexModes ^ rwFORESHORTEN);
RenderScene(window);
break;
// apply a texture to our selected object
case ID_APPLYA: case ID_APPLYB: case ID_APPLYC: case ID_APPLYD: case ID_APPLYALL:
_splitpath(LastFileName, directory, dir, fileName, ext);
strcat(fileName, ext);
strcat(directory, dir);
len = strlen(directory);
if ((len > 0) && (directory[len - 1] == '\\'))
directory[len - 1] = '\0';
/* select the texture to map onto the selected object */
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = window;
ofn.lpstrFilter = "Texture (*.bmp)\0*.bmp\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile= fileName;
ofn.nMaxFile = sizeof(fileName);
ofn.lpstrInitialDir = directory;
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
/* Save the file name for next time */
strcpy(LastFileName, fileName);
/* Read the texture */
applyTexture=RwReadTexture(fileName);
/* if successful, then apply the texture to one tagged side or all sides */
if (applyTexture!=NULL)
{
switch(item) {
case ID_APPLYA:
rfSideCode = rfSideA;
break;
case ID_APPLYB:
rfSideCode = rfSideB;
break;
case ID_APPLYC:
rfSideCode = rfSideC;
break;
case ID_APPLYD:
rfSideCode = rfSideD;
break;
case ID_APPLYALL:
rfSideCode = rfSideAll;
break;
}
if(rfSideCode==rfSideAll)
{
RwForAllPolygonsInClumpPointer(SelectedClump, (RwPolygon3dFuncPointer)RwSetPolygonTexture, NULL);
RwForAllPolygonsInClumpPointer(SelectedClump, (RwPolygon3dFuncPointer)RwSetPolygonTexture, applyTexture);}
else
{
applyPolygon = RwFindTaggedPolygon(SelectedClump,rfSideCode);
RwSetPolygonTexture(applyPolygon, NULL);
RwSetPolygonTexture(applyPolygon, applyTexture);
}
RenderScene(window);
}
}
break;
// ******************************************* Pre and Post Concat ***************************************
// translate then rotate preconcat
case ID_PRECON1:
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(),CREAL(0.0),CREAL(0),CREAL(1.2),rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),CREAL(1),CREAL(0),CREAL(0),CREAL(45.0),rwPRECONCAT);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
RenderScene(window);
break;
// translate then rotate postconcat
case ID_POSTCON1:
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(),CREAL(0.0),CREAL(0),CREAL(1.2),rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),CREAL(1),CREAL(0),CREAL(0),CREAL(45.0),rwPOSTCONCAT);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
RenderScene(window);
break;
// rotate then translate preconcat
case ID_PRECON2:
RwPushScratchMatrix();
RwRotateMatrix(RwScratchMatrix(),CREAL(1),CREAL(0),CREAL(0),CREAL(45.0),rwREPLACE);
RwTranslateMatrix(RwScratchMatrix(),CREAL(0.0),CREAL(0),CREAL(1.2),rwPRECONCAT);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
RenderScene(window);
break;
// rotate then translate postconcat
case ID_POSTCON2:
RwPushScratchMatrix();
RwRotateMatrix(RwScratchMatrix(),CREAL(1),CREAL(0),CREAL(0),CREAL(45.0),rwREPLACE);
RwTranslateMatrix(RwScratchMatrix(),CREAL(0.0),CREAL(0),CREAL(1.2),rwPOSTCONCAT);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
RenderScene(window);
break;
// **************************************** pan, revolve, and tilt *************************************
/* pan the selected object */
case IDC_PAN:
RwPushScratchMatrix();
RwGetClumpOrigin(SelectedClump,&rfRel.pos);
// about local Y UP
rfRel.up.x = CREAL(0.0); rfRel.up.y = CREAL(1.0); rfRel.up.z = CREAL(0.0);
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.up,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),-rfRel.pos.x,-rfRel.pos.y,-rfRel.pos.z,rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),rfRel.up.x, rfRel.up.y, rfRel.up.z, (RwReal)rfLoc.val,rwPOSTCONCAT);
RwTranslateMatrix(RwScratchMatrix(),rfRel.pos.x,rfRel.pos.y,rfRel.pos.z,rwPOSTCONCAT);
if(rfLoc.repeat!=1) rfRepeatMode = TRUE;
for (i=0; i<rfLoc.repeat; i++) {
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
if(i == rfLoc.repeat-1) rfRepeatMode = FALSE;
RenderScene(window);
}
RwPopScratchMatrix();
break;
/* revolve the selected object */
case IDC_REVOLVE:
RwPushScratchMatrix();
RwGetClumpOrigin(SelectedClump,&rfRel.pos);
// about local Z AT
rfRel.at.x = CREAL(0.0); rfRel.at.y = CREAL(0.0); rfRel.at.z = CREAL(1.0);
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.at,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),-rfRel.pos.x,-rfRel.pos.y,-rfRel.pos.z,rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),rfRel.at.x, rfRel.at.y, rfRel.at.z, (RwReal)rfLoc.val,rwPOSTCONCAT);
RwTranslateMatrix(RwScratchMatrix(),rfRel.pos.x,rfRel.pos.y,rfRel.pos.z,rwPOSTCONCAT);
if(rfLoc.repeat!=1) rfRepeatMode = TRUE;
for (i=0; i<rfLoc.repeat; i++) {
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
if(i == rfLoc.repeat-1) rfRepeatMode = FALSE;
RenderScene(window);
}
RwPopScratchMatrix();
break;
/* tilt the selected object */
case IDC_TILT:
RwPushScratchMatrix();
// about local X RIGHT
RwGetClumpOrigin(SelectedClump,&rfRel.pos);
rfRel.right.x = CREAL(1.0); rfRel.right.y = CREAL(0.0); rfRel.right.z = CREAL(0.0);
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.right,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),-rfRel.pos.x,-rfRel.pos.y,-rfRel.pos.z,rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),rfRel.right.x, rfRel.right.y, rfRel.right.z,(RwReal) rfLoc.val, rwPOSTCONCAT);
RwTranslateMatrix(RwScratchMatrix(),rfRel.pos.x,rfRel.pos.y,rfRel.pos.z,rwPOSTCONCAT);
if(rfLoc.repeat!=1) rfRepeatMode = TRUE;
for (i=0; i<rfLoc.repeat; i++) {
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
if(i == rfLoc.repeat-1) rfRepeatMode = FALSE;
RenderScene(window);
}
RwPopScratchMatrix();
break;
/* pan, revolve and tilt setup */
case IDD_PRT_SETUP:
dialogProc = MakeProcInstance(PRTDlgProc, AppInstance);
if (DialogBox(AppInstance, MAKEINTRESOURCE(IDD_PRT_SETUP),
window, dialogProc)==IDCANCEL)
{
FreeProcInstance(dialogProc);
return;
}
FreeProcInstance(dialogProc);
break;
// ********************************************** translate ******************************************
// translate the selected object about the X, Y, Z or User (local or global) defined axis
case ID_TRANSX: case ID_TRANSY: case ID_TRANSZ: case ID_TRANSU:
switch(item) {
case ID_TRANSX:
rfRel.vc.x = rfTran.x; rfRel.vc.y = CREAL(0.0); rfRel.vc.z = CREAL(0.0); combine = rfTran.combine;
break;
case ID_TRANSY:
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = rfTran.y; rfRel.vc.z = CREAL(0.0); combine = rfTran.combine;
break;
case ID_TRANSZ:
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = CREAL(0.0); rfRel.vc.z = rfTran.z; combine = rfTran.combine;
break;
case ID_TRANSU: // user defined through dialog
dialogProc = MakeProcInstance(TranslateDlgProc, AppInstance);
if (DialogBoxParam(AppInstance, MAKEINTRESOURCE(RDD_TRANSLATE),
window, dialogProc, (LPARAM)SelectedClump)==IDCANCEL)
{
FreeProcInstance(dialogProc);
return;
}
rfRel.vc.x = rfTran.x; rfRel.vc.y = rfTran.y; rfRel.vc.z = rfTran.z; combine = rfTran.combine;
break;
}
rfRel.up.x = CREAL(0.0); rfRel.up.y = CREAL(1.0); rfRel.up.z = CREAL(0.0);
rfRel.at.x = CREAL(0.0); rfRel.at.y = CREAL(0.0); rfRel.at.z = CREAL(1.0);
rfRel.right.x = CREAL(1.0); rfRel.right.y = CREAL(0.0); rfRel.right.z = CREAL(0.0);
RwPushScratchMatrix();
if(combine==rwPRECONCAT) {
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.up,RwScratchMatrix());
RwTransformVector(&rfRel.at,RwScratchMatrix());
RwTransformVector(&rfRel.right,RwScratchMatrix());
}
RwTranslateMatrix(RwScratchMatrix(),
(rfRel.vc.x * rfRel.right.x) + (rfRel.vc.y * rfRel.up.x) + (rfRel.vc.z * rfRel.at.x),
(rfRel.vc.x * rfRel.right.y) + (rfRel.vc.y * rfRel.up.y) + (rfRel.vc.z * rfRel.at.y),
(rfRel.vc.x * rfRel.right.z) + (rfRel.vc.y * rfRel.up.z) + (rfRel.vc.z * rfRel.at.z),rwREPLACE);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
RenderScene(window);
break;
// ******************************************* scale ***************************************
// scale the selected object about the X, Y, Z or User (local or global) defined axis
case ID_SCALEX: case ID_SCALEY: case ID_SCALEZ: case ID_SCALEU:
switch(item) {
case ID_SCALEX:
rfRel.vc.x = rfScale.x; rfRel.vc.y = CREAL(1.0); rfRel.vc.z = CREAL(1.0); combine = rfScale.combine;
break;
case ID_SCALEY:
rfRel.vc.x = CREAL(1.0); rfRel.vc.y = rfScale.y; rfRel.vc.z = CREAL(1.0); combine = rfScale.combine;
break;
case ID_SCALEZ:
rfRel.vc.x = CREAL(1.0); rfRel.vc.y = CREAL(1.0); rfRel.vc.z = rfScale.z; combine = rfScale.combine;
break;
case ID_SCALEU:
dialogProc = MakeProcInstance(ScaleDlgProc, AppInstance);
if (DialogBoxParam(AppInstance, MAKEINTRESOURCE(RDD_SCALE),
window, dialogProc, (LPARAM)SelectedClump)==IDCANCEL){
FreeProcInstance(dialogProc);
return;
}
rfRel.vc.x = rfScale.x; rfRel.vc.y = rfScale.y; rfRel.vc.z = rfScale.z;
combine = rfScale.combine;
FreeProcInstance(dialogProc);
break;
}
RwPushScratchMatrix();
RwGetClumpOrigin(SelectedClump,&rfRel.pos);
rfRel.up.x = CREAL(0.0); rfRel.up.y = CREAL(1.0); rfRel.up.z = CREAL(0.0);
rfRel.at.x = CREAL(0.0); rfRel.at.y = CREAL(0.0); rfRel.at.z = CREAL(1.0);
rfRel.right.x = CREAL(1.0); rfRel.right.y = CREAL(0.0); rfRel.right.z = CREAL(0.0);
if(combine==rwPRECONCAT) {
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.up,RwScratchMatrix());
RwTransformVector(&rfRel.at,RwScratchMatrix());
RwTransformVector(&rfRel.right,RwScratchMatrix());
RwNormalize(&rfRel.up);
RwNormalize(&rfRel.right);
RwNormalize(&rfRel.at);
}
RwTranslateMatrix(RwScratchMatrix(),-rfRel.pos.x,-rfRel.pos.y,-rfRel.pos.z,rwREPLACE);
RwScaleMatrix(RwScratchMatrix(),
(rfRel.vc.x * rfRel.right.x) + (rfRel.vc.y * rfRel.up.x) + (rfRel.vc.z * rfRel.at.x),
(rfRel.vc.x * rfRel.right.y) + (rfRel.vc.y * rfRel.up.y) + (rfRel.vc.z * rfRel.at.y),
(rfRel.vc.x * rfRel.right.z) + (rfRel.vc.y * rfRel.up.z) + (rfRel.vc.z * rfRel.at.z),rwPOSTCONCAT);
RwTranslateMatrix(RwScratchMatrix(),rfRel.pos.x,rfRel.pos.y,rfRel.pos.z,rwPOSTCONCAT);
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
RenderScene(window);
RwPopScratchMatrix();
break;
// ******************************************* rotate ***************************************
// rotate the selected object about the X, Y, Z or User (local or global) defined axis
case ID_ROTX: case ID_ROTY: case ID_ROTZ: case ID_ROTU:
switch(item) {
case ID_ROTX:
rfRel.vc.x = CREAL(1.0); rfRel.vc.y = CREAL(0.0); rfRel.vc.z = CREAL(0.0); angle = (RwReal)rfRot.val; combine = rfRot.combine;
break;
case ID_ROTY:
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = CREAL(1.0); rfRel.vc.z = CREAL(0.0); angle = (RwReal)rfRot.val; combine = rfRot.combine;
break;
case ID_ROTZ:
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = CREAL(0.0); rfRel.vc.z = CREAL(1.0); angle = (RwReal)rfRot.val; combine = rfRot.combine;
break;
case ID_ROTU:
dialogProc = MakeProcInstance(RotateDlgProc, AppInstance);
if (DialogBoxParam(AppInstance, MAKEINTRESOURCE(RDD_ROTATE),
window, dialogProc, (LPARAM)SelectedClump)==IDCANCEL) {
FreeProcInstance(dialogProc);
return;
}
rfRel.vc.x = rfRot.x; rfRel.vc.y = rfRot.y; rfRel.vc.z = rfRot.z;
angle = (RwReal) rfRot.val; combine = (RwReal)rfRot.combine;
FreeProcInstance(dialogProc);
break;
}
RwPushScratchMatrix();
RwGetClumpOrigin(SelectedClump,&rfRel.pos);
rfRel.up.x = CREAL(0.0); rfRel.up.y = CREAL(1.0); rfRel.up.z = CREAL(0.0);
rfRel.at.x = CREAL(0.0); rfRel.at.y = CREAL(0.0); rfRel.at.z = CREAL(1.0);
rfRel.right.x = CREAL(1.0); rfRel.right.y = CREAL(0.0); rfRel.right.z = CREAL(0.0);
if(combine==rwPRECONCAT) {
RwGetClumpLTM(SelectedClump,RwScratchMatrix());
RwTransformVector(&rfRel.up,RwScratchMatrix());
RwTransformVector(&rfRel.at,RwScratchMatrix());
RwTransformVector(&rfRel.right,RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(),-rfRel.pos.x,-rfRel.pos.y,-rfRel.pos.z,rwREPLACE);
RwRotateMatrix(RwScratchMatrix(),
(rfRel.vc.x * rfRel.right.x) + (rfRel.vc.y * rfRel.up.x) + (rfRel.vc.z * rfRel.at.x),
(rfRel.vc.x * rfRel.right.y) + (rfRel.vc.y * rfRel.up.y) + (rfRel.vc.z * rfRel.at.y),
(rfRel.vc.x * rfRel.right.z) + (rfRel.vc.y * rfRel.up.z) + (rfRel.vc.z * rfRel.at.z),angle,rwPOSTCONCAT);
RwTranslateMatrix(RwScratchMatrix(),rfRel.pos.x,rfRel.pos.y,rfRel.pos.z,rwPOSTCONCAT);
}
else {
RwRotateMatrix(RwScratchMatrix(),rfRel.vc.x, rfRel.vc.y, rfRel.vc.z, angle, rwREPLACE);
}
if(rfRot.repeat!=1) rfRepeatMode = TRUE;
for (i=0; i<rfRot.repeat; i++) {
RwTransformClump(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
if(i == rfRot.repeat-1) rfRepeatMode = FALSE;
RenderScene(window);
}
RwPopScratchMatrix();
break;
// ********************************************** Joint Rotate ******************************************
// rotate joing the selected object about the X, Y, Z or User (local or global) defined axis
case ID_JROTX: case ID_JROTY: case ID_JROTZ: case ID_JROTU:
switch(item) {
case ID_JROTX:
rfRel.vc.x = CREAL(1.0); rfRel.vc.y = CREAL(0.0); rfRel.vc.z = CREAL(0.0); angle = (RwReal)rfRot.val;
break;
case ID_JROTY:
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = CREAL(1.0); rfRel.vc.z = CREAL(0.0); angle = (RwReal)rfRot.val;
break;
case ID_JROTZ:
rfRel.vc.x = CREAL(0.0); rfRel.vc.y = CREAL(0.0); rfRel.vc.z = CREAL(1.0); angle = (RwReal)rfRot.val;
break;
case ID_JROTU:
dialogProc = MakeProcInstance(RotateDlgProc, AppInstance);
if (DialogBoxParam(AppInstance, MAKEINTRESOURCE(RDD_ROTATE),
window, dialogProc, (LPARAM)SelectedClump)==IDCANCEL) {
FreeProcInstance(dialogProc);
return;
}
rfRel.vc.x = rfRot.x; rfRel.vc.y = rfRot.y; rfRel.vc.z = rfRot.z;
angle = (RwReal) rfRot.val;
FreeProcInstance(dialogProc);
break;
}
RwPushScratchMatrix();
RwRotateMatrix(RwScratchMatrix(),rfRel.vc.x, rfRel.vc.y, rfRel.vc.z, angle, rwREPLACE);
if(rfRot.repeat!=1) rfRepeatMode = TRUE;
for (i=0; i<rfRot.repeat; i++) {
RwTransformClumpJoint(SelectedClump, RwScratchMatrix(), rwPOSTCONCAT);
if(i == rfRot.repeat-1) rfRepeatMode = FALSE;
RenderScene(window);
}
RwPopScratchMatrix();
break;
// ********************************************** materials ******************************************
// turn on/off material animation
case ID_MANIMATE:
if (rfSurf.MatAnimate) { // turn it off
rfSurf.MatAnimate = FALSE;
CheckMenuItem(GetMenu(window), ID_MANIMATE, MF_BYCOMMAND | MF_UNCHECKED);
}
else { // turn it on
rfSurf.MatAnimate = TRUE;
CheckMenuItem(GetMenu(window), ID_MANIMATE, MF_BYCOMMAND | MF_CHECKED);
}
break;
// turn on/off ambient component of material animation
case MRF_AMBIENT:
if (rfSurf.Ambient) { // turn it off
rfSurf.Ambient = FALSE;
CheckMenuItem(GetMenu(window), MRF_AMBIENT, MF_BYCOMMAND | MF_UNCHECKED);
}
else { // turn it on
rfSurf.Ambient = TRUE;
CheckMenuItem(GetMenu(window), MRF_AMBIENT, MF_BYCOMMAND | MF_CHECKED);
}
break;
// turn on/off diffuse component of material animation
case MRF_DIFFUSE:
if (rfSurf.Diffuse) { // turn it off
rfSurf.Diffuse = FALSE;
CheckMenuItem(GetMenu(window), MRF_DIFFUSE, MF_BYCOMMAND | MF_UNCHECKED);
}
else { // turn it on
rfSurf.Diffuse = TRUE;
CheckMenuItem(GetMenu(window), MRF_DIFFUSE, MF_BYCOMMAND | MF_CHECKED);
}
break;
// turn on/off specular component of material animation
case MRF_SPECULAR:
if (rfSurf.Specular) { // turn it off
rfSurf.Specular = FALSE;
CheckMenuItem(GetMenu(window), MRF_SPECULAR, MF_BYCOMMAND | MF_UNCHECKED);
}
else { // turn it on
rfSurf.Specular = TRUE;
CheckMenuItem(GetMenu(window), MRF_SPECULAR, MF_BYCOMMAND | MF_CHECKED);
}
break;
// ********************************************** select Chapters for path ******************************************
case IDM_CHAP5:
strcpy(fileName,"\\l3d\\chap5\\box"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap5\\poly"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap5\\robot"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap5\\tex1"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP6:
strcpy(fileName,"\\l3d\\chap6\\kitchen"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap6\\ship"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap6\\robot"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP7:
strcpy(fileName,"\\l3d\\chap7\\ball"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap7\\color"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP8:
strcpy(fileName,"\\l3d\\chap8\\box"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap8\\fore"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap8\\turn"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap8\\wall"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP9:
strcpy(fileName,"\\l3d\\chap9\\ani"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap9\\box"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap9\\mask"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap9\\poly"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap9\\ship"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap9\\tex1"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap9\\tex2"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP10:
strcpy(fileName,"\\l3d\\chap10"); RwSetShapePath(fileName, rwREPLACE);
break;
case IDM_CHAP11:
strcpy(fileName,"\\l3d\\chap11"); RwSetShapePath(fileName, rwREPLACE);
break;
case IDM_CHAP12:
strcpy(fileName,"\\l3d\\chap12\\car"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap12\\f16"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap12\\tracks"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap12\\triad"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP13:
strcpy(fileName,"\\l3d\\chap13\\compos"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap13\\coral"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
case IDM_CHAP15:
strcpy(fileName,"\\l3d\\chap15"); RwSetShapePath(fileName, rwREPLACE);
break;
case IDM_CHAP19:
strcpy(fileName,"\\l3d\\chap19\\dolphin"); RwSetShapePath(fileName, rwREPLACE);
strcpy(fileName,"\\l3d\\chap19\\face"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\include"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\misc"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\reflect"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\robot"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\share"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\triad"); RwSetShapePath(fileName, rwPOSTCONCAT);
strcpy(fileName,"\\l3d\\chap19\\tv"); RwSetShapePath(fileName, rwPOSTCONCAT);
break;
// ********************************************** amimate textures ******************************************
/* each animate cycle, a certain number of frames are skipped. The more frames that are skipped,
the faster the animation plays */
// increment the number of frames to skip per frame to speed the animation
case IDM_FASTER:
rfChangeAnimateSpeed(SelectedClump,1);
break;
// decrement the number of frames to skip per frame to slow the animation
case IDM_SLOWER:
rfChangeAnimateSpeed(SelectedClump,-1);
break;
/* Each timer cycle, the textureRate amount is added to an accumulator. Every overflow of the accumulator
causes the texture animation to go to its next frame */
// accelerate the texture frame rate by making the textureRate larger
case IDM_ACCELERATE:
textureRate += (float)0.1;
if(textureRate>=1.0) textureRate=(float)1.0;
break;
// decelerate the texture frame rate by making the textureRate smaller
case IDM_DECELERATE:
textureRate -= (float)0.1;
if(textureRate<=0.1) textureRate=(float)0.1;
break;
// ********************************************** modify raster ******************************************
// change a texture raster for either 8-bit or 16-bit display modes
case IDM_MODTEXRASTER:
if(DisplayDepth==16)
badret = rfModifyTextureRaster16(SelectedClump);
else
badret = rfModifyTextureRaster8(SelectedClump);
if(badret)
{
RenderScene(window);
}
break;
// change a backdrop raster for either 8-bit or 16-bit display modes
case IDM_MODBACKRASTER:
CurrentWindow = window;
if(DisplayDepth==16)
badret = rfModifyBackdropRaster16(Camera);
else
badret = rfModifyBackdropRaster8(Camera);
if(badret)
{
RwInvalidateCameraViewport(Camera);
RenderScene(window);
}
break;
// ********************************************** sprites ******************************************
//when set, a (.bmp) file is read onto a newly created sprite as opposed to the background raster
case MRF_READSPRITES:
if (rfReadSprite) { // turn it off
rfReadSprite = FALSE;
CheckMenuItem(GetMenu(window), MRF_READSPRITES, MF_BYCOMMAND | MF_UNCHECKED);
}
else { // turn it on
rfReadSprite = TRUE;
CheckMenuItem(GetMenu(window), MRF_READSPRITES, MF_BYCOMMAND | MF_CHECKED);
}
break;
// ********************************************** bird's eye view ******************************************
// when set, a sprite is created with all 256 colors present as 16 by 16 color boxes thereby showing the entire palette
case MRF_PALETTEVIEW:
if (!rfPaletteView) { // turn it on
rfPaletteView = TRUE;
RwSetClumpState(PaletteSprite, rwON);
CheckMenuItem(GetMenu(window), MRF_PALETTEVIEW, MF_BYCOMMAND | MF_CHECKED);
}
else { // turn it off
rfPaletteView = FALSE;
RwSetClumpState(PaletteSprite, rwOFF);
CheckMenuItem(GetMenu(window), MRF_PALETTEVIEW, MF_BYCOMMAND | MF_UNCHECKED);
}
RenderScene(window);
break;
// ********************************************** bird's eye view ******************************************
/* when on, a bird's eye sprite is created and onto the raster of this sprite is placed a second camera viewport */
case MRF_BIRDSEYE:
if (rfBirdsEye) { // turn it off
rfBirdsEye = FALSE;
CheckMenuItem(GetMenu(window), MRF_BIRDSEYE, MF_BYCOMMAND | MF_UNCHECKED);
}
else { // turn it on
rfBirdsEye = TRUE;
CheckMenuItem(GetMenu(window), MRF_BIRDSEYE, MF_BYCOMMAND | MF_CHECKED);
}
RenderScene(window);
break;
// ********************************************** regular rwView ******************************************
case IDM_FILE_OPEN:
/*
* Use a common dialog to get the name of the file to load.
* We intialize things with the directory and name of the last
* filename loaded.
*/
_splitpath(LastFileName, directory, dir, fileName, ext);
strcat(fileName, ext);
strcat(directory, dir);
len = strlen(directory);
if ((len > 0) && (directory[len - 1] == '\\'))
directory[len - 1] = '\0';
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = window;
ofn.lpstrFilter = "RW Object (*.rwx)\0*.rwx\0Backdrop (*.bmp)\0*.bmp\0Spline (*.rrc)\0*.rrc\0Palette (*.pal)\0*.pal\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile= fileName;
ofn.nMaxFile = sizeof(fileName);
ofn.lpstrInitialDir = directory;
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
/*
* Save the file name for next time.
*/
strcpy(LastFileName, fileName);
/*
* Use LoadObject() to load an object of the appropriate type from
* the given file. LoadObject() determines the object type to load
* from the extension of the file.
*/
if (LoadObject(window, fileName))
{
/*
* Update the MRU file list and menus.
*/
DeleteMRUFileMenuItems(window);
AddFileToMRUFileList(fileName);
AppendMRUFileMenuItems(window);
RenderScene(window);
}
}
break;
case IDM_FILE_SAVE:
/*
* Ensure there is a clump and its not the representation
* of a light (we don't save those).
*/
if ((SelectedClump != NULL) && (!ISCLUMPLIGHT(SelectedClump)))
{
/*
* Write out under the filename stored with the clump.
*/
oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
status = RwWriteShape(GETCLUMPFILENAME(SelectedClump), SelectedClump);
SetCursor(oldCursor);
if (!status)
{
sprintf(buffer, "Could not write the file %s",
GETCLUMPFILENAME(SelectedClump));
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
}
}
break;
case IDM_FILE_SAVEAS:
/*
* Ensure there is a clump and its not the representation
* of a light (we don't save those).
*/
if ((SelectedClump != NULL) && (!ISCLUMPLIGHT(SelectedClump)))
{
/*
* Use a common dialog to get the name of the file to save.
* We intialize things with the current filename of the clump
* to be saved.
*/
_splitpath(GETCLUMPFILENAME(SelectedClump), directory, dir, fileName, ext);
strcat(fileName, ext);
strcat(directory, dir);
len = strlen(directory);
if ((len > 0) && (directory[len - 1] == '\\'))
directory[len - 1] = '\0';
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = window;
ofn.lpstrFilter = "RW Object (*.rwx)\0*.rwx\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile= fileName;
ofn.nMaxFile = sizeof(fileName);
ofn.lpstrInitialDir = directory;
ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
if (GetSaveFileName(&ofn))
{
/*
* Write out under the new filename.
*/
oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
status = RwWriteShape(fileName, SelectedClump);
SetCursor(oldCursor);
if (!status)
{
sprintf(buffer, "Could not write the file %s",
fileName);
MessageBox(window, buffer, WINDOWTITLE,
MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION);
}
}
/*
* Update the clump's stored filename to reflect the new file it
* is stored int.
*/
strcpy(GETCLUMPFILENAME(SelectedClump), fileName);
}
break;
case IDM_FILE_EXIT:
/*
* Close the viewer.
*/
SendMessage(window, WM_CLOSE, 0, 0L);
break;
case IDM_FILE_MRUFILE:
case IDM_FILE_MRUFILE + 1:
case IDM_FILE_MRUFILE + 2:
case IDM_FILE_MRUFILE + 3:
if (LoadObject(window, MRUFiles[item - IDM_FILE_MRUFILE]))
RenderScene(window);
break;
case IDM_EDIT_DELETE:
/*
* Delete the picked clump (if there is one) but don't delete a sprite or spline.
*/
if( (GETOBJECTTYPE(SelectedClump)==rfIsClump) || (GETOBJECTTYPE(SelectedClump)==rfIsLight)
|| (GETOBJECTTYPE(SelectedClump)==rfNoMoveClump) || (GETOBJECTTYPE(SelectedClump)==rfIsSprite))
{
if (SelectedClump != NULL)
{
DestroyClumpObj(SelectedClump);
DeselectClump(window);
RenderScene(window);
}
}
break;
case IDM_SCENE_NEW:
/*
* Ensure the user really wishes to discard this scene and its
* contents.
*/
if (MessageBox(window, "Discard this 3D Scene?", WINDOWTITLE,
MB_YESNO | MB_APPLMODAL | MB_ICONQUESTION) == IDYES)
{
CreateNewScene(window);
}
break;
case IDM_SCENE_BACKGROUNDCOLOR:
case IDM_BACKGROUNDPOPUP_COLOR:
/*
* Change the background color of the world.
*/
dialogProc = MakeProcInstance(ColorDlgProc, AppInstance);
RwGetCameraBackColor(Camera, &color);
if (DialogBoxParam(AppInstance, MAKEINTRESOURCE(IDD_COLORPICKER),
window, dialogProc, (LPARAM)&color) == IDOK)
{
/*
* Change the background camera's background color and re-render.
*/
SettingsChanged = TRUE;
BackgroundColor = RGBToColorRef(&color);
RwSetCameraBackColorStruct(Camera, &color);
RwInvalidateCameraViewport(Camera);
RenderScene(window);
}
FreeProcInstance(dialogProc);
break;
case IDM_CAMERA_ELEVATIONVIEW:
case IDM_CAMERA_RESET:
/*
* Reset the camera's viewing position.
*/
ResetCamera(Camera);
RenderScene(window);
break;
case IDM_CAMERA_PLANVIEW:
/*
* Put the camera in plan view, i.e., looking down.
*/
RwSetCameraPosition(Camera, CREAL(0.0), DEFAULTCAMERADISTANCE, CREAL(0.0));
RwPointCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.0));
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(0.0), CREAL(-1.0));
RenderScene(window);
break;
case IDM_CAMERA_SIDEVIEW:
/*
* Put the camera in side view.
*/
RwSetCameraPosition(Camera, DEFAULTCAMERADISTANCE, CREAL(0.0), CREAL(0.0));
RwPointCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.0));
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RenderScene(window);
break;
case IDM_LIGHT_NEWDIRECTIONAL:
light = CreateLightObj(rwDIRECTIONAL);
if (light != NULL)
{
SetLightObjVisibleState(light, (ShowLights ? rwON : rwOFF));
AddLightObjToScene(Scene, light);
RenderScene(window);
}
else
{
MessageBox(window,
"Could not create the RenderWare light",
WINDOWTITLE, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
}
break;
case IDM_LIGHT_NEWPOINT:
light = CreateLightObj(rwPOINT);
if (light != NULL)
{
SetLightObjVisibleState(light, (ShowLights ? rwON : rwOFF));
AddLightObjToScene(Scene, light);
RenderScene(window);
}
else
{
MessageBox(window,
"Could not create the RenderWare light",
WINDOWTITLE, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
}
break;
case IDM_LIGHT_NEWCONICAL:
light = CreateLightObj(rwCONICAL);
if (light != NULL)
{
SetLightObjVisibleState(light, (ShowLights ? rwON : rwOFF));
AddLightObjToScene(Scene, light);
RenderScene(window);
}
else
{
MessageBox(window,
"Could not create the RenderWare light",
WINDOWTITLE, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
}
break;
case IDM_OPTIONS_SHOWLIGHTS:
if (ShowLights)
{
/*
* If the menu item is currently checked then lights are shown so turn them off and
* uncheck the menu.
*/
ShowLights = FALSE;
RwForAllLightsInSceneInt(Scene, (RwLightFuncInt)SetLightObjVisibleState, rwOFF);
CheckMenuItem(GetMenu(window), IDM_OPTIONS_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/*
* If the menu item is currently unchecked then lights are not shown so turn them on and
* check the menu.
*/
ShowLights = TRUE;
RwForAllLightsInSceneInt(Scene, (RwLightFuncInt)SetLightObjVisibleState, rwON);
CheckMenuItem(GetMenu(window), IDM_OPTIONS_SHOWLIGHTS, MF_BYCOMMAND | MF_CHECKED);
}
SettingsChanged = TRUE;
RenderScene(window);
break;
case IDM_OPTIONS_SHOWHIGHLIGHT:
if (ShowHighlight)
{
/*
* We are currently showing highlights. So turn the highlight off and
* uncheck the menu item.
*/
ShowHighlight = FALSE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_SHOWHIGHLIGHT, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/*
* We are currently not showing highlights. So turn the highlight on and
* check the menu item.
*/
ShowHighlight = TRUE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_SHOWHIGHLIGHT, MF_BYCOMMAND | MF_CHECKED);
}
SettingsChanged = TRUE;
RenderScene(window);
break;
case IDM_OPTIONS_PLAYMOVIES:
if (PlayMovies)
{
/*
* We are currently playing movies (multi-frame textures). So turn
* the playing off and uncheck the menu item.
*/
PlayMovies = FALSE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_PLAYMOVIES, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/*
* We currently are not playing movies (multi-frame textures). So turn
* the playing on and check the menu item.
*/
PlayMovies = TRUE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_PLAYMOVIES, MF_BYCOMMAND | MF_CHECKED);
}
SettingsChanged = TRUE;
break;
case IDM_OPTIONS_MOMENTUM:
if (Momentum)
{
/*
* We are currently have object momentum. So turn it off and uncheck
* the menu item.
*/
Momentum = FALSE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_MOMENTUM, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/*
* We are currently don't have object momentum. So turn it on and check
* the menu item.
*/
Momentum = TRUE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_MOMENTUM, MF_BYCOMMAND | MF_CHECKED);
}
SettingsChanged = TRUE;
break;
case IDM_OPTIONS_CENTERBACKDROP:
if (CenterBackdrop)
{
/*
* We are currently a centered backdrop. So turn it off and uncheck
* the menu item.
*/
CenterBackdrop = FALSE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_CENTERBACKDROP, MF_BYCOMMAND | MF_UNCHECKED);
}
else
{
/*
* We are currently don't have a centered backdrop. So turn it on and check
* the menu item.
*/
CenterBackdrop = TRUE;
CheckMenuItem(GetMenu(window), IDM_OPTIONS_CENTERBACKDROP, MF_BYCOMMAND | MF_CHECKED);
}
UpdateCameraBackdropPosition(Camera);
RenderScene(window);
SettingsChanged = TRUE;
break;
case IDM_OPTIONS_SEARCHPATH:
/* Display the search path box */
dialogProc = MakeProcInstance(SearchPathDlgProc, AppInstance);
DialogBox(AppInstance, MAKEINTRESOURCE(IDD_SEARCHPATH), window, dialogProc);
FreeProcInstance(dialogProc);
break;
case IDM_CLUMP_RESET:
case IDM_CLUMPPOPUP_RESET:
/*
* Reset the clump to its default position, orientation and scaling.
*/
RwPushScratchMatrix();
RwIdentityMatrix(RwScratchMatrix());
RwTransformClump(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwTransformClumpJoint(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
RenderScene(window);
break;
case IDM_CAMERA_MOVETO:
case IDM_LIGHTPOPUP_MOVETO:
case IDM_CLUMPPOPUP_MOVETO:
/*
* Alight the camera with the position and orientation of the given object.
*/
RwPushScratchMatrix();
RwGetClumpLTM(SelectedClump, RwScratchMatrix());
RwTransformCamera(Camera, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
RenderScene(window);
break;
case IDM_CAMERA_LOOKAT:
case IDM_LIGHTPOPUP_LOOKAT:
case IDM_CLUMPPOPUP_LOOKAT:
/*
* Make the camera look at the picked object.
*/
RwGetClumpOrigin(SelectedClump, &point);
RwPointCamera(Camera, point.x, point.y, point.z);
RenderScene(window);
break;
case IDM_EDIT_DUPLICATE:
case IDM_LIGHTPOPUP_DUPLICATE:
case IDM_CLUMPPOPUP_DUPLICATE:
/*
* Duplicate the selected object (which may be a clump
* or a light and the clump which represents it).
*/
oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
newClump = DuplicateClumpObj(SelectedClump);
SetCursor(oldCursor);
if (newClump != NULL)
{
/*
* Move the new clump slightly (an arbitrary amount) to
* the right and down (in camera space) so the new and
* old objects don't occupy the same space.
*/
RwGetCameraLookRight(Camera, &right);
right.x = RMul(CREAL(0.2), right.x);
right.y = RMul(CREAL(0.2), right.y);
right.z = RMul(CREAL(0.2), right.z);
RwGetCameraLookUp(Camera, &up);
up.x = RMul(CREAL(-0.2), up.x);
up.y = RMul(CREAL(-0.2), up.y);
up.z = RMul(CREAL(-0.2), up.z);
RwPushScratchMatrix();
RwTranslateMatrix(RwScratchMatrix(), right.x, right.y, right.z, rwREPLACE);
RwTranslateMatrix(RwScratchMatrix(), up.x, up.y, up.z, rwPOSTCONCAT);
RwTransformClump(newClump, RwScratchMatrix(), rwPOSTCONCAT);
if (ISCLUMPLIGHT(newClump))
{
light = GETCLUMPLIGHT(newClump);
SetLightObjVisibleState(light, (ShowLights ? rwON : rwOFF));
/*
* If the clump is the representation of a light reposition
* the light to match the new position of the clump.
*/
RwGetClumpLTM(newClump, RwScratchMatrix());
RwTransformLight(light, RwScratchMatrix(), rwREPLACE);
}
RwPopScratchMatrix();
RenderScene(window);
}
else
{
MessageBox(window,
"Could not duplicate the RenderWare object",
WINDOWTITLE, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
}
break;
case IDM_LIGHTPOPUP_DELETE:
case IDM_CLUMPPOPUP_DELETE:
/*
* Delete the picked clump. If the picked clump is the
* representation of a light, delete the associated
* light.
*/
DestroyClumpObj(SelectedClump);
DeselectClump(window);
RenderScene(window);
break;
case IDM_LIGHTPOPUP_PROPERTIES:
case IDM_LIGHT_PROPERTIES:
/*
* Display the light properties dialog.
*/
dialogProc = MakeProcInstance(LightPropsDlgProc, AppInstance);
if (DialogBoxParam(AppInstance, MAKEINTRESOURCE(IDD_LIGHTPROPS),
window, dialogProc, (LPARAM)GETCLUMPLIGHT(SelectedClump)) == IDOK)
RenderScene(window);
FreeProcInstance(dialogProc);
break;
case IDM_CLUMPPOPUP_PROPERTIES:
case IDM_CLUMP_PROPERTIES:
/*
* Display the clump properties dialog.
*/
dialogProc = MakeProcInstance(ClumpPropsDlgProc, AppInstance);
DialogBoxParam(AppInstance, MAKEINTRESOURCE(IDD_CLUMPPROPS),
window, dialogProc, (LPARAM)SelectedClump);
FreeProcInstance(dialogProc);
break;
case IDM_SCENE_BACKDROPDELETE:
case IDM_BACKGROUNDPOPUP_DELETE:
/*
* Delete the camera's backdrop (if there is one).
*/
if (RwGetCameraBackdrop(Camera) != NULL)
{
RwDestroyRaster(RwGetCameraBackdrop(Camera));
RwSetCameraBackdrop(Camera, NULL);
EnableMenuItem(GetMenu(window), IDM_SCENE_BACKDROPDELETE, MF_BYCOMMAND | MF_GRAYED);
BackdropFileName[0] = '\0';
SettingsChanged = TRUE;
RenderScene(window);
}
break;
case IDM_HELP_ABOUT:
/*
* Display the about box.
*/
dialogProc = MakeProcInstance(AboutBoxDlgProc, AppInstance);
DialogBox(AppInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), window, dialogProc);
FreeProcInstance(dialogProc);
break;
}
}
/**********************************************************************/
/*
* Handle MS Window's timer expiry. This function will perform any
* animation actions necessary, including spinning clumps and animating
* textures.
*/
static void
OnTimer(HWND window)
{
BOOL render = FALSE;
RwPolygon3d *myPoly;
RwMaterial *myMaterial=RwCreateMaterial();
RwInt32 rate;
/* ********************************************** surface animation ************************************* */
// If surface is on, then change the surface of the selected clump
if(rfSurf.Ambient) { // update the ambient reflection coefficient
RwForAllPolygonsInClumpReal(SelectedClump, RwSetPolygonAmbient, rfSurf.vAmbient);
rfSurf.vAmbient += rfSurf.AmbientInc; if(rfSurf.vAmbient>=CREAL(1.0)) rfSurf.vAmbient=CREAL(0.0);
render = TRUE;
}
if(rfSurf.Diffuse) { // update the diffuse reflection coefficient
RwForAllPolygonsInClumpReal(SelectedClump, RwSetPolygonDiffuse, rfSurf.vDiffuse);
rfSurf.vDiffuse += rfSurf.DiffuseInc; if(rfSurf.vDiffuse>=CREAL(1.0)) rfSurf.vDiffuse=CREAL(0.0);
render = TRUE;
}
if(rfSurf.Specular) { // update the specular reflection coefficient
RwForAllPolygonsInClumpReal(SelectedClump, RwSetPolygonSpecular, rfSurf.vSpecular);
rfSurf.vSpecular += rfSurf.SpecularInc; if(rfSurf.vSpecular>=CREAL(1.0)) rfSurf.vSpecular=CREAL(0.0);
render = TRUE;
}
if(rfSurf.MatAnimate) { // update the ambient reflection coefficient of the tagged polygon of the selected clump
myPoly = RwFindTaggedPolygon(SelectedClump,WINDOWTAG);
myMaterial = RwGetPolygonMaterial(myPoly);
if(myPoly!=NULL) {
RwSetMaterialAmbient(myMaterial,rfSurf.vAmbient);
rfSurf.vAmbient += rfSurf.AmbientInc; if(rfSurf.vAmbient>=CREAL(1.0)) rfSurf.vAmbient=CREAL(0.0);
render = TRUE;
}
}
// if an object is traveling the spline then update its location
if(TravelSpline) {
coaster->t = RAdd(coaster->t,coaster->tDelta); // advance to next spline locatin
PositionObjectOnSpline(coaster,SelectedClump);
render = TRUE;
}
/*
* Determine if there is a clump to spin (we also disable the spin
* if the mouse is being dragged).
*/
if (Momentum && SpinClump && (MouseMoveMode == mmNoAction))
{
/*
* Spin the last clump picked by the last computed spin matrix.
*/
RwTransformClumpJoint(SelectedClump, SpinMatrix, rwPOSTCONCAT);
render = TRUE;
if ((FrameNumber++ & 0x7f) == 0)
{
/*
* Every 128 frames (a somewhat arbitrary frequency) we call
* RwOrthoNormalizeMatrix() on the clump's joint matrix to
* correct any errors which may have crept into it during
* successive matrix concatenations. This is necessary due
* to the inevitable accuracy limitations of fixed-point
* numbers. It is unlikely that this action will be necessary
* in your own applications unless you perform a very large
* number of incremental rotation matrix concatenations (as
* is done here). If this is the case with your application,
* periodic use of RwOrthoNormalizeMatrix() will ensure
* that these rounding errors will be eliminated.
*
* We call RwOrthoNormalizeMatrix() in the floating-point
* version of RwView as well, as it is not a particularly
* expensive operation and the same problems of rounding
* errors in matrices can occur when using floating-point.
* Although they are more uncommon.
*/
RwPushScratchMatrix();
RwGetClumpJointMatrix(SelectedClump, RwScratchMatrix());
RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
RwTransformClumpJoint(SelectedClump, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
}
}
// if texture animation is enabled then
if (PlayMovies)
{
rate = (int) accumulatedRate; // new rate is the integer porition of the accumulated rate
accumulatedRate += textureRate; // add the texture rate increment to the accumulated rate
if((int) accumulatedRate > rate) // only upgrade when integer overflow occurs
{
RwForAllNamedTextures(RwTextureNextFrame); // do for all named textures
render = TRUE;
}
}
if (render)
{
/*
* Re-render the scene if necessary.
*/
RenderScene(window);
}
}
/**********************************************************************/
/*
* The window procedure for this application's window.
*/
LRESULT CALLBACK
MainWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
POINT point;
#if defined(WIN32)
POINTS points;
#endif
switch (message)
{
case WM_CREATE:
/*
* Create the pop-up menus.
*/
if (!CreatePopupMenus())
return -1L;
/*
* Ensure the menu items are in the correct state.
*/
EnableMenuItem(GetMenu(window), IDM_SCENE_BACKDROPDELETE,
MF_BYCOMMAND | (RwGetCameraBackdrop(Camera) != NULL ? MF_ENABLED : MF_GRAYED));
CheckMenuItem(GetMenu(window), IDM_OPTIONS_SHOWHIGHLIGHT,
MF_BYCOMMAND | (ShowHighlight ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(GetMenu(window), IDM_OPTIONS_SHOWLIGHTS,
MF_BYCOMMAND | (ShowLights ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(GetMenu(window), IDM_OPTIONS_PLAYMOVIES,
MF_BYCOMMAND | (PlayMovies ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(GetMenu(window), IDM_OPTIONS_MOMENTUM,
MF_BYCOMMAND | (Momentum ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(GetMenu(window), IDM_OPTIONS_CENTERBACKDROP,
MF_BYCOMMAND | (CenterBackdrop ? MF_CHECKED : MF_UNCHECKED));
AppendMRUFileMenuItems(window);
/*
* There is not initially selected clump.
*/
DeselectClump(window);
/*
* Clumps are loaded into the scene by drag and drop.
* So make this window a drop site.
*/
DragAcceptFiles(window, TRUE);
/*
* In this application, 3D animation is driven by window's
* timer messages, so turn a timer on.
*/
SetTimer(window, 1, 20, NULL);
// *********************************** initialize the animating materials variables ************************
rfSurf.vAmbient = CREAL(0.0); rfSurf.vDiffuse=CREAL(0.0); rfSurf.vSpecular=CREAL(0.0);
rfSurf.AmbientInc = CREAL(0.01); rfSurf.DiffuseInc=CREAL(0.01); rfSurf.SpecularInc=CREAL(0.01);
rfReadSprite=FALSE; // use BMP as backdrop not sprites
rfBirdsEye=FALSE; // don't display bird's eye sprite
rfPaletteView=FALSE; // don't display palette sprite
RwSetClumpState(PaletteSprite, rwOFF); // start with off
rfSurf.Ambient=FALSE; // don't animate ambient
rfSurf.Diffuse=FALSE; // don't diffuse ambient
rfSurf.Specular=FALSE; // don't specular ambient
rfSurf.MatAnimate=FALSE; // don't animate ambient of tagged polygon
// *********************************************** initialize debugging ***************************************
rfDebug.Severity=rwWARNING;
rfDebug.Message=rwDISABLE;
rfDebug.Assertion=rwENABLE;
rfDebug.Script=rwDISABLE;
rfDebug.Output=rwENABLE;
rfDebug.Trace=rwENABLE;
// *********************************************** initialize the transformations *******************************
// rotation about the Y axis in 15 degrees repreating 10 times according to the world coordiante system
rfScale.x=CREAL(1.0); rfScale.y=CREAL(1.0); rfScale.z=CREAL(1.0); rfScale.combine=rwPOSTCONCAT;
// rotation about the Y axis in 15 degrees repreating 10 times according to the world coordiante system
rfTran.x=CREAL(0.0); rfTran.y=CREAL(0.0); rfTran.z=CREAL(0.0); rfTran.combine=rwPOSTCONCAT;
// rotation about the Y axis in 15 degrees repreating 10 times according to the world coordiante system
rfRot.x=CREAL(0.0); rfRot.y=CREAL(1.0); rfRot.z=CREAL(0.0); rfRot.val=15; rfRot.repeat=10; rfRot.combine=rwPOSTCONCAT;
// pan, revolve and tilt is set to move in 15 degree increments repeating 10 times
rfLoc.val=15; rfLoc.repeat=10;
// camera is set to move in 0.2 increments repeating 10 times
rfCam.val=CREAL(0.2); rfCam.repeat=10;
// figure out the display depth
DisplayDepth = Is8or16bpp(window);
//************************************************ Spline **********************************************************
HideSpline = FALSE;
CheckMenuItem(GetMenu(window), IDM_HIDESPLINETRACK, MF_BYCOMMAND | MF_UNCHECKED);
HideControlPoints = FALSE;
CheckMenuItem(GetMenu(window), IDM_HIDESPLINECONTROLPOINTS, MF_BYCOMMAND | MF_UNCHECKED);
UseSmoothEnd = FALSE;
CheckMenuItem(GetMenu(window), IDM_SMOOTHEND, MF_BYCOMMAND | MF_UNCHECKED);
TravelSpline = FALSE;
CheckMenuItem(GetMenu(window), IDM_MOVEOBJECTONSPLINE, MF_BYCOMMAND | MF_UNCHECKED);
return 0L;
#if defined(CONSTRAIN_SIZE)
case WM_GETMINMAXINFO:
#if defined(__WINDOWS_386__)
/*
* The MK_FP32() is necessary under Watcom to convert
* an Windows 16 bit far pointer to a 32 bit far pointer.
*/
OnGetMinMaxInfo((MINMAXINFO FAR *)MK_FP32((void*)lParam));
#else
OnGetMinMaxInfo((MINMAXINFO FAR *)lParam);
#endif
return 0L;
#endif
case WM_SIZE:
if (RwIsOpen)
OnSize(window, LOWORD(lParam), HIWORD(lParam));
return 0L;
case WM_MEASUREITEM:
#if defined(__WINDOWS_386__)
/*
* The MK_FP32() is necessary under Watcom to convert
* an Windows 16 bit far pointer to a 32 bit far pointer.
*/
OnMeasureItem(window, (MEASUREITEMSTRUCT FAR *)MK_FP32((void*)lParam));
#else
OnMeasureItem(window, (MEASUREITEMSTRUCT FAR *)lParam);
#endif
return 0L;
case WM_DRAWITEM:
#if defined(__WINDOWS_386__)
/*
* The MK_FP32() is necessary under Watcom to convert
* an Windows 16 bit far pointer to a 32 bit far pointer.
*/
OnDrawItem(window, (DRAWITEMSTRUCT FAR *)MK_FP32((void*)lParam));
#else
OnDrawItem(window, (DRAWITEMSTRUCT FAR *)lParam);
#endif
return 0L;
case WM_DROPFILES:
if (RwIsOpen)
{
/*
* Turn the timer off for the duration of the drop
*/
KillTimer(window, 1);
OnDrop(window, (HDROP)wParam);
/*
* Turn the timer back on to start the animations back
* up.
*/
SetTimer(window, 1, 20, NULL);
}
return 0L;
case WM_LBUTTONDOWN:
if (RwIsOpen)
{
#if defined(WIN32)
points = MAKEPOINTS(lParam);
POINTSTOPOINT(point, points);
#else
point = MAKEPOINT(lParam);
#endif
OnLButtonDown(window, &point, wParam);
}
return 0L;
case WM_RBUTTONDOWN:
if (RwIsOpen)
{
#if defined(WIN32)
points = MAKEPOINTS(lParam);
POINTSTOPOINT(point, points);
#else
point = MAKEPOINT(lParam);
#endif
OnRButtonDown(window, &point, wParam);
}
return 0L;
case WM_MOUSEMOVE:
if (RwIsOpen)
{
if (MouseMoveMode != mmNoAction)
{
#if defined(WIN32)
points = MAKEPOINTS(lParam);
POINTSTOPOINT(point, points);
#else
point = MAKEPOINT(lParam);
#endif
OnMouseMove(window, &point);
}
}
return 0L;
case WM_LBUTTONUP:
if (RwIsOpen)
OnLButtonUp();
return 0L;
case WM_RBUTTONUP:
if (RwIsOpen)
OnRButtonUp();
return 0L;
case WM_PAINT:
if (RwIsOpen)
OnPaint(window);
return 0L;
case WM_COMMAND:
if (RwIsOpen)
{
#ifdef WIN32
HWND hwndCtl = (HWND) lParam;
WORD wID = LOWORD(wParam);
WORD wNotifyCode = HIWORD(wParam);
#else
HWND hwndCtl = (HWND) LOWORD(lParam);
WORD wID = wParam;
WORD wNotifyCode = HIWORD(lParam);
#endif
/*
* Turn the timer off for the duration of the command
* action.
*/
KillTimer(window, 1);
if (hwndCtl == (HWND)0)
OnMenu(window, wID);
/*
* Turn the timer back on to start the animations back
* up.
*/
SetTimer(window, 1, 20, NULL);
}
return 0L;
case WM_TIMER:
if (RwIsOpen)
OnTimer(window);
return 0L;
case WM_CLOSE:
/*
* If the settings have changed then ask the user if she or he
* wishes to save them.
*/
if (SettingsChanged)
{
if (MessageBox(window, "Save the new 3D Object Viewer settings?",
WINDOWTITLE, MB_YESNO | MB_APPLMODAL | MB_ICONQUESTION) == IDYES)
WriteSettings(TRUE);
else
WriteSettings(FALSE);
}
else
{
WriteSettings(FALSE);
}
DestroyWindow(window);
return 0L;
case WM_DESTROY:
/*
* The window is going away so it is no longer a drop site.
*/
DragAcceptFiles(window, FALSE);
/*
* Turn the timer off.
*/
KillTimer(window, 1);
/*
* Destroy the pop-up menus.
*/
DestroyPopupMenus();
/*
* Quit message handling.
*/
PostQuitMessage(0);
return 0L;
}
/*
* Let Windows handle all other messages.
*/
return DefWindowProc(window, message, wParam, lParam);
}
/**********************************************************************/
/*
* Windows application entry point.
*/
int PASCAL
WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow)
{
MSG msg;
HWND window;
HACCEL accel;
/*
* Cache the instance handle in a global variable for later use.
*/
AppInstance = instance;
if (prevInstance)
{
/*
* Only allow one viewer application to run at any one time.
*/
MessageBox(NULL,
"The RenderWare 3D Object Viewer is already running."
"Only a single 3D Object Viewer can run at any one time",
WINDOWTITLE, MB_OK | MB_APPLMODAL | MB_ICONSTOP);
return FALSE;
}
/*
* Register the window class.
*/
if (!InitApplication(instance))
return FALSE;
/*
* Read the initial settings from the initialization file.
*/
ReadSettings();
/*
* Create the window.
*/
window = InitInstance(instance);
if (window == NULL)
return FALSE;
/*
* Initialize the 3D (RenderWare) components of the app.
*/
if (!Init3D(window))
{
DestroyWindow(window);
return FALSE;
}
/*
* Parse any command line parameters.
*/
if (!ReadFromCommandLine(window, cmdLine))
{
TidyUp3D();
DestroyWindow(window);
return FALSE;
}
/*
* Show the window, and refresh it.
*/
ShowWindow(window, cmdShow);
UpdateWindow(window);
/*
* Load the accelerators.
*/
accel = LoadAccelerators(AppInstance, MAKEINTRESOURCE(IDR_ACCELERATOR));
/*
* Enter the message processing loop.
*/
while (GetMessage(&msg, NULL, 0U, 0U))
{
if (!TranslateAccelerator(window, accel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/*
* Tidy up the 3D (RenderWare) components of the application.
*/
TidyUp3D();
return msg.wParam;
}