int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix // these are used to create a circling camera static float view_angle = 0; static float camera_distance = 6000; static VECTOR4D pos = {0,0,0,0}; static float tank_speed; static float turning = 0; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface DDraw_Fill_Surface(lpddsback, 0); // draw the sky Draw_Rectangle(0,0, WINDOW_WIDTH-1, WINDOW_HEIGHT/2, RGB16Bit(0,140,192), lpddsback); // draw the ground Draw_Rectangle(0,WINDOW_HEIGHT/2, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, RGB16Bit(103,62,3), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV1(&rend_list); // allow user to move camera // turbo if (keyboard_state[DIK_SPACE]) tank_speed = 5*TANK_SPEED; else tank_speed = TANK_SPEED; // forward/backward if (keyboard_state[DIK_UP]) { // move forward cam.pos.x += tank_speed*Fast_Sin(cam.dir.y); cam.pos.z += tank_speed*Fast_Cos(cam.dir.y); } // end if if (keyboard_state[DIK_DOWN]) { // move backward cam.pos.x -= tank_speed*Fast_Sin(cam.dir.y); cam.pos.z -= tank_speed*Fast_Cos(cam.dir.y); } // end if // rotate if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=3; // add a little turn to object if ((turning+=2) > 15) turning=15; } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=3; // add a little turn to object if ((turning-=2) < -15) turning=-15; } // end if else // center heading again { if (turning > 0) turning-=1; else if (turning < 0) turning+=1; } // end else // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // insert the tanks in the world for (index = 0; index < NUM_TANKS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_tank); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(0, tanks[index].w, 0, &mrot); // rotate the local coords of the object Transform_OBJECT4DV1(&obj_tank, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // set position of tank obj_tank.world_pos.x = tanks[index].x; obj_tank.world_pos.y = tanks[index].y; obj_tank.world_pos.z = tanks[index].z; // attempt to cull object if (!Cull_OBJECT4DV1(&obj_tank, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj_tank, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_tank); } // end if } // end for // insert the player into the world // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_player); // set position of tank obj_player.world_pos.x = cam.pos.x+300*Fast_Sin(cam.dir.y); obj_player.world_pos.y = cam.pos.y-70; obj_player.world_pos.z = cam.pos.z+300*Fast_Cos(cam.dir.y); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(0, cam.dir.y+turning, 0, &mrot); // rotate the local coords of the object Transform_OBJECT4DV1(&obj_player, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV1(&obj_player, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_player); // insert the towers in the world for (index = 0; index < NUM_TOWERS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_tower); // set position of tower obj_tower.world_pos.x = towers[index].x; obj_tower.world_pos.y = towers[index].y; obj_tower.world_pos.z = towers[index].z; // attempt to cull object if (!Cull_OBJECT4DV1(&obj_tower, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj_tower); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_tower); } // end if } // end for // seed number generator so that modulation of markers is always the same srand(13); // insert the ground markers into the world for (int index_x = 0; index_x < NUM_POINTS_X; index_x++) for (int index_z = 0; index_z < NUM_POINTS_Z; index_z++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_marker); // set position of tower obj_marker.world_pos.x = RAND_RANGE(-100,100)-UNIVERSE_RADIUS+index_x*POINT_SIZE; obj_marker.world_pos.y = obj_marker.max_radius; obj_marker.world_pos.z = RAND_RANGE(-100,100)-UNIVERSE_RADIUS+index_z*POINT_SIZE; // attempt to cull object if (!Cull_OBJECT4DV1(&obj_marker, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj_marker); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_marker); } // end if } // end for // remove backfaces Remove_Backfaces_RENDERLIST4DV1(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV1(&rend_list, &cam); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV1(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV1(&rend_list, &cam); sprintf(work_string,"pos:[%f, %f, %f] heading:[%f] elev:[%f]", cam.pos.x, cam.pos.y, cam.pos.z, cam.dir.y, cam.dir.x); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-20, RGB(0,255,0), lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press Arrow Keys to Move. Space for TURBO.", 0, 0, RGB(0,255,0), lpddsback); // lock the back buffer DDraw_Lock_Back_Surface(); // render the object Draw_RENDERLIST4DV1_Wire16(&rend_list, back_buffer, back_lpitch); // unlock the back buffer DDraw_Unlock_Back_Surface(); // flip the surfaces DDraw_Flip(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix // these are used to create a circling camera static float view_angle = 0; static float camera_distance = 6000; static VECTOR4D pos = {0,0,0,0}; static float tank_speed; static float turning = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = 1; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface DDraw_Fill_Surface(lpddsback, 0); // draw the sky //Draw_Rectangle(0,0, WINDOW_WIDTH, WINDOW_HEIGHT/2, RGB16Bit(0,35,50), lpddsback); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT/2-1, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(20,12,0), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV2(&rend_list); // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // backface removal if (keyboard_state[DIK_B]) { // toggle backface removal backface_mode = -backface_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights[AMBIENT_LIGHT_INDEX].state == LIGHTV1_STATE_ON) lights[AMBIENT_LIGHT_INDEX].state = LIGHTV1_STATE_OFF; else lights[AMBIENT_LIGHT_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights[INFINITE_LIGHT_INDEX].state == LIGHTV1_STATE_ON) lights[INFINITE_LIGHT_INDEX].state = LIGHTV1_STATE_OFF; else lights[INFINITE_LIGHT_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights[POINT_LIGHT_INDEX].state == LIGHTV1_STATE_ON) lights[POINT_LIGHT_INDEX].state = LIGHTV1_STATE_OFF; else lights[POINT_LIGHT_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle spot light if (keyboard_state[DIK_S]) { // toggle spot light if (lights[SPOT_LIGHT2_INDEX].state == LIGHTV1_STATE_ON) lights[SPOT_LIGHT2_INDEX].state = LIGHTV1_STATE_OFF; else lights[SPOT_LIGHT2_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_Z]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if static float plight_ang = 0, slight_ang = 0; // angles for light motion // move point light source in ellipse around game world lights[POINT_LIGHT_INDEX].pos.x = 1000*Fast_Cos(plight_ang); lights[POINT_LIGHT_INDEX].pos.y = 100; lights[POINT_LIGHT_INDEX].pos.z = 1000*Fast_Sin(plight_ang); if ((plight_ang+=3) > 360) plight_ang = 0; // move spot light source in ellipse around game world lights[SPOT_LIGHT2_INDEX].pos.x = 1000*Fast_Cos(slight_ang); lights[SPOT_LIGHT2_INDEX].pos.y = 200; lights[SPOT_LIGHT2_INDEX].pos.z = 1000*Fast_Sin(slight_ang); if ((slight_ang-=5) < 0) slight_ang = 360; // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // use these to rotate objects static float x_ang = 0, y_ang = 0, z_ang = 0; ////////////////////////////////////////////////////////////////////////// // constant shaded water // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_constant_water); // set position of constant shaded water obj_constant_water.world_pos.x = -50; obj_constant_water.world_pos.y = 0; obj_constant_water.world_pos.z = 120; // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_constant_water, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_constant_water, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_constant_water,0); ////////////////////////////////////////////////////////////////////////// // flat shaded water // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_flat_water); // set position of constant shaded water obj_flat_water.world_pos.x = 0; obj_flat_water.world_pos.y = 0; obj_flat_water.world_pos.z = 120; // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_flat_water, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_flat_water, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_flat_water,0); ////////////////////////////////////////////////////////////////////////// // gouraud shaded water // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_gouraud_water); // set position of constant shaded water obj_gouraud_water.world_pos.x = 50; obj_gouraud_water.world_pos.y = 0; obj_gouraud_water.world_pos.z = 120; // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_gouraud_water, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_gouraud_water, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_gouraud_water,0); // update rotation angles if ((x_ang+=1) > 360) x_ang = 0; if ((y_ang+=2) > 360) y_ang = 0; if ((z_ang+=3) > 360) z_ang = 0; // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // light scene all at once if (lighting_mode==1) Light_RENDERLIST4DV2_World16(&rend_list, &cam, lights, 4); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); sprintf(work_string,"Lighting [%s]: Ambient=%d, Infinite=%d, Point=%d, Spot=%d | Zsort [%s], BckFceRM [%s]", ((lighting_mode == 1) ? "ON" : "OFF"), lights[AMBIENT_LIGHT_INDEX].state, lights[INFINITE_LIGHT_INDEX].state, lights[POINT_LIGHT_INDEX].state, lights[SPOT_LIGHT2_INDEX].state, ((zsort_mode == 1) ? "ON" : "OFF"), ((backface_mode == 1) ? "ON" : "OFF")); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34, RGB(0,255,0), lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press <H> for Help.", 0, 0, RGB(0,255,0), lpddsback); // should we display help int text_y = 16; if (help_mode==1) { // draw help menu Draw_Text_GDI("<A>..............Toggle ambient light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<I>..............Toggle infinite light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<P>..............Toggle point light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<S>..............Toggle spot light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<W>..............Toggle wire frame/solid mode.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<B>..............Toggle backface removal.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<H>..............Toggle Help.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<ESC>............Exit demo.", 0, text_y+=12, RGB(255,255,255), lpddsback); } // end help // lock the back buffer DDraw_Lock_Back_Surface(); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the object if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) Draw_RENDERLIST4DV2_Solid16(&rend_list, back_buffer, back_lpitch); // unlock the back buffer DDraw_Unlock_Back_Surface(); // flip the surfaces DDraw_Flip(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix static float plight_ang = 0, slight_ang = 0; // angles for light motion // use these to rotate objects static float x_ang = 0, y_ang = 0, z_ang = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = -1; static int x_clip_mode = 1; static int y_clip_mode = 1; static int z_clip_mode = 1; static float hl = 300, // artificial light height ks = 1.25; // generic scaling factor to make things look good char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface DDraw_Fill_Surface(lpddsback, 0); // draw the sky Draw_Rectangle(0,0, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, RGB16Bit(50,50,200), lpddsback); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT*.38, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(25,50,110), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV2(&rend_list); // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // backface removal if (keyboard_state[DIK_B]) { // toggle backface removal backface_mode = -backface_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights2[AMBIENT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights2[INFINITE_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights2[POINT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; // toggle point light if (lights2[POINT_LIGHT2_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT2_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT2_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_Z]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // next animation if (keyboard_state[DIK_2]) { if (++obj_md2.anim_state >= NUM_MD2_ANIMATIONS) obj_md2.anim_state = 0; Set_Animation_MD2(&obj_md2, obj_md2.anim_state, MD2_ANIM_SINGLE_SHOT); Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // previous animation if (keyboard_state[DIK_1]) { if (--obj_md2.anim_state < 0) obj_md2.anim_state = NUM_MD2_ANIMATIONS-1; Set_Animation_MD2(&obj_md2, obj_md2.anim_state, MD2_ANIM_SINGLE_SHOT); Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // replay animation if (keyboard_state[DIK_3]) { Set_Animation_MD2(&obj_md2, obj_md2.anim_state, MD2_ANIM_SINGLE_SHOT); Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // replay animation if (keyboard_state[DIK_4]) { Set_Animation_MD2(&obj_md2, obj_md2.anim_state, MD2_ANIM_LOOP); Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // forward/backward if (keyboard_state[DIK_UP]) { // move forward if ( (cam_speed+=1) > MAX_SPEED) cam_speed = MAX_SPEED; } // end if else if (keyboard_state[DIK_DOWN]) { // move backward if ((cam_speed-=1) < -MAX_SPEED) cam_speed = -MAX_SPEED; } // end if // rotate around y axis or yaw if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=5; // scroll the background Scroll_Bitmap(&background_bmp, -10); } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=5; // scroll the background Scroll_Bitmap(&background_bmp, 10); } // end if // scroll sky slowly Scroll_Bitmap(&background_bmp, -1); // motion section ///////////////////////////////////////////////////////// // terrain following, simply find the current cell we are over and then // index into the vertex list and find the 4 vertices that make up the // quad cell we are hovering over and then average the values, and based // on the current height and the height of the terrain push the player upward // the terrain generates and stores some results to help with terrain following //ivar1 = columns; //ivar2 = rows; //fvar1 = col_vstep; //fvar2 = row_vstep; int cell_x = (cam.pos.x + TERRAIN_WIDTH/2) / obj_terrain.fvar1; int cell_y = (cam.pos.z + TERRAIN_HEIGHT/2) / obj_terrain.fvar1; static float terrain_height, delta; // test if we are on terrain if ( (cell_x >=0) && (cell_x < obj_terrain.ivar1) && (cell_y >=0) && (cell_y < obj_terrain.ivar2) ) { // compute vertex indices into vertex list of the current quad int v0 = cell_x + cell_y*obj_terrain.ivar2; int v1 = v0 + 1; int v2 = v1 + obj_terrain.ivar2; int v3 = v0 + obj_terrain.ivar2; // now simply index into table terrain_height = 0.25 * (obj_terrain.vlist_trans[v0].y + obj_terrain.vlist_trans[v1].y + obj_terrain.vlist_trans[v2].y + obj_terrain.vlist_trans[v3].y); // compute height difference delta = terrain_height - (cam.pos.y - gclearance); // test for penetration if (delta > 0) { // apply force immediately to camera (this will give it a springy feel) vel_y+=(delta * (VELOCITY_SCALER)); // test for pentration, if so move up immediately so we don't penetrate geometry cam.pos.y+=(delta*CAM_HEIGHT_SCALER); // now this is more of a hack than the physics model :) let move the front // up and down a bit based on the forward velocity and the gradient of the // hill cam.dir.x -= (delta*PITCH_CHANGE_RATE); } // end if } // end if // decelerate camera if (cam_speed > (CAM_DECEL) ) cam_speed-=CAM_DECEL; else if (cam_speed < (-CAM_DECEL) ) cam_speed+=CAM_DECEL; else cam_speed = 0; // force camera to seek a stable orientation if (cam.dir.x > (neutral_pitch+PITCH_RETURN_RATE)) cam.dir.x -= (PITCH_RETURN_RATE); else if (cam.dir.x < (neutral_pitch-PITCH_RETURN_RATE)) cam.dir.x += (PITCH_RETURN_RATE); else cam.dir.x = neutral_pitch; // apply gravity vel_y+=gravity; // test for absolute sea level and push upward.. if (cam.pos.y < sea_level) { vel_y = 0; cam.pos.y = sea_level; } // end if // move camera cam.pos.x += cam_speed*Fast_Sin(cam.dir.y); cam.pos.z += cam_speed*Fast_Cos(cam.dir.y); cam.pos.y += vel_y; // move point light source in ellipse around game world lights2[POINT_LIGHT_INDEX].pos.x = 500*Fast_Cos(plight_ang); //lights2[POINT_LIGHT_INDEX].pos.y = 200; lights2[POINT_LIGHT_INDEX].pos.z = 500*Fast_Sin(plight_ang); // move point light source in ellipse around game world lights2[POINT_LIGHT2_INDEX].pos.x = 200*Fast_Cos(-2*plight_ang); //lights2[POINT_LIGHT2_INDEX].pos.y = 400; lights2[POINT_LIGHT2_INDEX].pos.z = 200*Fast_Sin(-2*plight_ang); if ((plight_ang+=1) > 360) plight_ang = 0; // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); ////////////////////////////////////////////////////////////////////////// // the terrain // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_terrain); // generate rotation matrix around y axis //Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_terrain, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_terrain, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_terrain,0); ////////////////////////////////////////////////////////////////////////// int v0, v1, v2, v3; // used to track vertices VECTOR4D pl, // position of the light po, // position of the occluder object/vertex vlo, // vector from light to object ps; // position of the shadow float rs, // radius of shadow t; // parameter t ////////////////////////////////////////////////////////////////////////// // render model, this next section draws each copy of the mech model ////////////////////////////////////////////////////////////////////////// // animate the model Animate_MD2(&obj_md2); // extract the frame of animation from vertex banks Extract_MD2_Frame(&obj_model, // pointer to destination object &obj_md2); // md2 object to extract frame from // set position of object obj_model.world_pos.x = 0; obj_model.world_pos.y = 100; obj_model.world_pos.z = 0; // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_model); // create identity matrix MAT_IDENTITY_4X4(&mrot); // transform the local coords of the object Transform_OBJECT4DV2(&obj_model, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_model, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_model,0); // set position of object obj_model.world_pos.x = 0; obj_model.world_pos.y = 100; obj_model.world_pos.z = 200; // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_model); // create identity matrix MAT_IDENTITY_4X4(&mrot); // transform the local coords of the object Transform_OBJECT4DV2(&obj_model, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_model, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_model,0); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // draw all the light objects to represent the position of light sources // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_light_array[INDEX_RED_LIGHT_INDEX]); // set position of object to light obj_light_array[INDEX_RED_LIGHT_INDEX].world_pos = lights2[POINT_LIGHT_INDEX].pos; // create identity matrix MAT_IDENTITY_4X4(&mrot); // transform the local coords of the object Transform_OBJECT4DV2(&obj_light_array[INDEX_RED_LIGHT_INDEX], &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_light_array[INDEX_RED_LIGHT_INDEX], TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_light_array[INDEX_RED_LIGHT_INDEX],0); // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_light_array[INDEX_YELLOW_LIGHT_INDEX]); // set position of object to light obj_light_array[INDEX_YELLOW_LIGHT_INDEX].world_pos = lights2[POINT_LIGHT2_INDEX].pos; // create identity matrix MAT_IDENTITY_4X4(&mrot); // transform the local coords of the object Transform_OBJECT4DV2(&obj_light_array[INDEX_YELLOW_LIGHT_INDEX], &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_light_array[INDEX_YELLOW_LIGHT_INDEX], TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_light_array[INDEX_YELLOW_LIGHT_INDEX],0); //////////////////////////////////////////////////////////////////////////////////// // reset number of polys rendered debug_polys_rendered_per_frame = 0; debug_polys_lit_per_frame = 0; // perform rendering pass one // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, CLIP_POLY_X_PLANE | CLIP_POLY_Y_PLANE | CLIP_POLY_Z_PLANE ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // lock the back buffer DDraw_Lock_Back_Surface(); // draw background Draw_Bitmap16(&background_bmp, back_buffer, back_lpitch,0); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the object if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // perspective mode affine texturing // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER // | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; // initialize zbuffer to 0 fixed point Clear_Zbuffer(&zbuffer, (16000 << FIXP16_SHIFT)); // set up remainder of rendering context rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 0; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16_2(&rc); } // end if // now make second rendering pass and draw shadow // reset the render list Reset_RENDERLIST4DV2(&rend_list); ////////////////////////////////////////////////////////////////////////// // project shaded object into shadow by projecting it's vertices onto // the ground plane // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_model); // save the shading attributes/color of each polygon, and override them with // attributes of a shadow then restore them int pcolor[OBJECT4DV2_MAX_POLYS], // used to store color pattr[OBJECT4DV2_MAX_POLYS]; // used to store attribute // save all the color and attributes for each polygon for (int pindex = 0; pindex < obj_model.num_polys; pindex++) { // save attribute and color pattr[pindex] = obj_model.plist[pindex].attr; pcolor[pindex] = obj_model.plist[pindex].color; // set attributes for shadow rendering obj_model.plist[pindex].attr = POLY4DV2_ATTR_RGB16 | POLY4DV2_ATTR_SHADE_MODE_CONSTANT | POLY4DV2_ATTR_TRANSPARENT; obj_model.plist[pindex].color = RGB16Bit(50,50,50) + (7 << 24); } // end for pindex // create identity matrix MAT_IDENTITY_4X4(&mrot); // solve for t when the projected vertex intersects ground plane pl = lights2[POINT_LIGHT_INDEX].pos; // transform each local/model vertex of the object mesh and store result // in "transformed" vertex list, note for (int vertex=0; vertex < obj_model.num_vertices; vertex++) { POINT4D presult; // hold result of each transformation // compute parameter t0 when projected ray pierces y=0 plane VECTOR4D vi; // set position of object obj_model.world_pos.x = 0; obj_model.world_pos.y = 100; obj_model.world_pos.z = 0; // transform coordinates to worldspace right now... VECTOR4D_Add(&obj_model.vlist_local[vertex].v, &obj_model.world_pos, &vi); float t0 = -pl.y / (vi.y - pl.y); // transform point obj_model.vlist_trans[vertex].v.x = pl.x + t0*(vi.x - pl.x); obj_model.vlist_trans[vertex].v.y = 10.0; // pl.y + t0*(vi.y - pl.y); obj_model.vlist_trans[vertex].v.z = pl.z + t0*(vi.z - pl.z); obj_model.vlist_trans[vertex].v.w = 1.0; } // end for index // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_model,0); // and now second shadow object from second light source... // solve for t when the projected vertex intersects pl = lights2[POINT_LIGHT_INDEX].pos; // transform each local/model vertex of the object mesh and store result // in "transformed" vertex list for (vertex=0; vertex < obj_model.num_vertices; vertex++) { POINT4D presult; // hold result of each transformation // compute parameter t0 when projected ray pierces y=0 plane VECTOR4D vi; // set position of object obj_model.world_pos.x = 0; obj_model.world_pos.y = 100; obj_model.world_pos.z = 200; // transform coordinates to worldspace right now... VECTOR4D_Add(&obj_model.vlist_local[vertex].v, &obj_model.world_pos, &vi); float t0 = -pl.y / (vi.y - pl.y); // transform point obj_model.vlist_trans[vertex].v.x = pl.x + t0*(vi.x - pl.x); obj_model.vlist_trans[vertex].v.y = 10.0; // pl.y + t0*(vi.y - pl.y); obj_model.vlist_trans[vertex].v.z = pl.z + t0*(vi.z - pl.z); obj_model.vlist_trans[vertex].v.w = 1.0; } // end for index // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_model,0); // restore attributes and color for (pindex = 0; pindex < obj_model.num_polys; pindex++) { // save attribute and color obj_model.plist[pindex].attr = pattr[pindex]; obj_model.plist[pindex].color = pcolor[pindex]; } // end for pindex ////////////////////////////////////////////////////////////////////////// // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, CLIP_POLY_X_PLANE | CLIP_POLY_Y_PLANE | CLIP_POLY_Z_PLANE ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // render the object if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // perspective mode affine texturing // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; // initialize zbuffer to 0 fixed point //Clear_Zbuffer(&zbuffer, (16000 << FIXP16_SHIFT)); // set up remainder of rendering context rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 0; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16_3(&rc); } // end if // unlock the back buffer DDraw_Unlock_Back_Surface(); // draw cockpit //Draw_BOB16(&cockpit, lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press <H> for Help.", 0, 0, RGB(255,255,255), lpddsback); // should we display help int text_y = 16; if (help_mode==1) { // draw help menu Draw_Text_GDI("<A>..............Toggle ambient light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<I>..............Toggle infinite light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<P>..............Toggle point light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<W>..............Toggle wire frame/solid mode.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<B>..............Toggle backface removal.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<Z>..............Toggle Z-sorting.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<1>,<2>..........Previous/Next Animation.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<3>,<4>..........Play Animation Single Shot/Looped.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<H>..............Toggle Help.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<ESC>............Exit demo.", 0, text_y+=12, RGB(255,255,255), lpddsback); } // end help sprintf(work_string,"Lighting [%s]: Ambient=%d, Infinite=%d, Point=%d, BckFceRM [%s], Zsort[%s]", ((lighting_mode == 1) ? "ON" : "OFF"), lights2[AMBIENT_LIGHT_INDEX].state, lights2[INFINITE_LIGHT_INDEX].state, lights2[POINT_LIGHT_INDEX].state, ((backface_mode == 1) ? "ON" : "OFF"), ((zsort_mode == 1) ? "ON" : "OFF") ); Draw_Text_GDI(work_string, 0+1, WINDOW_HEIGHT-34+1, RGB(0,0,0), lpddsback); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34, RGB(255,255,255), lpddsback); sprintf(work_string,"Polys Rendered: %d, Polys lit: %d Anim[%d]=%s Frm=%d", debug_polys_rendered_per_frame, debug_polys_lit_per_frame, obj_md2.anim_state,md2_anim_strings[obj_md2.anim_state], obj_md2.curr_frame ); Draw_Text_GDI(work_string, 0+1, WINDOW_HEIGHT-34-2*16+1, RGB(0,0,0), lpddsback); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-2*16, RGB(255,255,255), lpddsback); sprintf(work_string,"CAM [%5.2f, %5.2f, %5.2f], CELL [%d, %d]", cam.pos.x, cam.pos.y, cam.pos.z, cell_x, cell_y); Draw_Text_GDI(work_string, 0+1, WINDOW_HEIGHT-34-3*16+1, RGB(0,0,0), lpddsback); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-3*16, RGB(255,255,255), lpddsback); // flip the surfaces DDraw_Flip2(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix static float plight_ang = 0, slight_ang = 0; // angles for light motion // use these to rotate objects static float x_ang = 0, y_ang = 0, z_ang = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = 1; static int x_clip_mode = 1; static int y_clip_mode = 1; static int z_clip_mode = 1; static int bilinear_mode = 1; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface //DDraw_Fill_Surface(lpddsback, 0); // draw the sky //Draw_Rectangle(0,0, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(250,190,80), lpddsback); lpddsback->Blt(NULL, background.images[0], NULL, DDBLT_WAIT, NULL); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT*.5, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(190,190,230), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV2(&rend_list); // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights2[AMBIENT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights2[INFINITE_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights2[POINT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle spot light if (keyboard_state[DIK_S]) { // toggle spot light if (lights2[SPOT_LIGHT2_INDEX].state == LIGHTV2_STATE_ON) lights2[SPOT_LIGHT2_INDEX].state = LIGHTV2_STATE_OFF; else lights2[SPOT_LIGHT2_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_S]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // forward/backward if (keyboard_state[DIK_UP]) { // move forward if ( (cam_speed+=1) > MAX_SPEED) cam_speed = MAX_SPEED; } // end if else if (keyboard_state[DIK_DOWN]) { // move backward if ((cam_speed-=1) < -MAX_SPEED) cam_speed = -MAX_SPEED; } // end if // rotate around y axis or yaw if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=5; } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=5; } // end if // move to next object if (keyboard_state[DIK_N]) { if (++curr_object >= NUM_OBJECTS) curr_object = 0; // update pointer obj_work = &obj_array[curr_object]; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle bilinear mode if (keyboard_state[DIK_B]) { bilinear_mode = -bilinear_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // decelerate camera if (cam_speed > (CAM_DECEL) ) cam_speed-=CAM_DECEL; else if (cam_speed < (-CAM_DECEL) ) cam_speed+=CAM_DECEL; else cam_speed = 0; // move camera cam.pos.x += cam_speed*Fast_Sin(cam.dir.y); cam.pos.z += cam_speed*Fast_Cos(cam.dir.y); // move point light source in ellipse around game world lights2[POINT_LIGHT_INDEX].pos.x = 1000*Fast_Cos(plight_ang); lights2[POINT_LIGHT_INDEX].pos.y = 100; lights2[POINT_LIGHT_INDEX].pos.z = 1000*Fast_Sin(plight_ang); if ((plight_ang+=3) > 360) plight_ang = 0; // move spot light source in ellipse around game world lights2[SPOT_LIGHT2_INDEX].pos.x = 1000*Fast_Cos(slight_ang); lights2[SPOT_LIGHT2_INDEX].pos.y = 200; lights2[SPOT_LIGHT2_INDEX].pos.z = 1000*Fast_Sin(slight_ang); if ((slight_ang-=5) < 0) slight_ang = 360; // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // reset BHV for culling BHV_Reset_Tree(&bhv_tree); // now cull the BHV ... die polygons die! bhv_nodes_visited = 0; BHV_FrustrumCull(&bhv_tree, // the root of the BHV &cam, // camera to cull relative to CULL_OBJECT_XYZ_PLANES); // clipping planes to consider // statistic tracking int objects_processed = 0; //////////////////////////////////////////////////////// // insert the scenery into universe for (index = 0; index < NUM_SCENE_OBJECTS; index++) { // test if container has been culled already by BHV if (scene_objects[index].state & OBJECT4DV2_STATE_CULLED) continue; // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(obj_work); objects_processed++; // set position of object obj_work->world_pos.x = scene_objects[index].pos.x; obj_work->world_pos.y = scene_objects[index].pos.y; obj_work->world_pos.z = scene_objects[index].pos.z; // rotate object if ((scene_objects[index].rot.y+=scene_objects[index].auxi[0]) >= 360) scene_objects[index].rot.y = 0; // attempt to cull object if (!Cull_OBJECT4DV2(obj_work, &cam, CULL_OBJECT_XYZ_PLANES)) { MAT_IDENTITY_4X4(&mrot); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(0, scene_objects[index].rot.y, 0, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(obj_work, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(obj_work, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list,obj_work,0); } // end if } // end for // reset number of polys rendered debug_polys_rendered_per_frame = 0; debug_polys_lit_per_frame = 0; // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, ((x_clip_mode == 1) ? CLIP_POLY_X_PLANE : 0) | ((y_clip_mode == 1) ? CLIP_POLY_Y_PLANE : 0) | ((z_clip_mode == 1) ? CLIP_POLY_Z_PLANE : 0) ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // lock the back buffer DDraw_Lock_Back_Surface(); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the renderinglist if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // initialize zbuffer to 16000 fixed point Clear_Zbuffer(&zbuffer, (000 << FIXP16_SHIFT)); // set up rendering context rc.attr = RENDER_ATTR_INVZBUFFER // | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP | (bilinear_mode==1 ? RENDER_ATTR_BILERP : 0) | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 3500; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = 5; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16(&rc); } // end if // unlock the back buffer DDraw_Unlock_Back_Surface(); sprintf(work_string,"Lighting [%s]: Ambient=%d, Infinite=%d, Point=%d, Spot=%d, Zsort [%s]", ((lighting_mode == 1) ? "ON" : "OFF"), lights[AMBIENT_LIGHT_INDEX].state, lights[INFINITE_LIGHT_INDEX].state, lights[POINT_LIGHT_INDEX].state, lights[SPOT_LIGHT2_INDEX].state, ((zsort_mode == 1) ? "ON" : "OFF")); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16, RGB(0,255,0), lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press <H> for Help.", 0, 0, RGB(0,255,0), lpddsback); // should we display help int text_y = 16; if (help_mode==1) { // draw help menu Draw_Text_GDI("<A>..............Toggle ambient light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<I>..............Toggle infinite light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<P>..............Toggle point light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<S>..............Toggle spot light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<N>..............Next object.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<W>..............Toggle wire frame/solid mode.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<S>..............Toggle Z sorting.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<H>..............Toggle Help.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<ESC>............Exit demo.", 0, text_y+=12, RGB(255,255,255), lpddsback); } // end help sprintf(work_string,"Polys Rendered: %d, Polys lit: %d, Object Pre-Culled by BHV: %d, Nodes visited in BHV Tree: %d", debug_polys_rendered_per_frame, debug_polys_lit_per_frame, NUM_SCENE_OBJECTS - objects_processed, bhv_nodes_visited); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16-16, RGB(0,255,0), lpddsback); sprintf(work_string,"CAM [%5.2f, %5.2f, %5.2f]", cam.pos.x, cam.pos.y, cam.pos.z); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16-16-16, RGB(0,255,0), lpddsback); // flip the surfaces DDraw_Flip2(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix // these are used to create a circling camera static float view_angle = 0; static float camera_distance = 6000; static VECTOR4D pos = {0,0,0,0}; static float tank_speed; static float turning = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = 1; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface //DDraw_Fill_Surface(lpddsback, 0); #if 1 // draw the sky //Draw_Rectangle(0,0, WINDOW_WIDTH-1, WINDOW_HEIGHT/2, 166, lpddsback); //Draw_Rectangle(0,WINDOW_HEIGHT/2, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, rgblookup[RGB16Bit565(115,42,16)], lpddsback); //Draw_Rectangle(0,0, WINDOW_WIDTH-1, WINDOW_HEIGHT/2, rgblookup[RGB16Bit565(0,140,192)], lpddsback); //Draw_Rectangle(0,0, WINDOW_WIDTH-1, WINDOW_HEIGHT/2, RGB16Bit(0,140,192), lpddsback); Draw_Rectangle(0,0, WINDOW_WIDTH, WINDOW_HEIGHT/2, RGB16Bit(0,35,50), lpddsback); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT/2, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, 28, lpddsback); //Draw_Rectangle(0,WINDOW_HEIGHT/2, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, rgblookup[RGB16Bit565(115,42,16)], lpddsback); //Draw_Rectangle(0,WINDOW_HEIGHT/2, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, RGB16Bit(103,62,3), lpddsback); Draw_Rectangle(0,WINDOW_HEIGHT/2-1, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(20,12,0), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV2(&rend_list); // allow user to move camera // turbo if (keyboard_state[DIK_SPACE]) tank_speed = 5*TANK_SPEED; else tank_speed = TANK_SPEED; // forward/backward if (keyboard_state[DIK_UP]) { // move forward cam.pos.x += tank_speed*Fast_Sin(cam.dir.y); cam.pos.z += tank_speed*Fast_Cos(cam.dir.y); } // end if if (keyboard_state[DIK_DOWN]) { // move backward cam.pos.x -= tank_speed*Fast_Sin(cam.dir.y); cam.pos.z -= tank_speed*Fast_Cos(cam.dir.y); } // end if // rotate if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=3; // add a little turn to object if ((turning+=2) > 25) turning=25; } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=3; // add a little turn to object if ((turning-=2) < -25) turning=-25; } // end if else // center heading again { if (turning > 0) turning-=1; else if (turning < 0) turning+=1; } // end else // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // backface removal if (keyboard_state[DIK_B]) { // toggle backface removal backface_mode = -backface_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights[AMBIENT_LIGHT_INDEX].state == LIGHTV1_STATE_ON) lights[AMBIENT_LIGHT_INDEX].state = LIGHTV1_STATE_OFF; else lights[AMBIENT_LIGHT_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights[INFINITE_LIGHT_INDEX].state == LIGHTV1_STATE_ON) lights[INFINITE_LIGHT_INDEX].state = LIGHTV1_STATE_OFF; else lights[INFINITE_LIGHT_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights[POINT_LIGHT_INDEX].state == LIGHTV1_STATE_ON) lights[POINT_LIGHT_INDEX].state = LIGHTV1_STATE_OFF; else lights[POINT_LIGHT_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle spot light if (keyboard_state[DIK_S]) { // toggle spot light if (lights[SPOT_LIGHT2_INDEX].state == LIGHTV1_STATE_ON) lights[SPOT_LIGHT2_INDEX].state = LIGHTV1_STATE_OFF; else lights[SPOT_LIGHT2_INDEX].state = LIGHTV1_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_Z]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if static float plight_ang = 0, slight_ang = 0; // angles for light motion // move point light source in ellipse around game world lights[POINT_LIGHT_INDEX].pos.x = 4000*Fast_Cos(plight_ang); lights[POINT_LIGHT_INDEX].pos.y = 200; lights[POINT_LIGHT_INDEX].pos.z = 4000*Fast_Sin(plight_ang); if ((plight_ang+=3) > 360) plight_ang = 0; // move spot light source in ellipse around game world lights[SPOT_LIGHT2_INDEX].pos.x = 2000*Fast_Cos(slight_ang); lights[SPOT_LIGHT2_INDEX].pos.y = 200; lights[SPOT_LIGHT2_INDEX].pos.z = 2000*Fast_Sin(slight_ang); if ((slight_ang-=5) < 0) slight_ang = 360; // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // insert the player into the world // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_player); // set position of tank obj_player.world_pos.x = cam.pos.x+300*Fast_Sin(cam.dir.y); obj_player.world_pos.y = cam.pos.y-70; obj_player.world_pos.z = cam.pos.z+300*Fast_Cos(cam.dir.y); // generate rotation matrix around y axis static int turn=0; Build_XYZ_Rotation_MATRIX4X4(1, cam.dir.y+turning, 2, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_player, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_player, TRANSFORM_TRANS_ONLY); //Light_OBJECT4DV2_World16(&obj_player, &cam, lights, 4); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_player,0); #if 1 ////////////////////////////////////////////////////////// // insert the tanks in the world for (index = 0; index < NUM_TANKS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_tank); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(0, tanks[index].w, 0, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_tank, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // set position of tank obj_tank.world_pos.x = tanks[index].x; obj_tank.world_pos.y = tanks[index].y; obj_tank.world_pos.z = tanks[index].z; // attempt to cull object if (!Cull_OBJECT4DV2(&obj_tank, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV2(&obj_tank, TRANSFORM_TRANS_ONLY); //Light_OBJECT4DV2_World16(&obj_tank, &cam, lights, 4); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_tank,0); } // end if } // end for //////////////////////////////////////////////////////// // insert the towers in the world for (index = 0; index < NUM_TOWERS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_tower); // set position of tower obj_tower.world_pos.x = towers[index].x; obj_tower.world_pos.y = towers[index].y; obj_tower.world_pos.z = towers[index].z; // attempt to cull object if (!Cull_OBJECT4DV2(&obj_tower, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV2(&obj_tower); //Light_OBJECT4DV2_World16(&obj_tower, &cam, lights, 4); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_tower,0); } // end if } // end for /////////////////////////////////////////////////////////////// // seed number generator so that modulation of markers is always the same srand(13); static int mcount = 0, mdir = 2; mcount+=mdir; if (mcount > 200 || mcount < -200) { mdir=-mdir; mcount+=mdir; } // insert the ground markers into the world for (int index_x = 0; index_x < NUM_POINTS_X; index_x++) for (int index_z = 0; index_z < NUM_POINTS_Z; index_z++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_marker); // set position of tower obj_marker.world_pos.x = RAND_RANGE(-100,100)-UNIVERSE_RADIUS+index_x*POINT_SIZE; obj_marker.world_pos.y = obj_marker.max_radius[0] + 50*Fast_Sin(index_x*10+Fast_Sin(index_z)+mcount); obj_marker.world_pos.z = RAND_RANGE(-100,100)-UNIVERSE_RADIUS+index_z*POINT_SIZE; // attempt to cull object if (!Cull_OBJECT4DV2(&obj_marker, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV2(&obj_marker); //Light_OBJECT4DV2_World16(&obj_marker, &cam, lights, 4); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_marker,0); } // end if } // end for //////////////////////////////////////////////////////////////////////// #endif // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // light scene all at once if (lighting_mode==1) Light_RENDERLIST4DV2_World16(&rend_list, &cam, lights, 4); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); sprintf(work_string,"pos:[%f, %f, %f] heading:[%f] elev:[%f], polys[%d]", cam.pos.x, cam.pos.y, cam.pos.z, cam.dir.y, cam.dir.x, debug_polys_rendered_per_frame); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-20, RGB(0,255,0), lpddsback); sprintf(work_string,"Lighting [%s]: Ambient=%d, Infinite=%d, Point=%d, Spot=%d | Zsort [%s], BckFceRM [%s]", ((lighting_mode == 1) ? "ON" : "OFF"), lights[AMBIENT_LIGHT_INDEX].state, lights[INFINITE_LIGHT_INDEX].state, lights[POINT_LIGHT_INDEX].state, lights[SPOT_LIGHT2_INDEX].state, ((zsort_mode == 1) ? "ON" : "OFF"), ((backface_mode == 1) ? "ON" : "OFF")); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34, RGB(0,255,0), lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press <H> for Help.", 0, 0, RGB(0,255,0), lpddsback); // should we display help int text_y = 16; if (help_mode==1) { // draw help menu Draw_Text_GDI("<A>..............Toggle ambient light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<I>..............Toggle infinite light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<P>..............Toggle point light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<S>..............Toggle spot light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<W>..............Toggle wire frame/solid mode.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<B>..............Toggle backface removal.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<RIGHT ARROW>....Rotate player right.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<LEFT ARROW>.....Rotate player left.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<UP ARROW>.......Move player forward.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<DOWN ARROW>.....Move player backward.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<SPACE BAR>......Turbo.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<H>..............Toggle Help.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<ESC>............Exit demo.", 0, text_y+=12, RGB(255,255,255), lpddsback); } // end help // lock the back buffer DDraw_Lock_Back_Surface(); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the object if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) Draw_RENDERLIST4DV2_Solid16(&rend_list, back_buffer, back_lpitch); #endif // unlock the back buffer DDraw_Unlock_Back_Surface(); // flip the surfaces DDraw_Flip(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix static float plight_ang = 0, slight_ang = 0; // angles for light motion static float alpha_override = 0, alpha_inc = .25; // use these to rotate objects static float x_ang = 0, y_ang = 0, z_ang = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = 1; static int x_clip_mode = 1; static int y_clip_mode = 1; static int z_clip_mode = 1; static int z_buffer_mode = 1; static int display_mode = 1; static float turning = 0; static int pass_mode = 2; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface //DDraw_Fill_Surface(lpddsback, 0); // draw the sky //Draw_Rectangle(0,0, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(0,0,0), lpddsback); lpddsback->Blt(NULL, background.images[0], NULL, DDBLT_WAIT, NULL); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT*.5, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(190,190,230), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // backface removal if (keyboard_state[DIK_B]) { // toggle backface removal backface_mode = -backface_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights2[AMBIENT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights2[INFINITE_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights2[POINT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle spot light if (keyboard_state[DIK_S]) { // toggle spot light if (lights2[SPOT_LIGHT2_INDEX].state == LIGHTV2_STATE_ON) lights2[SPOT_LIGHT2_INDEX].state = LIGHTV2_STATE_OFF; else lights2[SPOT_LIGHT2_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // reflection pass mode if (keyboard_state[DIK_N]) { // toggle help menu if (++pass_mode > 2) pass_mode = 0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_S]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // forward/backward if (keyboard_state[DIK_UP]) { // move forward if ( (cam_speed+=1) > MAX_SPEED) cam_speed = MAX_SPEED; } // end if else if (keyboard_state[DIK_DOWN]) { // move backward if ((cam_speed-=1) < -MAX_SPEED) cam_speed = -MAX_SPEED; } // end if // rotate if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=3; // add a little turn to object if ((turning+=2) > 25) turning=25; } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=3; // add a little turn to object if ((turning-=2) < -25) turning=-25; } // end if else // center heading again { if (turning > 0) turning-=1; else if (turning < 0) turning+=1; } // end else // decelerate camera if (cam_speed > (CAM_DECEL) ) cam_speed-=CAM_DECEL; else if (cam_speed < (-CAM_DECEL) ) cam_speed+=CAM_DECEL; else cam_speed = 0; // move camera cam.pos.x += cam_speed*Fast_Sin(cam.dir.y); cam.pos.y = 200; cam.pos.z += cam_speed*Fast_Cos(cam.dir.y); // move point light source in ellipse around game world lights2[POINT_LIGHT_INDEX].pos.x = 1000*Fast_Cos(plight_ang); lights2[POINT_LIGHT_INDEX].pos.y = 100; lights2[POINT_LIGHT_INDEX].pos.z = 1000*Fast_Sin(plight_ang); if ((plight_ang+=3) > 360) plight_ang = 0; // move spot light source in ellipse around game world lights2[SPOT_LIGHT2_INDEX].pos.x = 1000*Fast_Cos(slight_ang); lights2[SPOT_LIGHT2_INDEX].pos.y = 200; lights2[SPOT_LIGHT2_INDEX].pos.z = 1000*Fast_Sin(slight_ang); if ((slight_ang-=5) < 0) slight_ang = 360; // update rotation angles if ((x_ang+=.2) > 360) x_ang = 0; if ((y_ang+=.4) > 360) y_ang = 0; if ((z_ang+=.8) > 360) z_ang = 0; // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // lock the back buffer DDraw_Lock_Back_Surface(); // render the terrain first ///////////////////////////////// if (pass_mode >= 0) { // reset the render list Reset_RENDERLIST4DV2(&rend_list); // rotate the local coords of the object MAT_IDENTITY_4X4(&mrot); Transform_OBJECT4DV2(&obj_terrain, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_terrain, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_terrain,0); // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, ((x_clip_mode == 1) ? CLIP_POLY_X_PLANE : 0) | ((y_clip_mode == 1) ? CLIP_POLY_Y_PLANE : 0) | ((z_clip_mode == 1) ? CLIP_POLY_Z_PLANE : 0) ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // // get an identity matrix // MAT_IDENTITY_4X4(&mrot); // mrot.M11 = -1; // transform the rendering list by x-z plane reflection matrix Transform_RENDERLIST4DV2(&rend_list, &mrot, TRANSFORM_TRANS_ONLY); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the renderinglist if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // initialize zbuffer to 16000 fixed point Clear_Zbuffer(&zbuffer, (16000 << FIXP16_SHIFT)); // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER | RENDER_ATTR_ALPHA //| RENDER_ATTR_MIPMAP //| RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 3500; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16(&rc); } // end if } // end if ////////////////////////////////////////////////////////// if (pass_mode >= 1) { // render the reflection of the objects // reset the render list Reset_RENDERLIST4DV2(&rend_list); // insert the scenery into universe for (index = 0; index < NUM_SCENE_OBJECTS; index++) { // select proper object first obj_work = &obj_array[(int)scene_objects[index].w]; // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(obj_work); // set position of tower obj_work->world_pos.x = scene_objects[index].x; obj_work->world_pos.y = scene_objects[index].y; obj_work->world_pos.z = scene_objects[index].z; // move objects scene_objects[index].x+=scene_objects_vel[index].x; scene_objects[index].y+=scene_objects_vel[index].y; scene_objects[index].z+=scene_objects_vel[index].z; // test for out of bounds if (scene_objects[index].x >= UNIVERSE_RADIUS || scene_objects[index].x <= -UNIVERSE_RADIUS) { scene_objects_vel[index].x=-scene_objects_vel[index].x; scene_objects[index].x+=scene_objects_vel[index].x; } // end if if (scene_objects[index].y >= (UNIVERSE_RADIUS/2) || scene_objects[index].y <= -(UNIVERSE_RADIUS/2)) { scene_objects_vel[index].y=-scene_objects_vel[index].y; scene_objects[index].y+=scene_objects_vel[index].y; } // end if if (scene_objects[index].z >= UNIVERSE_RADIUS || scene_objects[index].z <= -UNIVERSE_RADIUS) { scene_objects_vel[index].z=-scene_objects_vel[index].z; scene_objects[index].z+=scene_objects_vel[index].z; } // end if // attempt to cull object if (!Cull_OBJECT4DV2(obj_work, &cam, CULL_OBJECT_XYZ_PLANES)) { MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(obj_work, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(obj_work, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, obj_work,0); } // end if } // end for // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, ((x_clip_mode == 1) ? CLIP_POLY_X_PLANE : 0) | ((y_clip_mode == 1) ? CLIP_POLY_Y_PLANE : 0) | ((z_clip_mode == 1) ? CLIP_POLY_Z_PLANE : 0) ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // get an identity matrix MAT_IDENTITY_4X4(&mrot); mrot.M11 = -1; mrot.M31 = -450; // transform the rendering list by x-z plane reflection matrix Transform_RENDERLIST4DV2(&rend_list, &mrot, TRANSFORM_TRANS_ONLY); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the renderinglist if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // set up rendering context rc.attr = RENDER_ATTR_NOBUFFER | RENDER_ATTR_ALPHA //| RENDER_ATTR_MIPMAP //| RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 3500; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = 1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16(&rc); } // end if } // end if ////////////////////////////////////////////////////////// if (pass_mode >= 2) { // render the objects now // reset the render list Reset_RENDERLIST4DV2(&rend_list); // insert the scenery into universe for (index = 0; index < NUM_SCENE_OBJECTS; index++) { // select proper object first obj_work = &obj_array[(int)scene_objects[index].w]; // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(obj_work); // set position of tower obj_work->world_pos.x = scene_objects[index].x; obj_work->world_pos.y = scene_objects[index].y; obj_work->world_pos.z = scene_objects[index].z; // move objects scene_objects[index].x+=scene_objects_vel[index].x; scene_objects[index].y+=scene_objects_vel[index].y; scene_objects[index].z+=scene_objects_vel[index].z; // test for out of bounds if (scene_objects[index].x >= UNIVERSE_RADIUS || scene_objects[index].x <= -UNIVERSE_RADIUS) { scene_objects_vel[index].x=-scene_objects_vel[index].x; scene_objects[index].x+=scene_objects_vel[index].x; } // end if if (scene_objects[index].y >= (UNIVERSE_RADIUS/2) || scene_objects[index].y <= -(UNIVERSE_RADIUS/2)) { scene_objects_vel[index].y=-scene_objects_vel[index].y; scene_objects[index].y+=scene_objects_vel[index].y; } // end if if (scene_objects[index].z >= UNIVERSE_RADIUS || scene_objects[index].z <= -UNIVERSE_RADIUS) { scene_objects_vel[index].z=-scene_objects_vel[index].z; scene_objects[index].z+=scene_objects_vel[index].z; } // end if // attempt to cull object if (!Cull_OBJECT4DV2(obj_work, &cam, CULL_OBJECT_XYZ_PLANES)) { MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(obj_work, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(obj_work, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, obj_work,0); } // end if } // end for // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, ((x_clip_mode == 1) ? CLIP_POLY_X_PLANE : 0) | ((y_clip_mode == 1) ? CLIP_POLY_Y_PLANE : 0) | ((z_clip_mode == 1) ? CLIP_POLY_Z_PLANE : 0) ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // get an identity matrix //MAT_IDENTITY_4X4(&mrot); //mrot.M11 = -1; mrot.M31 = -400; // transform the rendering list by x-z plane reflection matrix Transform_RENDERLIST4DV2(&rend_list, &mrot, TRANSFORM_TRANS_ONLY); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the renderinglist if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER | RENDER_ATTR_ALPHA //| RENDER_ATTR_MIPMAP //| RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 3500; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16(&rc); } // end if } // end if // unlock the back buffer DDraw_Unlock_Back_Surface(); sprintf(work_string,"Lighting [%s]: Ambient=%d, Infinite=%d, Point=%d, Spot=%d, BckFceRM [%s], Zsort [%s]", ((lighting_mode == 1) ? "ON" : "OFF"), lights[AMBIENT_LIGHT_INDEX].state, lights[INFINITE_LIGHT_INDEX].state, lights[POINT_LIGHT_INDEX].state, lights[SPOT_LIGHT2_INDEX].state, ((backface_mode == 1) ? "ON" : "OFF"), ((zsort_mode == 1) ? "ON" : "OFF")); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16, RGB(0,255,0), lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press <H> for Help.", 0, 0, RGB(0,255,0), lpddsback); // should we display help int text_y = 16; if (help_mode==1) { // draw help menu Draw_Text_GDI("<A>..............Toggle ambient light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<I>..............Toggle infinite light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<P>..............Toggle point light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<S>..............Toggle spot light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<N>..............Enable next rendering pass.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<W>..............Toggle wire frame/solid mode.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<B>..............Toggle backface removal.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<S>..............Toggle Z sorting.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<H>..............Toggle Help.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<ESC>............Exit demo.", 0, text_y+=12, RGB(255,255,255), lpddsback); } // end help sprintf(work_string,"Polys Rendered: %d, Polys lit: %d", debug_polys_rendered_per_frame, debug_polys_lit_per_frame); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16-16, RGB(0,255,0), lpddsback); sprintf(work_string,"CAM [%5.2f, %5.2f, %5.2f]", cam.pos.x, cam.pos.y, cam.pos.z); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16-16-16, RGB(0,255,0), lpddsback); // flip the surfaces DDraw_Flip2(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix static float plight_ang = 0, slight_ang = 0; // angles for light motion // use these to rotate objects static float x_ang = 0, y_ang = 0, z_ang = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = 1; static int x_clip_mode = 1; static int y_clip_mode = 1; static int z_clip_mode = 1; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface DDraw_Fill_Surface(lpddsback, 0); // draw the sky Draw_Rectangle(0,0, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(255,120,255), lpddsback); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT*.38, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(25,50,110), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV2(&rend_list); // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // backface removal if (keyboard_state[DIK_B]) { // toggle backface removal backface_mode = -backface_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights2[AMBIENT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights2[INFINITE_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights2[POINT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; // toggle point light if (lights2[POINT_LIGHT2_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT2_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT2_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_Z]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // move to next object if (keyboard_state[DIK_O]) { VECTOR4D old_pos; old_pos = obj_work->world_pos; if (++curr_object >= NUM_OBJECTS) curr_object = 0; // update pointer obj_work = &obj_array[curr_object]; obj_work->world_pos = old_pos; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // forward/backward if (keyboard_state[DIK_UP]) { // move forward if ( (cam_speed+=1) > MAX_SPEED) cam_speed = MAX_SPEED; } // end if else if (keyboard_state[DIK_DOWN]) { // move backward if ((cam_speed-=1) < -MAX_SPEED) cam_speed = -MAX_SPEED; } // end if // rotate around y axis or yaw if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=5; } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=5; } // end if // motion section ///////////////////////////////////////////////////////// // terrain following, simply find the current cell we are over and then // index into the vertex list and find the 4 vertices that make up the // quad cell we are hovering over and then average the values, and based // on the current height and the height of the terrain push the player upward // the terrain generates and stores some results to help with terrain following //ivar1 = columns; //ivar2 = rows; //fvar1 = col_vstep; //fvar2 = row_vstep; int cell_x = (cam.pos.x + TERRAIN_WIDTH/2) / obj_terrain.fvar1; int cell_y = (cam.pos.z + TERRAIN_HEIGHT/2) / obj_terrain.fvar1; static float terrain_height, delta; // test if we are on terrain if ( (cell_x >=0) && (cell_x < obj_terrain.ivar1) && (cell_y >=0) && (cell_y < obj_terrain.ivar2) ) { // compute vertex indices into vertex list of the current quad int v0 = cell_x + cell_y*obj_terrain.ivar2; int v1 = v0 + 1; int v2 = v1 + obj_terrain.ivar2; int v3 = v0 + obj_terrain.ivar2; // now simply index into table terrain_height = 0.25 * (obj_terrain.vlist_trans[v0].y + obj_terrain.vlist_trans[v1].y + obj_terrain.vlist_trans[v2].y + obj_terrain.vlist_trans[v3].y); // compute height difference delta = terrain_height - (cam.pos.y - gclearance); // test for penetration if (delta > 0) { // apply force immediately to camera (this will give it a springy feel) vel_y+=(delta * (VELOCITY_SCALER)); // test for pentration, if so move up immediately so we don't penetrate geometry cam.pos.y+=(delta*CAM_HEIGHT_SCALER); // now this is more of a hack than the physics model :) let move the front // up and down a bit based on the forward velocity and the gradient of the // hill cam.dir.x -= (delta*PITCH_CHANGE_RATE); } // end if } // end if // decelerate camera if (cam_speed > (CAM_DECEL) ) cam_speed-=CAM_DECEL; else if (cam_speed < (-CAM_DECEL) ) cam_speed+=CAM_DECEL; else cam_speed = 0; // force camera to seek a stable orientation if (cam.dir.x > (neutral_pitch+PITCH_RETURN_RATE)) cam.dir.x -= (PITCH_RETURN_RATE); else if (cam.dir.x < (neutral_pitch-PITCH_RETURN_RATE)) cam.dir.x += (PITCH_RETURN_RATE); else cam.dir.x = neutral_pitch; // apply gravity vel_y+=gravity; // test for absolute sea level and push upward.. if (cam.pos.y < sea_level) { vel_y = 0; cam.pos.y = sea_level; } // end if // move camera cam.pos.x += cam_speed*Fast_Sin(cam.dir.y); cam.pos.z += cam_speed*Fast_Cos(cam.dir.y); cam.pos.y += vel_y; // move point light source in ellipse around game world lights2[POINT_LIGHT_INDEX].pos.x = 1000*Fast_Cos(plight_ang); lights2[POINT_LIGHT_INDEX].pos.y = 200; lights2[POINT_LIGHT_INDEX].pos.z = 1000*Fast_Sin(plight_ang); // move point light source in ellipse around game world lights2[POINT_LIGHT2_INDEX].pos.x = 500*Fast_Cos(-2*plight_ang); lights2[POINT_LIGHT2_INDEX].pos.y = 400; lights2[POINT_LIGHT2_INDEX].pos.z = 1000*Fast_Sin(-2*plight_ang); if ((plight_ang+=3) > 360) plight_ang = 0; // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); ////////////////////////////////////////////////////////////////////////// // the terrain // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_terrain); // generate rotation matrix around y axis //Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_terrain, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_terrain, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_terrain,0); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // render the shaded object that projects the shadow // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(obj_work); // update rotation angle of object obj_work->ivar1+=3.0; if (obj_work->ivar1 >= 360) obj_work->ivar1 = 0; // set position of object obj_work->world_pos.x = 200*Fast_Cos(obj_work->ivar1); obj_work->world_pos.y = 200+50*Fast_Sin(3*obj_work->ivar1); obj_work->world_pos.z = 200*Fast_Sin(obj_work->ivar1); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); // rotate the local coords of the object Transform_OBJECT4DV2(obj_work, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(obj_work, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, obj_work,0); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // draw all the light objects to represent the position of light sources // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_light_array[INDEX_GREEN_LIGHT_INDEX]); // set position of object to light obj_light_array[INDEX_GREEN_LIGHT_INDEX].world_pos = lights2[POINT_LIGHT_INDEX].pos; // create identity matrix MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_light_array[INDEX_GREEN_LIGHT_INDEX], &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_light_array[INDEX_GREEN_LIGHT_INDEX], TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_light_array[INDEX_GREEN_LIGHT_INDEX],0); // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_light_array[INDEX_WHITE_LIGHT_INDEX]); // set position of object to light obj_light_array[INDEX_WHITE_LIGHT_INDEX].world_pos = lights2[POINT_LIGHT2_INDEX].pos; // create identity matrix MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_light_array[INDEX_WHITE_LIGHT_INDEX], &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_light_array[INDEX_WHITE_LIGHT_INDEX], TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_light_array[INDEX_WHITE_LIGHT_INDEX],0); //////////////////////////////////////////////////////////////////////////////////// // reset number of polys rendered debug_polys_rendered_per_frame = 0; debug_polys_lit_per_frame = 0; // prepare to make first pass at rendering target, so we can alpha blend in the shadows // on the next pass // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, CLIP_POLY_X_PLANE | CLIP_POLY_Y_PLANE | CLIP_POLY_Z_PLANE ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // lock the back buffer DDraw_Lock_Back_Surface(); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the object if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // perspective mode affine texturing // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER // | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; // initialize zbuffer to 0 fixed point Clear_Zbuffer(&zbuffer, (16000 << FIXP16_SHIFT)); // set up remainder of rendering context rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 0; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16_2(&rc); } // end if // now make second rendering pass and draw shadow(s) // reset the render list Reset_RENDERLIST4DV2(&rend_list); ////////////////////////////////////////////////////////////////////////// // shadow object // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&shadow_obj); // compute terrain cell shadow is over cell_x = (obj_work->world_pos.x + TERRAIN_WIDTH/2) / obj_terrain.fvar1; cell_y = (obj_work->world_pos.z + TERRAIN_HEIGHT/2) / obj_terrain.fvar1; // compute vertex indices into vertex list of the current quad int v0 = cell_x + cell_y*obj_terrain.ivar2; int v1 = v0 + 1; int v2 = v1 + obj_terrain.ivar2; int v3 = v0 + obj_terrain.ivar2; // now simply index into table terrain_height = MAX( MAX(obj_terrain.vlist_trans[v0].y, obj_terrain.vlist_trans[v1].y), MAX(obj_terrain.vlist_trans[v2].y, obj_terrain.vlist_trans[v3].y) ); // update position shadow_obj.world_pos = obj_work->world_pos; shadow_obj.world_pos.y = terrain_height+10; // create identity matrix MAT_IDENTITY_4X4(&mrot); // transform the local coords of the object Transform_OBJECT4DV2(&shadow_obj, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&shadow_obj, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &shadow_obj,0); ////////////////////////////////////////////////////////////////////////// // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, CLIP_POLY_X_PLANE | CLIP_POLY_Y_PLANE | CLIP_POLY_Z_PLANE ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // render the object if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // perspective mode affine texturing // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; // initialize zbuffer to 0 fixed point //Clear_Zbuffer(&zbuffer, (16000 << FIXP16_SHIFT)); // set up remainder of rendering context rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 0; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16_3(&rc); } // end if // unlock the back buffer DDraw_Unlock_Back_Surface(); // draw cockpit //Draw_BOB16(&cockpit, lpddsback); #if 1 sprintf(work_string,"Lighting [%s]: Ambient=%d, Infinite=%d, Point=%d, BckFceRM [%s]", ((lighting_mode == 1) ? "ON" : "OFF"), lights2[AMBIENT_LIGHT_INDEX].state, lights2[INFINITE_LIGHT_INDEX].state, lights2[POINT_LIGHT_INDEX].state, ((backface_mode == 1) ? "ON" : "OFF")); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34, RGB(0,255,0), lpddsback); // draw instructions Draw_Text_GDI("Press ESC to exit. Press <H> for Help.", 0, 0, RGB(0,255,0), lpddsback); // should we display help int text_y = 16; if (help_mode==1) { // draw help menu Draw_Text_GDI("<A>..............Toggle ambient light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<I>..............Toggle infinite light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<P>..............Toggle point light source.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<W>..............Toggle wire frame/solid mode.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<B>..............Toggle backface removal.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<O>..............Select different objects.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<H>..............Toggle Help.", 0, text_y+=12, RGB(255,255,255), lpddsback); Draw_Text_GDI("<ESC>............Exit demo.", 0, text_y+=12, RGB(255,255,255), lpddsback); } // end help sprintf(work_string,"Polys Rendered: %d, Polys lit: %d", debug_polys_rendered_per_frame, debug_polys_lit_per_frame); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16-16, RGB(0,255,0), lpddsback); sprintf(work_string,"CAM [%5.2f, %5.2f, %5.2f], CELL [%d, %d]", cam.pos.x, cam.pos.y, cam.pos.z, cell_x, cell_y); Draw_Text_GDI(work_string, 0, WINDOW_HEIGHT-34-16-16-16, RGB(0,255,0), lpddsback); #endif // flip the surfaces DDraw_Flip2(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix static float plight_ang = 0, slight_ang = 0; // angles for light motion // use these to rotate objects static float x_ang = 0, y_ang = 0, z_ang = 0; // state variables for different rendering modes and help static int wireframe_mode = 1; static int backface_mode = 1; static int lighting_mode = 1; static int help_mode = 1; static int zsort_mode = 1; static int x_clip_mode = 1; static int y_clip_mode = 1; static int z_clip_mode = 1; static int z_buffer_mode = 0; static int display_mode = 1; static char *z_buffer_modes[3] = {"Z Buffering", "1/Z Buffering", "NO buffering"}; char work_string[256]; // temp string int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface //DDraw_Fill_Surface(lpddsback, 0); // draw the sky //Draw_Rectangle(0,0, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(250,190,80), lpddsback); lpddsback->Blt(NULL, background.images[0], NULL, DDBLT_WAIT, NULL); // draw the ground //Draw_Rectangle(0,WINDOW_HEIGHT*.5, WINDOW_WIDTH, WINDOW_HEIGHT, RGB16Bit(190,190,230), lpddsback); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the render list Reset_RENDERLIST4DV2(&rend_list); // modes and lights // wireframe mode if (keyboard_state[DIK_W]) { // toggle wireframe mode if (++wireframe_mode > 1) wireframe_mode=0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // backface removal if (keyboard_state[DIK_B]) { // toggle backface removal backface_mode = -backface_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // lighting if (keyboard_state[DIK_L]) { // toggle lighting engine completely lighting_mode = -lighting_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle ambient light if (keyboard_state[DIK_A]) { // toggle ambient light if (lights2[AMBIENT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[AMBIENT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle infinite light if (keyboard_state[DIK_I]) { // toggle ambient light if (lights2[INFINITE_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[INFINITE_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle point light if (keyboard_state[DIK_P]) { // toggle point light if (lights2[POINT_LIGHT_INDEX].state == LIGHTV2_STATE_ON) lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_OFF; else lights2[POINT_LIGHT_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // toggle spot light if (keyboard_state[DIK_S]) { // toggle spot light if (lights2[SPOT_LIGHT2_INDEX].state == LIGHTV2_STATE_ON) lights2[SPOT_LIGHT2_INDEX].state = LIGHTV2_STATE_OFF; else lights2[SPOT_LIGHT2_INDEX].state = LIGHTV2_STATE_ON; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // help menu if (keyboard_state[DIK_H]) { // toggle help menu help_mode = -help_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z-sorting if (keyboard_state[DIK_S]) { // toggle z sorting zsort_mode = -zsort_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // z buffer // 0 - z buffer // 1 - 1/z buffer // 2 - no buffer if (keyboard_state[DIK_Z]) { // toggle z buffer if (++z_buffer_mode > 2) z_buffer_mode = 0; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // display mode if (keyboard_state[DIK_D]) { // toggle display mode display_mode = -display_mode; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // forward/backward if (keyboard_state[DIK_UP]) { // move forward if ( (cam_speed+=1) > MAX_SPEED) cam_speed = MAX_SPEED; } // end if else if (keyboard_state[DIK_DOWN]) { // move backward if ((cam_speed-=1) < -MAX_SPEED) cam_speed = -MAX_SPEED; } // end if // rotate around y axis or yaw if (keyboard_state[DIK_RIGHT]) { cam.dir.y+=5; } // end if if (keyboard_state[DIK_LEFT]) { cam.dir.y-=5; } // end if // move to next object if (keyboard_state[DIK_N]) { if (++curr_object >= NUM_OBJECTS) curr_object = 0; // update pointer obj_work = &obj_array[curr_object]; Wait_Clock(100); // wait, so keyboard doesn't bounce } // end if // decelerate camera if (cam_speed > (CAM_DECEL) ) cam_speed-=CAM_DECEL; else if (cam_speed < (-CAM_DECEL) ) cam_speed+=CAM_DECEL; else cam_speed = 0; // move camera cam.pos.x += cam_speed*Fast_Sin(cam.dir.y); cam.pos.z += cam_speed*Fast_Cos(cam.dir.y); // move point light source in ellipse around game world lights2[POINT_LIGHT_INDEX].pos.x = 1000*Fast_Cos(plight_ang); lights2[POINT_LIGHT_INDEX].pos.y = 100; lights2[POINT_LIGHT_INDEX].pos.z = 1000*Fast_Sin(plight_ang); if ((plight_ang+=3) > 360) plight_ang = 0; // move spot light source in ellipse around game world lights2[SPOT_LIGHT2_INDEX].pos.x = 1000*Fast_Cos(slight_ang); lights2[SPOT_LIGHT2_INDEX].pos.y = 200; lights2[SPOT_LIGHT2_INDEX].pos.z = 1000*Fast_Sin(slight_ang); if ((slight_ang-=5) < 0) slight_ang = 360; obj_work->world_pos.x = cam.pos.x + 150*Fast_Sin(cam.dir.y); obj_work->world_pos.y = cam.pos.y + 0; obj_work->world_pos.z = cam.pos.z + 150*Fast_Cos(cam.dir.y); // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); //////////////////////////////////////////////////////// // insert the scenery into universe for (index = 0; index < NUM_SCENE_OBJECTS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(&obj_scene); // set position of tower obj_scene.world_pos.x = scene_objects[index].x; obj_scene.world_pos.y = scene_objects[index].y; obj_scene.world_pos.z = scene_objects[index].z; // attempt to cull object if (!Cull_OBJECT4DV2(&obj_scene, &cam, CULL_OBJECT_XYZ_PLANES)) { MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(&obj_scene, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(&obj_scene, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_scene,0); } // end if } // end for /////////////////////////////////////////////////////////////// // insert the player object into universe // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV2(obj_work); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(x_ang, cam.dir.y + y_ang, z_ang, &mrot); //MAT_IDENTITY_4X4(&mrot); // rotate the local coords of the object Transform_OBJECT4DV2(obj_work, &mrot, TRANSFORM_LOCAL_TO_TRANS,1); // perform world transform Model_To_World_OBJECT4DV2(obj_work, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, obj_work,0); // update rotation angles if ((x_ang+=.2) > 360) x_ang = 0; if ((y_ang+=.4) > 360) y_ang = 0; if ((z_ang+=.8) > 360) z_ang = 0; // reset number of polys rendered debug_polys_rendered_per_frame = 0; debug_polys_lit_per_frame = 0; // remove backfaces if (backface_mode==1) Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV2(&rend_list, &cam); // clip the polygons themselves now Clip_Polys_RENDERLIST4DV2(&rend_list, &cam, ((x_clip_mode == 1) ? CLIP_POLY_X_PLANE : 0) | ((y_clip_mode == 1) ? CLIP_POLY_Y_PLANE : 0) | ((z_clip_mode == 1) ? CLIP_POLY_Z_PLANE : 0) ); // light scene all at once if (lighting_mode==1) { Transform_LIGHTSV2(lights2, 4, &cam.mcam, TRANSFORM_LOCAL_TO_TRANS); Light_RENDERLIST4DV2_World2_16(&rend_list, &cam, lights2, 4); } // end if // sort the polygon list (hurry up!) if (zsort_mode == 1) Sort_RENDERLIST4DV2(&rend_list, SORT_POLYLIST_AVGZ); // apply camera to perspective transformation Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam); // apply screen transform Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam); // lock the back buffer DDraw_Lock_Back_Surface(); // reset number of polys rendered debug_polys_rendered_per_frame = 0; // render the renderinglist if (wireframe_mode == 0) Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch); else if (wireframe_mode == 1) { // z buffer mode if (z_buffer_mode == 0) { // initialize zbuffer to 16000 fixed point Clear_Zbuffer(&zbuffer, (16000 << FIXP16_SHIFT)); // set up rendering context rc.attr = RENDER_ATTR_ZBUFFER // | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; } // end if else // 1/z buffer mode if (z_buffer_mode == 1) { // initialize 1/z buffer to 0 fixed point Clear_Zbuffer(&zbuffer, (0 << FIXP16_SHIFT)); // set up rendering context rc.attr = RENDER_ATTR_INVZBUFFER // | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; } // end if else // no buffering mode if (z_buffer_mode == 2) { // set up rendering context rc.attr = RENDER_ATTR_NOBUFFER // | RENDER_ATTR_ALPHA // | RENDER_ATTR_MIPMAP // | RENDER_ATTR_BILERP | RENDER_ATTR_TEXTURE_PERSPECTIVE_AFFINE; } // end if // set up remainder of rendering context rc.video_buffer = back_buffer; rc.lpitch = back_lpitch; rc.mip_dist = 4500; rc.zbuffer = (UCHAR *)zbuffer.zbuffer; rc.zpitch = WINDOW_WIDTH*4; rc.rend_list = &rend_list; rc.texture_dist = 0; rc.alpha_override = -1; // render scene Draw_RENDERLIST4DV2_RENDERCONTEXTV1_16(&rc); } // end if // display z buffer graphically (sorta) if (display_mode==-1) { // use z buffer visualization mode // copy each line of the z buffer into the back buffer and translate each z pixel // into a color USHORT *screen_ptr = (USHORT *)back_buffer; UINT *zb_ptr = (UINT *)zbuffer.zbuffer; for (int y = 0; y < WINDOW_HEIGHT; y++) { for (int x = 0; x < WINDOW_WIDTH; x++) { // z buffer is 32 bit, so be carefull UINT zpixel = zb_ptr[x + y*WINDOW_WIDTH]; zpixel = (zpixel/4096 & 0xffff); screen_ptr[x + y* (back_lpitch >> 1)] = (USHORT)zpixel; } // end for } // end for y } // end if
int Game_Main(void *parms) { // this is the workhorse of your game it will be called // continuously in real-time this is like main() in C // all the calls for you game go here! static MATRIX4X4 mrot; // general rotation matrix static float x_ang = 0, y_ang = 2, z_ang = 0; int index; // looping var // start the timing clock Start_Clock(); // clear the drawing surface DDraw_Fill_Surface(lpddsback, 0); // read keyboard and other devices here DInput_Read_Keyboard(); // game logic here... // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj); // reset angles x_ang = z_ang = 0; // is user trying to rotate if (KEY_DOWN(VK_DOWN)) x_ang = 1; else if (KEY_DOWN(VK_UP)) x_ang = -1; // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(x_ang, y_ang, z_ang, &mrot); // rotate the local coords of single polygon in renderlist Transform_OBJECT4DV1(&obj, &mrot, TRANSFORM_LOCAL_ONLY,1); // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj); // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // remove backfaces Remove_Backfaces_OBJECT4DV1(&obj, &cam); // apply world to camera transform World_To_Camera_OBJECT4DV1(&obj, &cam); // apply camera to perspective transformation Camera_To_Perspective_OBJECT4DV1(&obj, &cam); // apply screen transform Perspective_To_Screen_OBJECT4DV1(&obj, &cam); // draw instructions Draw_Text_GDI("Press ESC to exit. Use UP ARROW and DOWN ARROW to rotate.", 0, 0, RGB(0,255,0), lpddsback); // lock the back buffer DDraw_Lock_Back_Surface(); // render the object Draw_OBJECT4DV1_Wire16(&obj, back_buffer, back_lpitch); // unlock the back buffer DDraw_Unlock_Back_Surface(); // flip the surfaces DDraw_Flip(); // sync to 30ish fps Wait_Clock(30); // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if // return success return(1); } // end Game_Main
static void display(void) { //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); static float view_angle = 0; static float camera_distance = 6000; static VECTOR4D pos = { 0, 0, 0, 0 }; static float tank_speed; static float turning = 0; if (keyboard_state[VK_SPACE]) tank_speed = 5 * TANK_SPEED; else tank_speed = TANK_SPEED; // forward/backward if (keyboard_state['W'] || keyboard_state['w']) { // move forward cam.pos.x -= tank_speed*Fast_Sin(cam.dir.y); cam.pos.z -= tank_speed*Fast_Cos(cam.dir.y); } // end if if (keyboard_state['S'] || keyboard_state['s']) { // move backward cam.pos.x += tank_speed*Fast_Sin(cam.dir.y); cam.pos.z += tank_speed*Fast_Cos(cam.dir.y); } // end if // rotate if (keyboard_state['D'] || keyboard_state['d']) { cam.dir.y -= TANK_ROTATE_SPEED; // add a little turn to object if ((turning -= 2) < -15) turning = -15; } // end if if (keyboard_state['a'] || keyboard_state['A']) { cam.dir.y += TANK_ROTATE_SPEED; // add a little turn to object if ((turning += 2) > 15) turning = 15; } // end if else // center heading again { if (turning > 0) turning -= 1; else if (turning < 0) turning += 1; } // end else //cam.dir.y += 0.05; //if (cam.dir.y > 360) // cam.dir.y = 0; //Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); //Rotate_XYZ_OBJECT4DV1(&obj, 0, 1, 0); //Model_To_World_OBJECT4DV1(&obj); //Reset_OBJECT4DV1(&obj); //Cull_OBJECT4DV1(&obj, &cam, CULL_OBJECT_X_PLANE | CULL_OBJECT_Y_PLANE | CULL_OBJECT_Z_PLANE); //Remove_Backfaces_OBJECT4DV1(&obj, &cam); //World_To_Camera_OBJECT4DV1(&obj, &cam); //Camera_To_Perspective_Screen_OBJECT4DV1(&obj, &cam); //memset(buffer, 0, sizeof(UINT)* WINDOW_WIDTH * WINDOW_HEIGHT); for (int i = 0; i < g_width * g_height; ++i) { buffer[i] = 0;// 0xffffffff; } //Draw_OBJECT4DV1_Solid(&obj, (UCHAR *)buffer, WINDOW_WIDTH); //Draw_OBJECT4DV1_Wire(&obj, (UCHAR *)buffer, WINDOW_WIDTH); //glBindVertexArray(VAOs[VAO_1]); //glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]); //glBufferData(GL_ARRAY_BUFFER, sizeof(POINT4D)* obj.num_vertices, obj.vlist_trans, GL_DYNAMIC_DRAW); ////glDrawArrays(GL_TRIANGLES, 0, obj.num_polys); //int polys = 0; //for (int i = 0, j = 0; i < obj.num_polys; ++i) //{Z // if (!(obj.plist[i].state & POLY4DV1_STATE_ACTIVE) || (obj.plist[i].state & POLY4DV1_STATE_CLIPPED) // || (obj.plist[i].state & POLY4DV1_STATE_BACKFACE)) // continue; // indexBuffer[j++] = obj.plist[i].vert[0]; // indexBuffer[j++] = obj.plist[i].vert[1]; // indexBuffer[j++] = obj.plist[i].vert[2]; // ++polys; //} //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* 3 * polys, indexBuffer, GL_STATIC_DRAW); //glDrawElements(GL_TRIANGLES, polys * 3, GL_UNSIGNED_INT, 0); //glFlush(); Reset_RENDERLIST4DV1(&rend_list); static MATRIX4X4 mrot; // general rotation matrix // generate camera matrix Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX); // insert the tanks in the world for (int index = 0; index < NUM_TANKS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_tank); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(0, tanks[index].y, 0, &mrot); // rotate the local coords of the object Transform_OBJECT4DV1(&obj_tank, &mrot, TRANSFORM_LOCAL_TO_TRANS, 1); // set position of tank obj_tank.world_pos.x = tanks[index].x; obj_tank.world_pos.y = tanks[index].y; obj_tank.world_pos.z = tanks[index].z; // attempt to cull object if (!Cull_OBJECT4DV1(&obj_tank, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj_tank, TRANSFORM_TRANS_ONLY); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_tank); } // end if } // end for // insert the player into the world // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_player); // set position of tank obj_player.world_pos.x = cam.pos.x - 300 * Fast_Sin(cam.dir.y); obj_player.world_pos.y = cam.pos.y - 70; obj_player.world_pos.z = cam.pos.z - 300 * Fast_Cos(cam.dir.y); // generate rotation matrix around y axis Build_XYZ_Rotation_MATRIX4X4(0, cam.dir.y + turning, 0, &mrot); //lights[0].pos.x = 300 * Fast_Sin(cam.dir.y); //lights[0].pos.z = 300 * Fast_Cos(cam.dir.y); // rotate the local coords of the object Transform_OBJECT4DV1(&obj_player, &mrot, TRANSFORM_LOCAL_TO_TRANS, 1); // perform world transform Model_To_World_OBJECT4DV1(&obj_player, TRANSFORM_TRANS_ONLY); Cull_OBJECT4DV1(&obj_player, &cam, CULL_OBJECT_XYZ_PLANES); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_player); // insert the towers in the world for (int index = 0; index < NUM_TOWERS; index++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_tower); // set position of tower obj_tower.world_pos.x = towers[index].x; obj_tower.world_pos.y = towers[index].y; obj_tower.world_pos.z = towers[index].z; // attempt to cull object if (!Cull_OBJECT4DV1(&obj_tower, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj_tower); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_tower); } // end if } // end for // seed number generator so that modulation of markers is always the same srand(13); // insert the ground markers into the world for (int index_x = 0; index_x < NUM_POINTS_X; index_x++) for (int index_z = 0; index_z < NUM_POINTS_Z; index_z++) { // reset the object (this only matters for backface and object removal) Reset_OBJECT4DV1(&obj_marker); // set position of tower obj_marker.world_pos.x = RAND_RANGE(-100, 100) - UNIVERSE_RADIUS + index_x*POINT_SIZE; obj_marker.world_pos.y = obj_marker.max_radius; obj_marker.world_pos.z = RAND_RANGE(-100, 100) - UNIVERSE_RADIUS + index_z*POINT_SIZE; // attempt to cull object if (!Cull_OBJECT4DV1(&obj_marker, &cam, CULL_OBJECT_XYZ_PLANES)) { // if we get here then the object is visible at this world position // so we can insert it into the rendering list // perform local/model to world transform Model_To_World_OBJECT4DV1(&obj_marker); // insert the object into render list Insert_OBJECT4DV1_RENDERLIST4DV1(&rend_list, &obj_marker); } // end if } // end for // remove backfaces Remove_Backfaces_RENDERLIST4DV1(&rend_list, &cam); // apply world to camera transform World_To_Camera_RENDERLIST4DV1(&rend_list, &cam); Sort_RENDERLIST4DV1(&rend_list, SORT_POLYLIST_NEARZ); Light_RENDERLIST4DV1_World(&rend_list, &cam, lights, 1); Camera_To_Perspective_Screen_RENDERLIST4DV1(&rend_list, &cam); Draw_RENDERLIST4DV1_Wire(&rend_list, (UCHAR *)buffer, g_width); //Draw_RENDERLIST4DV1_Solid(&rend_list, (UCHAR *)buffer, g_width); glDrawPixels(g_width, g_height, GL_BGRA, GL_UNSIGNED_BYTE, buffer); glutSwapBuffers(); }