![]() |
![]() |
![]() |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
![]() |
To access the contents, click the chapter and section titles.
Cutting Edge Direct 3D Programming
Using Callback FunctionsEarly in this chapter, when we were using the Direct3D AppWizard to create the Sample application, we specified that we wanted an animated spotlight. The AppWizard added code to the project that updates the spotlights orientation during the execution of the program. This updating is accomplished with a callback function. Callback functions are functions that Direct3D calls whenever it is about to perform a system update. These functions can be used to adjust program settings at runtime. When we were creating the spotlight in the CreateScene() function, we installed a callback function named MoveLight(). The callback installation looks like this: slightframe->AddMoveCallback( MoveLight, NULL ); The AddMoveCallback() function is a Direct3DRMFrame member function. The first argument is a pointer to the function that is to be called on each update. The second parameter is a pointer to data that will be passed to the callback function. This extra data is optional, so we are sending NULL. The MoveLight() function adjusts the spotlights orientation. The code appears as follows: void SampleWin::MoveLight(LPDIRECT3DRMFRAME lightframe, void*, D3DVALUE) { // move the spotlight over the meshes static const D3DVALUE lim = D3DVALUE(0.3); static D3DVALUE xi = D3DVALUE(0.01); static D3DVALUE yi = D3DVALUE(0.005); static D3DVALUE x, y; if (x<-LIM || x>lim) xi=-xi; if (y<-LIM || y>lim) yi=-yi; x+=xi; y+=yi; lightframe->SetOrientation( NULL, x, y-1, D3DVALUE(1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); } The function uses a simple bouncing ball algorithm to calculate a new orientation for the spotlight on each invocation. The spotlights movement is limited by the lim constant and is incremented with the xi and yi values. After a new orientation has been calculated, it is assigned to the frame with the SetOrientation() function. Callback functions are always declared static, as shown: class SampleWin : public RMWin { // ... private: static void MoveLight(LPDIRECT3DRMFRAME frame, void* arg, D3DVALUE delta); // ... }; This is required, because regular member functions require an implicit class pointer. Declaring the function as static removes this dependency but means that the callback function cannot access the classes member functions. It is for this reason that the AddMoveCallback() function provides a way to supply the callback with extra data. Callbacks installed with AddMoveCallback() are required to have three parameters. The first is a pointer to the frame interface that installed the callback. The second parameter is the pointer that is optionally used to supply extra data to the callback. The third parameter is the value that was passed to the Tick() function. Recall that the Tick() function can be used to slow and speed a programs animation rate. If you always pass 1.0 to the Tick() function, then it is safe to ignore this parameter. Shutting Things DownInitializing Direct3D, creating scenes, and performing runtime animation is so much fun that it seems a shame to terminate a program, but it happens nevertheless. The OnDestroy() FunctionBefore an MFC application terminates, the OnDestroy() function is called. This is a good place to release the references that we have created. RMWin provides a version of OnDestroy() that releases the standard Direct3D interfaces. The function looks like this: void RMWin::OnDestroy() { if (scene) { scene->Release(); scene=0; } if (device) { device->Release(); device=0; } if (d3drm) { d3drm->Release(); d3drm=0; } if (clipper) { clipper->Release(); clipper=0; } } Helper FunctionsSome of the functions that weve looked at use functions that are not Win32, MFC, or Direct3D functions. These functions are convenience functions that the RMWin class provides. Well look at these functions next. The ScaleMesh() FunctionIn the CreateScene() function, after the meshbuilder had been created and loaded, the ScaleMesh() function was used to insure that the mesh was a certain size. This code appears, again: d3drm->CreateMeshBuilder( &meshbuilder ); r=meshbuilder->Load( meshname, NULL, D3DRMLOAD_FROMFILE, NULL, NULL ); if (r!=D3DRM_OK) { CString msg; msg.Format( "Failed to load file '%s'\n", meshname ); AfxMessageBox( msg ); return FALSE; } ScaleMesh( meshbuilder, D3DVALUE(25) ); The ScaleMesh() function takes two arguments: a pointer to the meshbuilder and a size value. The size value is not a scale factor but rather an ideal size for the object. The ScaleMesh() function calculates a scale factor that will bring the largest dimension of the object as near as possible to the size limit. In the code above, ScaleMesh() scales the object so that its longest side is 25 units in length. The ScaleMesh() function looks like this: void RMWin::ScaleMesh( LPDIRECT3DRMMESHBUILDER mesh, D3DVALUE dim) { D3DRMBOX box; mesh->GetBox( &box ); D3DVALUE sizex = box.max.x - box.min.x; D3DVALUE sizey = box.max.y - box.min.y; D3DVALUE sizez = box.max.z - box.min.z; D3DVALUE largedim=D3DVALUE(0); if (sizex>largedim) largedim=sizex; if (sizey>largedim) largedim=sizey; if (sizez>largedim) largedim=sizez; D3DVALUE scalefactor = dim/largedim; mesh->Scale( scalefactor, scalefactor, scalefactor ); } The function uses the Direct3DRMMeshBuilder GetBox() function to retrieve the dimensions of the mesh. It uses this data to determine which dimension of the mesh is the longest and calculates a scale factor that will scale the object to the prescribed size. The last function call performs the scaling. The GetMouse() FunctionsThe mouse is a fundamental part of Windows and users expect mouse support as much as they expect keyboard support. The GetMouseX() and GetMouseY() functions are supplied by the RMWin class so that your code can determine the current mouse location at any time. Both functions return the mouse position in pixel units. These functions are declared as static so that they can be used by callback functions.
|
![]() |
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. |