/* ================ R_DrawMirrors Draw all viewpasess from mirror position Mirror textures will be drawn in normal pass ================ */ void R_DrawMirrors( void ) { ref_instance_t oldRI; mplane_t plane; msurface_t *surf, *surf2; int i, oldframecount; mextrasurf_t *es, *tmp, *mirrorchain; vec3_t forward, right, up; vec3_t origin, angles; matrix4x4 mirrormatrix; cl_entity_t *e; model_t *m; float d; if( !tr.num_mirror_entities ) return; // mo mirrors for this frame oldRI = RI; // make refinst backup oldframecount = tr.framecount; for( i = 0; i < tr.num_mirror_entities; i++ ) { mirrorchain = tr.mirror_entities[i].chain; for( es = mirrorchain; es != NULL; es = es->mirrorchain ) { RI.currententity = e = tr.mirror_entities[i].ent; RI.currentmodel = m = RI.currententity->model; surf = INFO_SURF( es, m ); ASSERT( RI.currententity != NULL ); ASSERT( RI.currentmodel != NULL ); // NOTE: copy mirrortexture and mirrormatrix from another surfaces // from this entity\world that has same planes and reduce number of viewpasses // make sure what we have one pass at least if( es != mirrorchain ) { for( tmp = mirrorchain; tmp != es; tmp = tmp->mirrorchain ) { surf2 = INFO_SURF( tmp, m ); if( !tmp->mirrortexturenum ) continue; // not filled? if( surf->plane->dist != surf2->plane->dist ) continue; if( !VectorCompare( surf->plane->normal, surf2->plane->normal )) continue; // found surface with same plane! break; } if( tmp != es && tmp && tmp->mirrortexturenum ) { // just copy reflection texture from surface with same plane Matrix4x4_Copy( es->mirrormatrix, tmp->mirrormatrix ); es->mirrortexturenum = tmp->mirrortexturenum; continue; // pass skiped } } R_PlaneForMirror( surf, &plane, mirrormatrix ); d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist ); VectorMA( RI.vieworg, d, plane.normal, origin ); d = -2.0f * DotProduct( RI.vforward, plane.normal ); VectorMA( RI.vforward, d, plane.normal, forward ); VectorNormalize( forward ); d = -2.0f * DotProduct( RI.vright, plane.normal ); VectorMA( RI.vright, d, plane.normal, right ); VectorNormalize( right ); d = -2.0f * DotProduct( RI.vup, plane.normal ); VectorMA( RI.vup, d, plane.normal, up ); VectorNormalize( up ); VectorsAngles( forward, right, up, angles ); angles[ROLL] = -angles[ROLL]; RI.params = RP_MIRRORVIEW|RP_CLIPPLANE|RP_OLDVIEWLEAF; RI.clipPlane = plane; RI.clipFlags |= ( 1<<5 ); RI.frustum[5] = plane; RI.frustum[5].signbits = SignbitsForPlane( RI.frustum[5].normal ); RI.frustum[5].type = PLANE_NONAXIAL; RI.refdef.viewangles[0] = anglemod( angles[0] ); RI.refdef.viewangles[1] = anglemod( angles[1] ); RI.refdef.viewangles[2] = anglemod( angles[2] ); VectorCopy( origin, RI.refdef.vieworg ); VectorCopy( origin, RI.cullorigin ); // put pvsorigin before the mirror plane to avoid get full visibility on world mirrors if( RI.currententity == clgame.entities ) { VectorMA( es->origin, 1.0f, plane.normal, origin ); } else { Matrix4x4_VectorTransform( mirrormatrix, es->origin, origin ); VectorMA( origin, 1.0f, plane.normal, origin ); } VectorCopy( origin, RI.pvsorigin ); // combine two leafs from client and mirror views r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes ); r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ); if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) { // allow screen size RI.viewport[2] = bound( 96, RI.viewport[2], 1024 ); RI.viewport[3] = bound( 72, RI.viewport[3], 768 ); } else { RI.viewport[2] = NearestPOW( RI.viewport[2], true ); RI.viewport[3] = NearestPOW( RI.viewport[3], true ); RI.viewport[2] = bound( 128, RI.viewport[2], 1024 ); RI.viewport[3] = bound( 64, RI.viewport[3], 512 ); } tr.framecount++; R_RenderScene( &RI.refdef ); r_stats.c_mirror_passes++; es->mirrortexturenum = R_AllocateMirrorTexture(); // create personal projection matrix for mirror if( VectorIsNull( e->origin ) && VectorIsNull( e->angles )) { Matrix4x4_Copy( es->mirrormatrix, RI.worldviewProjectionMatrix ); } else { Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, mirrormatrix ); Matrix4x4_Concat( es->mirrormatrix, RI.projectionMatrix, RI.modelviewMatrix ); } RI = oldRI; // restore ref instance } // clear chain for this entity for( es = mirrorchain; es != NULL; ) { tmp = es->mirrorchain; es->mirrorchain = NULL; es = tmp; } tr.mirror_entities[i].chain = NULL; // done tr.mirror_entities[i].ent = NULL; } r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame tr.framecount = oldframecount; // restore real framecount tr.num_mirror_entities = 0; tr.num_mirrors_used = 0; }
/* ============ SV_PushRotate ============ */ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) { int i, e, block, oldsolid; matrix4x4 start_l, end_l; vec3_t lmove, amove; sv_pushed_t *p, *pushed_p; vec3_t org, org2, temp; edict_t *check; if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity )) { pusher->v.ltime += movetime; return NULL; } for( i = 0; i < 3; i++ ) amove[i] = pusher->v.avelocity[i] * movetime; // create pusher initial position Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f ); pushed_p = svgame.pushed; // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->v.origin, pushed_p->origin ); VectorCopy( pusher->v.angles, pushed_p->angles ); pushed_p++; // move the pusher to it's final position SV_AngularMove( pusher, movetime, pusher->v.friction ); SV_LinkEdict( pusher, false ); pusher->v.ltime += movetime; oldsolid = pusher->v.solid; // non-solid pushers can't push anything if( pusher->v.solid == SOLID_NOT ) return NULL; // create pusher final position Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f ); // see if any solid entities are inside the final position for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher )) { if( check->v.absmin[0] >= pusher->v.absmax[0] || check->v.absmin[1] >= pusher->v.absmax[1] || check->v.absmin[2] >= pusher->v.absmax[2] || check->v.absmax[0] <= pusher->v.absmin[0] || check->v.absmax[1] <= pusher->v.absmin[1] || check->v.absmax[2] <= pusher->v.absmin[2] ) continue; // see if the ent's bbox is inside the pusher's final position if( !SV_TestEntityPosition( check, NULL )) continue; } // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); VectorCopy( check->v.angles, pushed_p->angles ); pushed_p->fixangle = check->v.fixangle; pushed_p++; // calculate destination position if( check->v.movetype == MOVETYPE_PUSHSTEP || check->v.movetype == MOVETYPE_STEP ) VectorAverage( check->v.absmin, check->v.absmax, org ); else VectorCopy( check->v.origin, org ); Matrix4x4_VectorITransform( start_l, org, temp ); Matrix4x4_VectorTransform( end_l, temp, org2 ); VectorSubtract( org2, org, lmove ); // i can't clear FL_ONGROUND in all cases because many bad things may be happen if( check->v.movetype != MOVETYPE_WALK ) { if( lmove[2] != 0.0f ) check->v.flags &= ~FL_ONGROUND; if( lmove[2] < 0.0f && !pusher->v.dmg ) lmove[2] = 0.0f; // let's the free falling } // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity( check, lmove, amove, &block ); pusher->v.solid = oldsolid; // pushed entity blocked by wall if( block && check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; // if it is still inside the pusher, block if( SV_TestEntityPosition( check, NULL ) && block ) { if( !SV_CanBlock( check )) continue; pusher->v.ltime -= movetime; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= svgame.pushed; p-- ) { VectorCopy( p->origin, p->ent->v.origin ); VectorCopy( p->angles, p->ent->v.angles ); SV_LinkEdict( p->ent, (p->ent == check) ? true : false ); p->ent->v.fixangle = p->fixangle; } return check; } } return NULL; }