📄 boidswin.cpp
字号:
/* Filename: BoidsWin.cpp
Author: Robert Platt
Creation date: 15/06/1999
Modified: 13/05/2000
Version: 0.54
Description: Implementation file for the boids main window class.
*/
#include "BoidsWin.h"
// Windows message map.
BEGIN_MESSAGE_MAP( BoidsWin, CFrameWnd )
ON_WM_CREATE( )
ON_WM_PAINT( )
ON_WM_HSCROLL( )
ON_BN_CLICKED( 1, OnCentre )
ON_BN_CLICKED( 2, OnStartStop )
ON_WM_NCLBUTTONDOWN( )
ON_WM_NCRBUTTONDOWN( )
ON_WM_SIZE( )
ON_WM_CLOSE( )
ON_WM_DESTROY( )
// Window's Menu Items.
// Found in 'BoidsWinMenu.cpp'.
ON_COMMAND( IDM_LOAD, OnLoad )
ON_COMMAND( IDM_SAVE, OnSave )
ON_COMMAND( IDM_START_STOP, OnStartStop )
ON_COMMAND( IDM_EXIT, OnExit )
ON_COMMAND( IDM_CAMERA_ABOVE, OnCameraAbove )
ON_COMMAND( IDM_CAMERA_BOID, OnCameraBoid )
ON_COMMAND( IDM_CAMERA_NORTH, OnCameraNorth )
ON_COMMAND( IDM_CAMERA_EAST, OnCameraEast )
ON_COMMAND( IDM_CAMERA_SOUTH, OnCameraSouth )
ON_COMMAND( IDM_CAMERA_WEST, OnCameraWest )
ON_UPDATE_COMMAND_UI( IDM_CAMERA_ABOVE, OnUpdateCameraAbove )
ON_UPDATE_COMMAND_UI( IDM_CAMERA_BOID, OnUpdateCameraBoid )
ON_UPDATE_COMMAND_UI( IDM_CAMERA_NORTH, OnUpdateCameraNorth )
ON_UPDATE_COMMAND_UI( IDM_CAMERA_EAST, OnUpdateCameraEast )
ON_UPDATE_COMMAND_UI( IDM_CAMERA_SOUTH, OnUpdateCameraSouth )
ON_UPDATE_COMMAND_UI( IDM_CAMERA_WEST, OnUpdateCameraWest )
ON_COMMAND( IDM_CAMERA_UP, OnIncCameraPos )
ON_COMMAND( IDM_CAMERA_DOWN, OnDecCameraPos )
ON_COMMAND( IDM_CAMERA_RIGHT, OnIncCameraRot )
ON_COMMAND( IDM_CAMERA_LEFT, OnDecCameraRot )
ON_COMMAND( IDM_CAMERA_CENTRE, OnCentre )
ON_COMMAND( IDM_WIREFRAME, OnWireFrame )
ON_COMMAND( IDM_UNLITFLAT, OnUnlitFlat )
ON_COMMAND( IDM_FLAT, OnFlat )
ON_COMMAND( IDM_GOURAUD, OnGouraud )
ON_COMMAND( IDM_ADD_FLYER, OnAddFlyer )
ON_COMMAND( IDM_REMOVE_FLYER, OnRemoveFlyer )
ON_COMMAND( IDM_INC_FLYER_SIZE, OnIncFlyerSize )
ON_COMMAND( IDM_DEC_FLYER_SIZE, OnDecFlyerSize )
ON_COMMAND( IDM_TETRA, OnTetra )
ON_COMMAND( IDM_SMALL_BIRD, OnBird )
ON_COMMAND( IDM_ANIM_BIRD, OnAnimBird )
ON_COMMAND( IDM_FLYER_WHITE, OnFlyerWhite )
ON_COMMAND( IDM_FLYER_YELLOW, OnFlyerYellow )
ON_COMMAND( IDM_FLYER_PINK, OnFlyerPink )
ON_UPDATE_COMMAND_UI( IDM_WIREFRAME, OnUpdateWireframe )
ON_UPDATE_COMMAND_UI( IDM_UNLITFLAT, OnUpdateUnlitFlat )
ON_UPDATE_COMMAND_UI( IDM_FLAT, OnUpdateFlat )
ON_UPDATE_COMMAND_UI( IDM_GOURAUD, OnUpdateGouraud )
ON_UPDATE_COMMAND_UI( IDM_TETRA, OnUpdateTetra )
ON_UPDATE_COMMAND_UI( IDM_SMALL_BIRD, OnUpdateBird )
ON_UPDATE_COMMAND_UI( IDM_ANIM_BIRD, OnUpdateAnimBird )
ON_UPDATE_COMMAND_UI( IDM_FLYER_WHITE, OnUpdateFlyerWhite )
ON_UPDATE_COMMAND_UI( IDM_FLYER_YELLOW, OnUpdateFlyerYellow )
ON_UPDATE_COMMAND_UI( IDM_FLYER_PINK, OnUpdateFlyerPink )
ON_COMMAND( IDM_LAND_NONE, OnLandNone )
ON_COMMAND( IDM_LAND_WIREFRAME, OnLandWireframe )
ON_COMMAND( IDM_LAND_UNLITFLAT, OnLandUnlitFlat )
ON_COMMAND( IDM_LAND_FLAT, OnLandFlat )
ON_COMMAND( IDM_LAND_GOURAUD, OnLandGouraud )
ON_COMMAND( IDM_SOLID_COLOUR_GREEN, OnLandSolidGreen )
ON_COMMAND( IDM_SOLID_COLOUR_CHECKERED, OnLandSolidCheckered )
ON_COMMAND( IDM_LAND_RECALCULATE, OnLandRecalculate )
ON_UPDATE_COMMAND_UI( IDM_LAND_NONE, OnUpdateLandNone )
ON_UPDATE_COMMAND_UI( IDM_LAND_WIREFRAME, OnUpdateLandWireFrame )
ON_UPDATE_COMMAND_UI( IDM_LAND_UNLITFLAT, OnUpdateLandUnlitFlat )
ON_UPDATE_COMMAND_UI( IDM_LAND_FLAT, OnUpdateLandFlat )
ON_UPDATE_COMMAND_UI( IDM_LAND_GOURAUD, OnUpdateLandGouraud )
ON_UPDATE_COMMAND_UI( IDM_SOLID_COLOUR_GREEN, OnUpdateLandSolidGreen )
ON_UPDATE_COMMAND_UI( IDM_SOLID_COLOUR_CHECKERED,
OnUpdateLandSolidCheckered )
ON_COMMAND( IDM_FLOCKFORMING, OnFlockForming )
ON_COMMAND( IDM_VELOCITYMATCHING, OnVelocityMatching )
ON_COMMAND( IDM_COLLISIONAVOIDANCE, OnCollisionAvoidance )
ON_COMMAND( IDM_FLYER_ATTRIBUTES, OnFlyerAttributes )
ON_UPDATE_COMMAND_UI( IDM_FLOCKFORMING, OnUpdateFlockForming )
ON_UPDATE_COMMAND_UI( IDM_VELOCITYMATCHING, OnUpdateVelocityMatching )
ON_UPDATE_COMMAND_UI( IDM_COLLISIONAVOIDANCE, OnUpdateCollisionAvoidance )
ON_COMMAND( IDM_SWITCH_FS_MODE, OnSwitchFSMode )
ON_COMMAND( IDM_SELECT_MODE, OnSelectMode )
ON_COMMAND( IDM_WIN_640_480, OnWin640_480 )
ON_COMMAND( IDM_WIN_800_600, OnWin800_600 )
ON_COMMAND( IDM_WIN_1024_768, OnWin1024_768 )
ON_COMMAND( IDM_TOGGLE_CONTROL_PANEL, OnToggleControls )
ON_UPDATE_COMMAND_UI( IDM_TOGGLE_CONTROL_PANEL, OnUpdateToggleControls )
ON_COMMAND( IDM_ABOUT, OnAbout )
ON_COMMAND( IDK_ESC_KEY, OnEscKey )
END_MESSAGE_MAP( )
// Constructor for Window class.
BoidsWin::BoidsWin( )
{
// Create the D3DRM interface.
Direct3DRMCreate( &d3drm );
// Initialise the D3D interface pointers as being initially unused.
device = NULL;
scene = NULL;
clipper = NULL;
frontSurface = NULL; // Used for full screen mode.
zBuffer = NULL;
directDraw = NULL;
numFlyers = INITIAL_NUM_FLYERS; // Various initialisations.
requiredFlyers = numFlyers;
renderStyle = DEFAULT_RENDER_STYLE;
flyerMesh = DEFAULT_FLYER_MESH;
flyerColour = RGB_WHITE;
frameCount = 0; // Reset the frame counter to start at zero.
overloaded = false; // The simulation is not overloaded to start with.
flockFormingActive = true; // Activate the behaviour flags.
velocityMatchingActive = true;
collisionAvoidanceActive = true;
cameraView = CAM_ABOVE; // Initialise the camera view.
cameraOnBoid = false;
threadEnabled = false; // Initialise the multitasking flags.
threadFinished = true;
appIdle = false;
needShutdown = false;
needToggleControls = false;
needFullScreen = false;
fullScreenMode = FULLSCREEN_STARTUP; // Windowed & Full Screen modes.
showControlPanel = CONTROL_PANEL_ON_STARTUP;
windowedModePos.length = 0; // Used to indicate as being uninitialised.
resolutionFS.widthPixels = FULLSCREEN_WIDTH; // Set default FS mode.
resolutionFS.heightPixels = FULLSCREEN_HEIGHT;
resolutionFS.colourDepthBits = FULLSCREEN_COLOUR_DEPTH;
stopped = false;
runTime = 0;
stopTime = 0;
frameStartTime = clock( );
// Flyer attributes dialog settings.
accelerationRate = ACCELERATION_RATE;
angleOfVision = ANGLE_OF_VISION;
collisionDistance = COLLISION_DISTANCE;
flockFormingDistance = FLOCK_FORMING_DISTANCE;
flockingRadius = FLOCKING_RADIUS;
maximumSpeed = MAXIMUM_SPEED;
minimumSpeed = MINIMUM_SPEED;
rangeOfFlockHeadings = RANGE_OF_FLOCK_HEADINGS;
wingStrokesPerSecond = WING_STROKES_PER_SECOND;
}
// OnCreate is called after the window is created but before it is visible.
afx_msg void BoidsWin::OnCreate( )
{
// Record the initial window size.
GetClientRect( &prevWindowSize );
DWORD visible = NULL; // Flag for making the components visible.
if ( showControlPanel )
{
visible = WS_VISIBLE; // Set the flag to show the components.
}
// Set up the controls for the window.
CRect position;
GetClientRect( &position );
position.left = position.right - CONTROL_PANEL_SIZE;
// Create and draw the contols from the bottom up.
// border5 to place some spacing in the controls.
position.top = 400;
border5.Create( "", WS_CHILD | visible | SS_CENTER, position, this, 12 );
// btnStop CButton control as a push button to stop the simulation.
position.top = 370;
position.bottom = 400;
btnStop.Create( "Stop", WS_TABSTOP | WS_CHILD | BS_DEFPUSHBUTTON |
visible, position, this, 2 );
// staticTime for the simulation time.
position.top = 350;
position.bottom = 370;
staticTime.Create( "Time: ", WS_CHILD | visible | SS_CENTER,
position, this, 11 );
// staticFrames for the frames per second.
position.top = 330;
position.bottom = 350;
staticFrames.Create( "Frames per Second: ", WS_CHILD | visible |
SS_CENTER, position, this, 10 );
// border4 to place some spacing in the controls.
position.top = 310;
position.bottom = 330;
border4.Create( "", WS_CHILD | visible | SS_CENTER, position, this, 9 );
// btnCentre CButton control as a push button to reset the camera angle.
position.top = 280;
position.bottom = 310;
btnCentre.Create( "Centre Angle", WS_TABSTOP | WS_CHILD |
BS_DEFPUSHBUTTON | visible, position, this, 1 );
// sliderCam2 for the camera position.
position.top = 250;
position.bottom = 280;
sliderCam2.Create( visible | TBS_ENABLESELRANGE, position, this, 4 );
sliderCam2.SetRange( 0, 359 );
sliderCam2.SetPos( 180 );
// staticCam2 for the camera position.
position.top = 230;
position.bottom = 250;
staticCam2.Create( "Camera Rotation", WS_CHILD | visible |
SS_CENTER, position, this, 8 );
// border3 to place some spacing in the controls.
position.top = 210;
position.bottom = 230;
border3.Create( "", WS_CHILD | visible | SS_CENTER, position, this, 7 );
// sliderCam for the camera position.
position.top = 180;
position.bottom = 210;
sliderCam.Create( visible | TBS_ENABLESELRANGE, position, this, 3 );
sliderCam.SetRange( 0, 1000 );
sliderCam.SetPos( 0 );
// staticCam for the camera position.
position.top = 160;
position.bottom = 180;
staticCam.Create( "Camera Position", WS_CHILD | visible |
SS_CENTER, position, this, 6 );
// border2 to place some spacing in the controls.
position.top = 140;
position.bottom = 160;
border2.Create( "", WS_CHILD | visible | SS_CENTER, position, this, 5 );
// sliderSize for the size of the flyers.
position.top = 110;
position.bottom = 140;
sliderSize.Create( visible | TBS_ENABLESELRANGE, position, this, 2 );
/* NOTE: The size of the boid is calculated by dividing the slider position
by the scale factor. Therefore to prevent the size from becoming zero
the minimum value of the range should be the scale factor. Then the
size of the boid will always be >= 1. */
sliderSize.SetRange( SIZE_SCALE_FACTOR, 200 );
sliderSize.SetPos( INITIAL_SIZE_SLIDER_POSITION );
// staticSize for the size of the flyers.
position.top = 90;
position.bottom = 110;
staticSize.Create( "Flyer Size", WS_CHILD | visible |
SS_CENTER, position, this, 4 );
// border1 to place some spacing in the controls.
position.top = 70;
position.bottom = 90;
border1.Create( "", WS_CHILD | visible | SS_CENTER, position, this, 3 );
// sliderNum for the number of flyers.
position.top = 40;
position.bottom = 70;
sliderNum.Create( visible | TBS_ENABLESELRANGE, position, this, 1 );
sliderNum.SetRange( 0, MAXIMUM_NUM_FLYERS );
sliderNum.SetPos( numFlyers );
// staticNum for the number of Flyers.
position.top = 20;
position.bottom = 40;
// Set the text of the static control to show the starting number.
CString numberObjText( "Number of Flyers: " );
char buffer[ 50 ]; // Temporary buffer for string conversion.
numberObjText += _itoa( numFlyers, buffer, 10 );
staticNum.Create( numberObjText, WS_CHILD | visible |
SS_CENTER, position, this, 2 );
// topBorder static control.
position.top = 0;
position.bottom = 20;
topBorder.Create( "", WS_CHILD | visible | SS_CENTER, position, this, 1 );
// Used for starting up the application in full screen mode.
// To do this, just set the flag contants.
if ( fullScreenMode == true )
{
// Disable the menu and the window's normal features.
CMenu *mnu;
mnu = GetMenu( );
mnu -> DestroyMenu( );
SetMenu( mnu );
mnu -> Detach( );
ModifyStyle( WS_OVERLAPPEDWINDOW, WS_POPUP, 0 );
ShowCursor( false ); // Hide the mouse pointer.
// Create the direct draw interface.
DirectDrawCreate( 0, &directDraw, 0 );
directDraw -> SetCooperativeLevel( GetSafeHwnd( ),
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT );
directDraw -> SetDisplayMode( resolutionFS.widthPixels,
resolutionFS.heightPixels, resolutionFS.colourDepthBits );
createFSDevice( );
}
// NOTE: The windowed mode device is automatically called -
// - by the window by virtue of the MFC 'OnPaint' function.
}
// Create the full screen direct draw device for Direct3D to display with.
void BoidsWin::createFSDevice( )
{
// Hide the control panel if it is showing.
if ( showControlPanel == true )
{
showControls( false );
}
// Release the previous surfaces if any.
// The back buffer is attached to the front buffer here.
if ( frontSurface )
{
frontSurface -> Release( );
frontSurface = NULL;
}
if ( zBuffer )
{
zBuffer -> Release( );
zBuffer = NULL;
}
// Create a front surface with a single back buffer.
DDSURFACEDESC surfaceDesc;
memset( &surfaceDesc, 0, sizeof( surfaceDesc ) );
surfaceDesc.dwSize = sizeof( surfaceDesc );
surfaceDesc.dwFlags = DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
surfaceDesc.dwBackBufferCount = 1;
surfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_3DDEVICE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
directDraw -> CreateSurface( &surfaceDesc, &frontSurface, 0 );
// Get an interface to the back buffer surface.
DDSCAPS capabilities;
capabilities.dwCaps = DDSCAPS_BACKBUFFER;
frontSurface -> GetAttachedSurface( &capabilities , &backSurface );
// Create a Z buffer surface and attach it to the back surface.
memset( &surfaceDesc, 0, sizeof( surfaceDesc ) );
surfaceDesc.dwSize = sizeof( DDSURFACEDESC );
surfaceDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT |
DDSD_CAPS | DDSD_ZBUFFERBITDEPTH;
surfaceDesc.dwWidth = resolutionFS.widthPixels;
surfaceDesc.dwHeight = resolutionFS.heightPixels;
surfaceDesc.dwZBufferBitDepth = FULLSCREEN_ZBUFFER_DEPTH;
surfaceDesc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_SYSTEMMEMORY;
directDraw -> CreateSurface( &surfaceDesc, &zBuffer, 0 );
backSurface -> AddAttachedSurface( zBuffer );
// Create a D3DRM device and attach it to the back surface.
d3drm -> CreateDeviceFromSurface( 0, directDraw, backSurface, &device );
// If the scene is not constructed, set the device to -
// - default render quality and create the scene.
if ( !scene )
{
// Initial render style.
device -> SetQuality( DEFAULT_RENDER_STYLE );
createScene( ); // Set up all the simulation's graphics.
}
else
{
// The scene has already been created, -
// - just reconfigure the device and viewport.
device -> SetQuality( renderStyle ); // Restore the render style.
// Create the viewport.
d3drm -> CreateViewport( device, camera, 0, 0,
device -> GetWidth( ), device -> GetHeight( ), &viewPort );
// Set the range of vision, default is 100.
viewPort -> SetBack( D3DVALUE( VIEWPORT_BACK_DISTANCE ) );
}
}
// Render the next frame and perform a page flip when in full screen mode.
void BoidsWin::renderFullScreen( )
{
// Restore the front surface if it has been lost.
if ( frontSurface -> IsLost( ) == DDERR_SURFACELOST )
{
frontSurface -> Restore( );
}
// Paint the next frame onto to back buffer with the D3DRM device.
scene -> Move( D3DVALUE( 1.0 ) );
viewPort -> Clear( );
viewPort -> Render( scene );
viewPort -> ForceUpdate( 0, 0, resolutionFS.widthPixels - 1,
resolutionFS.heightPixels - 1 );
device -> Update( );
// Perform a page flip.
frontSurface -> Flip( 0, DDFLIP_WAIT );
}
// Create the windowed direct draw device for Direct3D to display with.
void BoidsWin::createWinDevice( )
{
// Create the Direct Draw clipper
DirectDrawCreateClipper( 0, &clipper, NULL );
clipper -> SetHWnd( 0, m_hWnd );
// Create the D3DRM drawing device.
CRect size;
GetClientRect( &size );
if ( showControlPanel ) // Make space for the control panel.
{
size.right -= CONTROL_PANEL_SIZE;
}
d3drm -> CreateDeviceFromClipper( clipper, NULL,
size.right, size.bottom, &device );
// If the scene is not constructed, set the device to -
// - the default render style and then create the scene.
if ( scene == NULL )
{
// Set the initial render style.
device -> SetQuality( DEFAULT_RENDER_STYLE );
// IMPORTANT STEP: Set up all the simulation's graphics.
createScene( );
}
else
{
// The scene has already been created, -
// - just reconfigure the device and viewport.
device -> SetQuality( renderStyle ); // Restore the render style.
// Create the viewport.
d3drm -> CreateViewport( device, camera, 0, 0,
device -> GetWidth( ), device -> GetHeight( ), &viewPort );
// Set the range of vision, default is 100.
viewPort -> SetBack( D3DVALUE( VIEWPORT_BACK_DISTANCE ) );
}
}
// Maintain the scene before rendering the next frame.
void BoidsWin::maintainScene( )
{
// Abort if the rendering thread is still active.
if ( threadFinished == false )
{
return;
}
// Gradually change the meshes over frame by frame.
// This prevents the system from being locked up.
if ( flyerMeshesChanged < numFlyers )
{
// Set the mesh.
flyers[ flyerMeshesChanged ] -> updateMesh( );
// Size the mesh according to the size slider.
double posSize = ( sliderSize.GetPos() * SIZE_SCALE_FACTOR );
flyers[ flyerMeshesChanged++ ] -> setSize( posSize );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -