📄 raiders3d_2b.cpp
字号:
// we want to use the screen coords of the energy burst this is fine, but a more effective method
// would be to compute the 3D world coords of where the energy burst is firing and then project
// that parallelpiped in 3D space to see where the player is trying to fire, this is a classic
// problem with screen picking, hence, in the engine, when an object is rendered sometimes its
// a good idea to track somekind of collision boundary in screen coords that can be used later
// for "object picking" and collision, anyway, let's do it the easy way, but the long way....
// first is the player firing weapon?
if (weapon_active)
{
// we need 4 transforms total, first we need all our points in world coords,
// then we need camera coords, then perspective coords, then screen coords
// we need to transform 2 points: the center and a point lying on the surface of the
// bounding sphere, as long as the
POINT4D pbox[4], // bounding box coordinates, center points, surrounding object
// denoted by X's, we need to project these to screen coords
// ....X....
// . | | .
// X |-O-| X
// . | | .
// ....X....
// we will use the average radius as the distance to each X from the center
presult; // used to hold temp results
// world to camera transform
// transform center point only
Mat_Mul_VECTOR4D_4X4(&obj_alien.world_pos, &cam.mcam, &presult);
// result holds center of object in camera coords now
// now we are in camera coords, aligned to z-axis, compute radial point axis aligned
// bounding box points
// x+r, y, z
pbox[0].x = presult.x + obj_alien.avg_radius[obj_alien.curr_frame];
pbox[0].y = presult.y;
pbox[0].z = presult.z;
pbox[0].w = 1;
// x-r, y, z
pbox[1].x = presult.x - obj_alien.avg_radius[obj_alien.curr_frame];
pbox[1].y = presult.y;
pbox[1].z = presult.z;
pbox[1].w = 1;
// x, y+r, z
pbox[2].x = presult.x;
pbox[2].y = presult.y + obj_alien.avg_radius[obj_alien.curr_frame];
pbox[2].z = presult.z;
pbox[2].w = 1;
// x, y-r, z
pbox[3].x = presult.x;
pbox[3].y = presult.y - obj_alien.avg_radius[obj_alien.curr_frame];
pbox[3].z = presult.z;
pbox[3].w = 1;
// now we are ready to project the points to screen space
float alpha = (0.5*cam.viewport_width-0.5);
float beta = (0.5*cam.viewport_height-0.5);
// loop and process each point
for (int bindex=0; bindex < 4; bindex++)
{
float z = pbox[bindex].z;
// perspective transform first
pbox[bindex].x = cam.view_dist*pbox[bindex].x/z;
pbox[bindex].y = cam.view_dist*pbox[bindex].y*cam.aspect_ratio/z;
// z = z, so no change
// screen projection
pbox[bindex].x = alpha*pbox[bindex].x + alpha;
pbox[bindex].y = -beta*pbox[bindex].y + beta;
} // end for bindex
#ifdef DEBUG_ON
// now we have the 4 points is screen coords and we can test them!!! ya!!!!
Draw_Clip_Line16(pbox[0].x, pbox[2].y, pbox[1].x, pbox[2].y, rgb_red, back_buffer, back_lpitch);
Draw_Clip_Line16(pbox[0].x, pbox[3].y, pbox[1].x, pbox[3].y, rgb_red, back_buffer, back_lpitch);
Draw_Clip_Line16(pbox[0].x, pbox[2].y, pbox[0].x, pbox[3].y, rgb_red, back_buffer, back_lpitch);
Draw_Clip_Line16(pbox[1].x, pbox[2].y, pbox[1].x, pbox[3].y, rgb_red, back_buffer, back_lpitch);
#endif
// test for collision
if ((cross_x_screen > pbox[1].x) && (cross_x_screen < pbox[0].x) &&
(cross_y_screen > pbox[2].y) && (cross_y_screen < pbox[3].y) )
{
Start_Mesh_Explosion(&obj_alien, // object to blow
&mrot, // initial orientation
3, // the detail level,1 highest detail
.5, // velocity of explosion shrapnel
100); // total lifetime of explosion
// remove from simulation
aliens[index].state = ALIEN_STATE_DEAD;
// make some sound
DSound_Play(explosion_id);
// increment hits
hits++;
// take into consideration the z, the speed, the level, blah blah
score += (int)((diff_level*10 + obj_alien.world_pos.z/10));
} // end if
} // end if weapon active
} break;
default: break;
} // end switch
} // end for index
// debug code
#ifdef DEBUG_ON
// reset the object (this only matters for backface and object removal)
Reset_OBJECT4DV2(&obj_alien);
static int ang_y = 0;
// generate rotation matrix around y axis
Build_XYZ_Rotation_MATRIX4X4(0, ang_y++, 0 ,&mrot);
// rotate the local coords of the object
Transform_OBJECT4DV2(&obj_alien, &mrot, TRANSFORM_LOCAL_TO_TRANS,1);
// set position of constant shaded cube
obj_alien.world_pos.x = px;
obj_alien.world_pos.y = py;
obj_alien.world_pos.z = pz;
// perform world transform
Model_To_World_OBJECT4DV2(&obj_alien, TRANSFORM_TRANS_ONLY);
// insert the object into render list
Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_alien,0);
#endif
} // end Draw_Aliens
//////////////////////////////////////////////////////////
void Draw_Mesh_Explosions(void)
{
// this function draws the mesh explosions
MATRIX4X4 mrot; // used to transform objects
// draw the explosions, note we do NOT cull them
for (int eindex = 0; eindex < NUM_EXPLOSIONS; eindex++)
{
// is the mesh explosions active
if ((explobj[eindex].state & OBJECT4DV2_STATE_ACTIVE))
{
// reset the object
Reset_OBJECT4DV2(&explobj[eindex]);
// generate rotation matrix
Build_XYZ_Rotation_MATRIX4X4(0, 0, 0 ,&mrot);
// rotate the local coords of the object
Transform_OBJECT4DV2(&explobj[eindex], &mrot, TRANSFORM_LOCAL_TO_TRANS,1);
// perform world transform
Model_To_World_OBJECT4DV2(&explobj[eindex], TRANSFORM_TRANS_ONLY);
// insert the object into render list
Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &explobj[eindex],0);
// now animate the mesh
VECTOR4D_PTR trajectory = (VECTOR4D_PTR)explobj[eindex].ivar1;
for (int pindex = 0; pindex < explobj[eindex].num_polys; pindex++)
{
// vertex 0
VECTOR4D_Add(&explobj[eindex].vlist_local[pindex*3 + 0].v,
&trajectory[pindex*2+0],
&explobj[eindex].vlist_local[pindex*3 + 0].v);
// vertex 1
VECTOR4D_Add(&explobj[eindex].vlist_local[pindex*3 + 1].v,
&trajectory[pindex*2 + 0],
&explobj[eindex].vlist_local[pindex*3 + 1].v);
// vertex 2
VECTOR4D_Add(&explobj[eindex].vlist_local[pindex*3 + 2].v,
&trajectory[pindex*2 + 0],
&explobj[eindex].vlist_local[pindex*3 + 2].v);
// modulate color
//explobj[eindex].plist[pindex].color = RGB16Bit(rand()%255,0,0);
} // end for pindex
// update counter, test for terminate
if (--explobj[eindex].ivar2 < 0)
{
// reset this object
explobj[eindex].state = OBJECT4DV2_STATE_NULL;
// release memory of object, but only data that isn't linked to master object
// local vertex list
if (explobj[eindex].head_vlist_local)
free(explobj[eindex].head_vlist_local);
// transformed vertex list
if (explobj[eindex].head_vlist_trans)
free(explobj[eindex].head_vlist_trans);
// polygon list
if (explobj[eindex].plist)
free(explobj[eindex].plist);
// trajectory list
if ((VECTOR4D_PTR)(explobj[eindex].ivar1))
free((VECTOR4D_PTR)explobj[eindex].ivar1);
// now clear out object completely
memset((void *)&explobj[eindex], 0, sizeof(OBJECT4DV2));
} // end if
} // end if
} // end for eindex
} // end Draw_Mesh_Explosions
//////////////////////////////////////////////////////////
int Start_Mesh_Explosion(OBJECT4DV2_PTR obj, // object to destroy
MATRIX4X4_PTR mrot, // initial orientation of object
int detail, // the detail level,1 highest detail
float rate, // velocity of explosion shrapnel
int lifetime) // total lifetime of explosion
{
// this function "blows up" an object, it takes a pointer to the object to
// be destroyed, the detail level of the polyogonal explosion, 1 is high detail,
// numbers greater than 1 are lower detail, the detail selects the polygon extraction
// stepping, hence a detail of 5 would mean every 5th polygon in the original mesh
// should be part of the explosion, on average no more than 10-50% of the polygons in
// the original mesh should be used for the explosion; some would be vaporized and
// in a more practical sense, when an object is far, there's no need to have detail
// the next parameter is the rate which is used as a general scale for the explosion
// velocity, and finally lifetime which is the number of cycles to display the explosion
// the function works by taking the original object then copying the core information
// except for the polygon and vertex lists, the function operates by selecting polygon
// by polygon to be destroyed and then makes a copy of the polygon AND all of it's vertices,
// thus the vertex coherence is completely lost, this is a necessity since each polygon must
// be animated separately by the engine, thus they can't share vertices, additionally at the
// end if the vertex list will be the velocity and rotation information for each polygon
// this is hidden to the rest of the engine, now for the explosion, the center of the object
// is used as the point of origin then a ray is drawn thru each polygon, then each polygon
// is thrown at some velocity with a small rotation rate
// finally the system can only have so many explosions at one time
// step: 1 find an available explosion
for (int eindex = 0; eindex < NUM_EXPLOSIONS; eindex++)
{
// is this explosion available?
if (explobj[eindex].state == OBJECT4DV2_STATE_NULL)
{
// copy the object, including the pointers which we will unlink shortly...
explobj[eindex] = *obj;
explobj[eindex].state = OBJECT4DV2_STATE_ACTIVE | OBJECT4DV2_STATE_VISIBLE;
// recompute a few things
explobj[eindex].num_polys = obj->num_polys/detail;
explobj[eindex].num_vertices = 3*obj->num_polys;
explobj[eindex].total_vertices = 3*obj->num_polys; // one frame only
// unlink/re-allocate all the pointers except the texture coordinates, we can use those, they don't
// depend on vertex coherence
// allocate memory for vertex lists
if (!(explobj[eindex].vlist_local = (VERTEX4DTV1_PTR)malloc(sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices)))
return(0);
// clear data
memset((void *)explobj[eindex].vlist_local,0,sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices);
if (!(explobj[eindex].vlist_trans = (VERTEX4DTV1_PTR)malloc(sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices)))
return(0);
// clear data
memset((void *)explobj[eindex].vlist_trans,0,sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices);
// allocate memory for polygon list
if (!(explobj[eindex].plist = (POLY4DV2_PTR)malloc(sizeof(POLY4DV2)*explobj[eindex].num_polys)))
return(0);
// clear data
memset((void *)explobj[eindex].plist,0,sizeof(POLY4DV2)*explobj[eindex].num_polys);
// now, we need somewhere to store the vector trajectories of the polygons and their rotational rates
// so let's allocate an array of VECTOR4D elements to hold this information and then store it
// in ivar1, therby using ivar as a pointer, this is perfectly fine :)
// each record will consist of a velocity and a rotational rate in x,y,z, so V0,R0, V1,R1,...Vn-1, Rn-1
// allocate memory for polygon list
if (!(explobj[eindex].ivar1 = (int)malloc(sizeof(VECTOR4D)*2*explobj[eindex].num_polys)))
return(0);
// clear data
memset((void *)explobj[eindex].ivar1,0,sizeof(VECTOR4D)*2*explobj[eindex].num_polys);
// alias working pointer
VECTOR4D_PTR trajectory = (VECTOR4D_PTR)explobj[eindex].ivar1;
// these are needed to track the "head" of the vertex list for multi-frame objects
explobj[eindex].head_vlist_local = explobj[eindex].vlist_local;
explobj[eindex].head_vlist_trans = explobj[eindex].vlist_trans;
// set the lifetime in ivar2
explobj[eindex].ivar2 = lifetime;
// now comes the tricky part, loop and copy each polygon, but as we copy the polygons, we have to copy
// the vertices, and insert them, and fix up the vertice indices etc.
for (int pindex = 0; pindex < explobj[eindex].num_polys; pindex++)
{
// alright, we want to copy the (pindex*detail)th poly from the master to the (pindex)th
// polygon in explosion
explobj[eindex].plist[pindex] = obj->plist[pindex*detail];
// we need to modify, the vertex list pointer and the vertex indices themselves
explobj[eindex].plist[pindex].vlist = explobj[eindex].vlist_local;
// now comes the hard part, we need to first copy the vertices from the original mesh
// into the new vertex storage, but at the same time keep the same vertex ordering
// vertex 0
explobj[eindex].plist[pindex].vert[0] = pindex*3 + 0;
explobj[eindex].vlist_local[pindex*3 + 0] = obj->vlist_local[ obj->plist[pindex*detail].vert[0] ];
// vertex 1
explobj[eindex].plist[pindex].vert[1] = pindex*3 + 1;
explobj[eindex].vlist_local[pindex*3 + 1] = obj->vlist_local[ obj->plist[pindex*detail].vert[1] ];
// vertex 2
explobj[eindex].plist[pindex].vert[2] = pindex*3 + 2;
explobj[eindex].vlist_local[pindex*3 + 2] = obj->vlist_local[ obj->plist[pindex*detail].vert[2] ];
// reset shading flag to constant for some of the shrapnel since they are giving off light
if ((rand()%5) == 1)
{
SET_BIT(explobj[eindex].plist[pindex].attr, POLY4DV2_ATTR_SHADE_MODE_PURE);
RESET_BIT(explobj[eindex].plist[pindex].attr, POLY4DV2_ATTR_SHADE_MODE_GOURAUD);
RESET_BIT(explobj[eindex].plist[pindex].attr, POLY4DV2_ATTR_SHADE_MODE_FLAT);
// set color
explobj[eindex].plist[pindex].color = RGB16Bit(128+rand()%128,0,0);
} // end if
// add some random noise to trajectory
static VECTOR4D mv;
// first compute trajectory as vector from center to vertex piercing polygon
VECTOR4D_INIT(&trajectory[pindex*2+0], &obj->vlist_local[ obj->plist[pindex*detail].vert[0] ].v);
VECTOR4D_Scale(rate, &trajectory[pindex*2+0], &trajectory[pindex*2+0]);
mv.x = RAND_RANGE(-10,10);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -