Loading and Handling RoadRage Models

[Previous] [Next]

The remainder of this chapter consists of a description of the code that's necessary for loading and using 3D Studio Max-animated and Quake II-animated models in your Direct3D Immediate Mode applications. I'll give step-by-step descriptions of the functionality of the render loop, which renders the scene for each frame in the animation process.

I'll mention the key routines for loading the 3D Studio and Quake character files so that you can visualize the code necessary for loading a file format and converting it to DrawPrimitive data. You should be able to understand this code on your own because the code simply performs a step-by-step load of the data in these files and stores the data in a format that Direct3D can use to render 3D objects. Describing all the nuances of the .3ds file format would take an entire book! If you want more details on the 3D Studio and Quake file formats, look at the files in the Quake II Utilities and 3D Studio Max Utilities directories on the companion CD. These directories also contain a number of utilities, links to various Web sites that have information on these formats, and files containing descriptions of these formats.

The first routines you need to modify so that you can implement character animation are the CD3DApplication::Render3DEnvironment and CD3DApplication::MovePlayer routines. These routines handle all input from the keyboard and other input devices.

Each Quake character model has a weapon model associated with it. The weapon model contains frames defining motion sequences just as the character model does. You can load these motions and use them in the same manner as you would load and use the movement of characters.

The CD3DApplication::Render3DEnvironment member function checks whether the user has selected the joystick as the input device. (The user makes this selection by pulling down the Control menu item from the main menu on the main screen.) If the joystick is in use, you acquire the joystick information (and reacquire the joystick if you lost it).

 else if( g_bUseJoystick ) {     g_pD3DApp->CreateInputDevice( GetParent(hWnd),                                   g_guidJoystick, &c_dfDIJoystick,                                    DISCL_EXCLUSIVE|DISCL_FOREGROUND );     g_pdidDevice2->Acquire(); 

Once you have the joystick (indicated if you have a valid pointer), you need to determine whether the character is walking or driving. In RoadRage, characters can either walk or drive around the 3D world. If the character is walking, set the field of view to the appropriate value, as the following code shows:

 if(walk_mode_enabled == TRUE) {     // JOYSTICK WALK MODE     car_speed = (float)0; 

Now that you know you have a joystick in use, start checking the status of the input device's buttons. (Recall that in DirectX the term joystick includes steering wheels, yokes, and so on.) The user switches to driving mode by hitting the second joystick button, as this code segment shows:

 if(delay_key_press_flag == FALSE) {     if (dijs.rgbButtons[JOY_BUTTON_2] & 0x80)     {         walk_mode_enabled = FALSE;         delay_key_press_flag = TRUE;         SetTimer(m_hWnd, 3, KEY_DELAY,NULL);     } 

The user presses the third button to switch to the previous gun in the weapon inventory, but switching to the previous gun has no effect if the first gun in the list of guns available to the user is currently selected. Selecting the previous gun causes the gun to switch its 3D model in this loop, using the animation sequence for switching weapons that's stored in the weapon model. The following code illustrates this switch:

 if (dijs.rgbButtons[JOY_BUTTON_3] & 0x80) {     current_gun--;         if (current_gun < 0)         current_gun++;     delay_key_press_flag = TRUE;     SetTimer(m_hWnd,3, KEY_DELAY,NULL); } 

The user presses the fourth button to switch to the next gun in the weapon inventory. Pressing the fourth button has no effect if the currently selected weapon is the last one on the list. Switching to the next weapon in the list causes the gun to switch its 3D model in this loop, using the animation sequence for switching weapons that's stored in the weapon model. The next code segment, in the CD3DApplication::Render3DEnvironment function, shows how to program this switch:

 if (dijs.rgbButtons[JOY_BUTTON_4] & 0x80)     {         current_gun++;         if (current_gun > MAX_NUM_WEAPONS)             current_gun--;         delay_key_press_flag = TRUE;         SetTimer(m_hWnd,3, KEY_DELAY,NULL);     } } 

Next you need to determine the x value of the joystick. If the user moves the joystick to the left, rotate the view of the scene to the left. If the user pushes the joystick to the right, rotate the view to the right. Now you also check the y value of the joystick. If the user pushes the stick forward, increase the speed of the user. If the user pushes the joystick backward, slow down the user. This next code segment shows you how to control an object's speed. To handle the motion, you call the MovePlayer routine with the axis and button information as follows:

 MovePlayer( dijs.lX<0, dijs.lX>0, dijs.lY<0, dijs.lY>0,             dijs.rgbButtons[0] & 0x80, 0, 0 ); VOID CD3DApplication::MovePlayer( BOOL bLeft, BOOL bRight,     BOOL bForward, BOOL bBackward, BOOL bUp, BOOL bDown,  BOOL bFire ) {          if( bForward  == TRUE )             {         m_vEyePt.x += speed * sinf(angy * k);         m_vEyePt.z += speed * cosf(angy * k);     }          if( bBackward  == TRUE)         {         m_vEyePt.x += -speed * sinf(angy * k);         m_vEyePt.z += -speed * cosf(angy * k);     }      

You also need to check the current camera angle. If you've pushed the angle below 0 degrees, add 360 degrees to the angle value to make it a valid setting. If you've pushed the camera angle past 360 degrees, subtract 360 degrees from its value. Here's the code for this technique:

 if(angle >= 360)     angle = angle - 360; if(angle < 0)     angle += 360; 

If the game is in joystick driving mode rather than in joystick walking mode, check whether the user has pressed the second button. If the user has, switch to walking mode. This code works the same as the code above for walking mode does, but it places the eyepoint closer to the ground.

If the user presses the third or fourth button on the joystick, set the speed and gear of the car:

 if (dijs.rgbButtons[JOY_BUTTON_3] & 0x80) {     if((car_speed > 0) && (car_gear == -1))         car_speed-=(float).2;     else         car_gear = 1; } if (dijs.rgbButtons[JOY_BUTTON_4] & 0x80) {     if((car_speed > 0) && (car_gear == 1))         car_speed-=(float).2;     else         car_gear = -1; } 

If the user moves the joystick to the left or the right, you need to rotate the view of the scene accordingly as long as the user is moving, as we did with the keyboard handling code. If the user moves the joystick backward or forward, you set the speed and gear of the car accordingly. You can also set the speed to a maximum of 64 mph and a minimum of 0 mph, as shown in this next code segment:

 if(dijs.lY < -200) // Accelerate {     frequency = 12000 + (int)((float)car_speed * (float)250.0);     car_speed+=(float).1; } if(dijs.lY > 200) // Brake {     frequency = 12000 + (int)((float)car_speed * (float)187.5);     car_speed-=(float).2; } if(car_speed<0)     car_speed=(float)0;          if(car_speed>64)     car_speed=(float)64; 

If the user is running in keyboard mode (meaning that all control comes from keyboard input), you need to check the keyboard status. If the user presses the Flip key, you need to play the sequence that makes the character gesture. ("Flip" is Quake terminology for "gesture.") To make this action visible, the RoadRage code causes this button to make the main character stand by the corner of the main buildings at the end of the town when you start the game gesture—for example, by waving, taunting, and so on.

If the user presses the Salute, Taunt, Wave, or Point key, we play the appropriate sequence to make the character perform the desired action in a similar manner. Refer to the CD3DApplication::Render3DEnvironment function to see all the key states that are handled. This code will also handle switching weapons, entering or exiting a car, rotating, speeding up, or slowing down.

To position the weapon the user has selected, you must offset it from the viewpoint. You also need to set the gun angle and make sure to restrict it to between 0 and 360 degrees so that it returns to 0 after passing 360 degrees. The next routine you need to create will set the frame sequences that animate the actions of the gun: fire, idle, put away, reload, burst fire, and last round. Here's the routine:

 void LoadYourGunAnimationSequenceList(int model_id, world_ptr wptr) {     int i;     i = model_id;     wptr->your_gun[0].current_sequence = 2;     wptr->your_gun[0].current_frame = 13;     wptr->your_gun[1].current_sequence = 2;     wptr->your_gun[1].current_frame = 13;     wptr->your_gun[2].current_sequence = 0;     wptr->your_gun[2].current_frame = 0;              wptr->pmdata[i].sequence_start_frame[0] =0;  // Active1     wptr->pmdata[i].sequence_stop_frame [0] =10;     wptr->pmdata[i].sequence_start_frame[1] =11; // Fire     wptr->pmdata[i].sequence_stop_frame [1] =12;     wptr->pmdata[i].sequence_start_frame[2] =13; // Idle     wptr->pmdata[i].sequence_stop_frame [2] =39;     wptr->pmdata[i].sequence_start_frame[3] =40; // Put away     wptr->pmdata[i].sequence_stop_frame [3] =44;     wptr->pmdata[i].sequence_start_frame[4] =45; // Reload     wptr->pmdata[i].sequence_stop_frame [4] =63;     wptr->pmdata[i].sequence_start_frame[5] =64; // Burst fire     wptr->pmdata[i].sequence_stop_frame [5] =69;     wptr->pmdata[i].sequence_start_frame[6] =70; // Last round     wptr->pmdata[i].sequence_stop_frame [6] =71; } 

To load all the models you import from 3D Studio or Quake format, use the LoadImportedModelList routine in the file loadworld.cpp. This routine loads the player, car, gun, and debug models from the requested file so that you can use them in your game.

The routine ImportMD2 in the file importMD2.cpp loads the Quake character models. The ImportMD2 routine loads a Quake character model in MD2 format and converts it into a triangle strip or a triangle fan. William Chin created a third routine to load Quake models and directly animate them in Direct3D. This routine allows you to load any of the thousands of characters available on the Internet or ones you create yourself using Quake Modeller, included on the companion CD. You can then render this object using DrawPrimitive. You'll find the Quake file format that's used to create this routine described in a number of places on the Internet. Also, the companion CD contains utilities for creating and texturing Quake models that should help you greatly in understanding this format if you want to investigate it further. Be aware that the term skin, which appears in the following code comments, defines each of the meshes that represent one step in the animation sequence.

The other key code to look at is the Import3ds routine and several auxiliary routines that Import3ds uses (look in the file import3DS.cpp). William Chin also created this code. The 3D Studio (.3ds) file format is complex, but you can use this routine to load any .3ds files containing nonanimated objects. This code doesn't handle many of the .3ds file data types, but the case statement lists each data type not handled so that you can add code to handle the ones you want to use.

This code creates data structures that hold and load the data from a 3D Studio .3ds file. Describing the format of the .3ds files would fill an entire book. If you want to learn more about this file format, consult one of the many books discussing this topic.



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net