/* * R_BrushModelBBox */ float R_BrushModelBBox( const entity_t *e, vec3_t mins, vec3_t maxs, qboolean *rotated ) { int i; const model_t *model = e->model; if( !Matrix3_Compare( e->axis, axis_identity ) ) { if( rotated ) *rotated = qtrue; for( i = 0; i < 3; i++ ) { mins[i] = e->origin[i] - model->radius * e->scale; maxs[i] = e->origin[i] + model->radius * e->scale; } return model->radius * e->scale; } else { if( rotated ) *rotated = qfalse; VectorMA( e->origin, e->scale, model->mins, mins ); VectorMA( e->origin, e->scale, model->maxs, maxs ); return RadiusFromBounds( mins, maxs ); } }
/* * R_AddPortalSurface */ portalSurface_t *R_AddPortalSurface( const entity_t *ent, const mesh_t *mesh, const vec3_t mins, const vec3_t maxs, const shader_t *shader ) { unsigned int i; float dist; cplane_t plane, untransformed_plane; vec3_t v[3]; portalSurface_t *portalSurface; if( !mesh ) { return NULL; } if( R_FASTSKY() && !( shader->flags & (SHADER_PORTAL_CAPTURE|SHADER_PORTAL_CAPTURE2) ) ) { // r_fastsky doesn't affect portalmaps return NULL; } for( i = 0; i < 3; i++ ) { VectorCopy( mesh->xyzArray[mesh->elems[i]], v[i] ); } PlaneFromPoints( v, &untransformed_plane ); untransformed_plane.dist += DotProduct( ent->origin, untransformed_plane.normal ); CategorizePlane( &untransformed_plane ); if( shader->flags & SHADER_AUTOSPRITE ) { vec3_t centre; // autosprites are quads, facing the viewer if( mesh->numVerts < 4 ) { return NULL; } // compute centre as average of 4 vertices VectorCopy( mesh->xyzArray[mesh->elems[3]], centre ); for( i = 0; i < 3; i++ ) VectorAdd( centre, v[i], centre ); VectorMA( ent->origin, 0.25, centre, centre ); VectorNegate( &rn.viewAxis[AXIS_FORWARD], plane.normal ); plane.dist = DotProduct( plane.normal, centre ); CategorizePlane( &plane ); } else { vec3_t temp; mat3_t entity_rotation; // regular surfaces if( !Matrix3_Compare( ent->axis, axis_identity ) ) { Matrix3_Transpose( ent->axis, entity_rotation ); for( i = 0; i < 3; i++ ) { VectorCopy( v[i], temp ); Matrix3_TransformVector( entity_rotation, temp, v[i] ); VectorMA( ent->origin, ent->scale, v[i], v[i] ); } PlaneFromPoints( v, &plane ); CategorizePlane( &plane ); } else { plane = untransformed_plane; } } if( ( dist = PlaneDiff( rn.viewOrigin, &plane ) ) <= BACKFACE_EPSILON ) { // behind the portal plane if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { return NULL; } // we need to render the backplane view } // check if portal view is opaque due to alphagen portal if( shader->portalDistance && dist > shader->portalDistance ) { return NULL; } // find the matching portal plane for( i = 0; i < rn.numPortalSurfaces; i++ ) { portalSurface = &rn.portalSurfaces[i]; if( portalSurface->entity == ent && portalSurface->shader == shader && DotProduct( portalSurface->plane.normal, plane.normal ) > 0.99f && fabs( portalSurface->plane.dist - plane.dist ) < 0.1f ) { goto addsurface; } } if( i == MAX_PORTAL_SURFACES ) { // not enough space return NULL; } portalSurface = &rn.portalSurfaces[rn.numPortalSurfaces++]; portalSurface->entity = ent; portalSurface->plane = plane; portalSurface->shader = shader; portalSurface->untransformed_plane = untransformed_plane; ClearBounds( portalSurface->mins, portalSurface->maxs ); memset( portalSurface->texures, 0, sizeof( portalSurface->texures ) ); addsurface: AddPointToBounds( mins, portalSurface->mins, portalSurface->maxs ); AddPointToBounds( maxs, portalSurface->mins, portalSurface->maxs ); VectorAdd( portalSurface->mins, portalSurface->maxs, portalSurface->centre ); VectorScale( portalSurface->centre, 0.5, portalSurface->centre ); return portalSurface; }
/* * R_TraceLine */ static msurface_t *R_TransformedTraceLine( rtrace_t *tr, const vec3_t start, const vec3_t end, entity_t *test, int surfumask ) { model_t *model; r_traceframecount++; // for multi-check avoidance // fill in a default trace memset( tr, 0, sizeof( *tr ) ); trace_surface = NULL; trace_umask = surfumask; trace_fraction = 1; VectorCopy( end, trace_impact ); memset( &trace_plane, 0, sizeof( trace_plane ) ); ClearBounds( trace_absmins, trace_absmaxs ); AddPointToBounds( start, trace_absmins, trace_absmaxs ); AddPointToBounds( end, trace_absmins, trace_absmaxs ); model = test->model; if( model ) { if( model->type == mod_brush ) { mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata; vec3_t temp, start_l, end_l; mat3_t axis; bool rotated = !Matrix3_Compare( test->axis, axis_identity ); // transform VectorSubtract( start, test->origin, start_l ); VectorSubtract( end, test->origin, end_l ); if( rotated ) { VectorCopy( start_l, temp ); Matrix3_TransformVector( test->axis, temp, start_l ); VectorCopy( end_l, temp ); Matrix3_TransformVector( test->axis, temp, end_l ); } VectorCopy( start_l, trace_start ); VectorCopy( end_l, trace_end ); // world uses a recursive approach using BSP tree, submodels // just walk the list of surfaces linearly if( test->model == rsh.worldModel ) { R_RecursiveHullCheck( bmodel->nodes, start_l, end_l ); } else if( BoundsIntersect( model->mins, model->maxs, trace_absmins, trace_absmaxs ) ) { R_TraceAgainstBmodel( bmodel ); } // transform back if( rotated && trace_fraction != 1 ) { Matrix3_Transpose( test->axis, axis ); VectorCopy( tr->plane.normal, temp ); Matrix3_TransformVector( axis, temp, trace_plane.normal ); } } } // calculate the impact plane, if any if( trace_fraction < 1 && trace_surface != NULL ) { VectorNormalize( trace_plane.normal ); trace_plane.dist = DotProduct( trace_plane.normal, trace_impact ); CategorizePlane( &trace_plane ); tr->shader = trace_surface->shader; tr->plane = trace_plane; tr->surfFlags = trace_surface->flags; tr->ent = R_ENT2NUM( test ); } tr->fraction = trace_fraction; VectorCopy( trace_impact, tr->endpos ); return trace_surface; }
/* * R_UpdatePortalSurface */ void R_UpdatePortalSurface( portalSurface_t *portalSurface, const mesh_t *mesh, const vec3_t mins, const vec3_t maxs, const shader_t *shader ) { unsigned int i; float dist; cplane_t plane, untransformed_plane; vec3_t v[3]; const entity_t *ent; if( !mesh || !portalSurface ) { return; } ent = portalSurface->entity; for( i = 0; i < 3; i++ ) { VectorCopy( mesh->xyzArray[mesh->elems[i]], v[i] ); } PlaneFromPoints( v, &untransformed_plane ); untransformed_plane.dist += DotProduct( ent->origin, untransformed_plane.normal ); untransformed_plane.dist += 1; // nudge along the normal a bit CategorizePlane( &untransformed_plane ); if( shader->flags & SHADER_AUTOSPRITE ) { vec3_t centre; // autosprites are quads, facing the viewer if( mesh->numVerts < 4 ) { return; } // compute centre as average of 4 vertices VectorCopy( mesh->xyzArray[mesh->elems[3]], centre ); for( i = 0; i < 3; i++ ) VectorAdd( centre, v[i], centre ); VectorMA( ent->origin, 0.25, centre, centre ); VectorNegate( &rn.viewAxis[AXIS_FORWARD], plane.normal ); plane.dist = DotProduct( plane.normal, centre ); CategorizePlane( &plane ); } else { vec3_t temp; mat3_t entity_rotation; // regular surfaces if( !Matrix3_Compare( ent->axis, axis_identity ) ) { Matrix3_Transpose( ent->axis, entity_rotation ); for( i = 0; i < 3; i++ ) { VectorCopy( v[i], temp ); Matrix3_TransformVector( entity_rotation, temp, v[i] ); VectorMA( ent->origin, ent->scale, v[i], v[i] ); } PlaneFromPoints( v, &plane ); CategorizePlane( &plane ); } else { plane = untransformed_plane; } } if( ( dist = PlaneDiff( rn.viewOrigin, &plane ) ) <= BACKFACE_EPSILON ) { // behind the portal plane if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { return; } // we need to render the backplane view } // check if portal view is opaque due to alphagen portal if( shader->portalDistance && dist > shader->portalDistance ) { return; } portalSurface->plane = plane; portalSurface->untransformed_plane = untransformed_plane; AddPointToBounds( mins, portalSurface->mins, portalSurface->maxs ); AddPointToBounds( maxs, portalSurface->mins, portalSurface->maxs ); VectorAdd( portalSurface->mins, portalSurface->maxs, portalSurface->centre ); VectorScale( portalSurface->centre, 0.5, portalSurface->centre ); }