Example #1
0
/*
* R_AddBrushModelToDrawList
*/
qboolean R_AddBrushModelToDrawList( const entity_t *e )
{
	unsigned int i;
	vec3_t origin;
	vec3_t bmins, bmaxs;
	qboolean rotated;
	model_t	*model = e->model;
	mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata;
	msurface_t *surf;
	mfog_t *fog;
	float radius, distance;
	unsigned int bit, fullBits;
	unsigned int dlightBits, shadowBits;

	if( bmodel->nummodelsurfaces == 0 ) {
		return qfalse;
	}

	radius = R_BrushModelBBox( e, bmins, bmaxs, &rotated );

	if( R_CullModelEntity( e, bmins, bmaxs, radius, rotated ) ) {
		return qfalse;
	}

	// never render weapon models or non-occluders into shadowmaps
	if( rn.renderFlags & RF_SHADOWMAPVIEW ) {
		if( rsc.entShadowGroups[R_ENT2NUM(e)] != rn.shadowGroup->id ) {
			return qtrue;
		}
	}

	VectorAdd( e->model->mins, e->model->maxs, origin );
	VectorMA( e->origin, 0.5, origin, origin );
	distance = Distance( origin, rn.refdef.vieworg );

	fog = R_FogForBounds( bmins, bmaxs );

	R_TransformPointToModelSpace( e, rotated, rn.refdef.vieworg, modelOrg );

	// check dynamic lights that matter in the instance against the model
	dlightBits = 0;
	for( i = 0, fullBits = rn.dlightBits, bit = 1; fullBits; i++, fullBits &= ~bit, bit <<= 1 ) {
		if( !( fullBits & bit ) ) {
			continue;
		}
		if( !BoundsAndSphereIntersect( bmins, bmaxs, rsc.dlights[i].origin, rsc.dlights[i].intensity ) ) {
			continue;
		}
		dlightBits |= bit;
	}

	// check shadowmaps that matter in the instance against the model
	shadowBits = 0;
	for( i = 0, fullBits = rn.shadowBits; fullBits; i++, fullBits &= ~bit ) {
		shadowGroup_t *grp = rsc.shadowGroups + i;
		bit = grp->bit;
		if( !( fullBits & bit ) ) {
			continue;
		}
		if( !BoundsIntersect( bmins, bmaxs, grp->visMins, grp->visMaxs ) ) {
			continue;
		}
		shadowBits |= bit;
	}

	for( i = 0, surf = bmodel->firstmodelsurface; i < bmodel->nummodelsurfaces; i++, surf++ ) {
		if( !surf->drawSurf ) {
			continue;
		}
		if( surf->visFrame != rf.frameCount ) {
			surf->visFrame = rf.frameCount;
			R_AddSurfaceToDrawList( e, surf, fog, 0, dlightBits, shadowBits, distance );
		}
	}

	return qtrue;
}
Example #2
0
/*
* 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;
}
Example #3
0
/*
* R_DrawSkeletalSurf
*/
qboolean R_DrawSkeletalSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceSkeletal_t *drawSurf )
{
	unsigned int i, j;
	int framenum = e->frame;
	int oldframenum = e->oldframe;
	float backlerp = e->backlerp;
	float frontlerp = 1.0 - backlerp;
	bonepose_t tempbonepose[256];
	const bonepose_t *bp, *oldbp, *bonepose, *oldbonepose, *lerpedbonepose;
	bonepose_t *out, tp;
	mskbone_t *bone;
	mat4_t *bonePoseRelativeMat;
	dualquat_t *bonePoseRelativeDQ;
	size_t bonePoseRelativeMatSize, bonePoseRelativeDQSize;
	const model_t *mod = drawSurf->model;
	const mskmodel_t *skmodel = ( const mskmodel_t * )mod->extradata;
	const mskmesh_t *skmesh = drawSurf->mesh;
	qboolean hardwareTransform = skmesh->vbo != NULL && glConfig.maxGLSLBones > 0 ? qtrue : qfalse;
	vattribmask_t vattribs;

	bonePoseRelativeMat = NULL;
	bonePoseRelativeDQ = NULL;

	bp = e->boneposes;
	oldbp = e->oldboneposes;

	// not sure if it's really needed
	if( bp == skmodel->frames[0].boneposes )
	{
		bp = NULL;
		framenum = oldframenum = 0;
	}

	// choose boneposes for lerping
	if( bp )
	{
		if( !oldbp )
			oldbp = bp;
	}
	else
	{
		if( ( framenum >= (int)skmodel->numframes ) || ( framenum < 0 ) )
		{
#ifndef PUBLIC_BUILD
			ri.Com_DPrintf( "R_DrawBonesFrameLerp %s: no such frame %d\n", mod->name, framenum );
#endif
			framenum = 0;
		}
		if( ( oldframenum >= (int)skmodel->numframes ) || ( oldframenum < 0 ) )
		{
#ifndef PUBLIC_BUILD
			ri.Com_DPrintf( "R_DrawBonesFrameLerp %s: no such oldframe %d\n", mod->name, oldframenum );
#endif
			oldframenum = 0;
		}

		bp = skmodel->frames[framenum].boneposes;
		oldbp = skmodel->frames[oldframenum].boneposes;
	}

	if( bp == oldbp && !framenum && skmesh->vbo != NULL ) {
		// fastpath: render static frame 0 as is
		RB_BindVBO( skmesh->vbo->index, GL_TRIANGLES );

		RB_DrawElements( 0, skmesh->numverts, 0, skmesh->numtris * 3 );

		return qfalse;
	}

	// see what vertex attribs backend needs
	vattribs = RB_GetVertexAttribs();

	// cache size
	bonePoseRelativeMatSize = sizeof( mat4_t ) * (skmodel->numbones + skmodel->numblends);
	bonePoseRelativeDQSize = sizeof( dualquat_t ) * skmodel->numbones;

	// fetch bones tranforms from cache (both matrices and dual quaternions)
	bonePoseRelativeDQ = ( dualquat_t * )R_GetSketalCache( R_ENT2NUM( e ), mod->lodnum );
	if( bonePoseRelativeDQ ) {
		bonePoseRelativeMat = ( mat4_t * )(( qbyte * )bonePoseRelativeDQ + bonePoseRelativeDQSize);
	}
	else {
		// lerp boneposes and store results in cache

		lerpedbonepose = tempbonepose;
		if( bp == oldbp || frontlerp == 1 )
		{
			if( e->boneposes )
			{
				// assume that parent transforms have already been applied
				lerpedbonepose = bp;
			}
			else
			{
				for( i = 0; i < skmodel->numbones; i++ )
				{
					j = i;
					out = tempbonepose + j;
					bonepose = bp + j;
					bone = skmodel->bones + j;

					if( bone->parent >= 0 ) {
						DualQuat_Multiply( tempbonepose[bone->parent].dualquat, bonepose->dualquat, out->dualquat );
					}
					else {
						DualQuat_Copy( bonepose->dualquat, out->dualquat );
					}
				}
			}
		}
		else
		{
			if( e->boneposes )
			{
				// lerp, assume that parent transforms have already been applied
				for( i = 0, out = tempbonepose, bonepose = bp, oldbonepose = oldbp, bone = skmodel->bones; i < skmodel->numbones; i++, out++, bonepose++, oldbonepose++, bone++ )
				{
					DualQuat_Lerp( oldbonepose->dualquat, bonepose->dualquat, frontlerp, out->dualquat );
				}
			}
			else
			{
				// lerp and transform
				for( i = 0; i < skmodel->numbones; i++ )
				{
					j = i;
					out = tempbonepose + j;
					bonepose = bp + j;
					oldbonepose = oldbp + j;
					bone = skmodel->bones + j;

					DualQuat_Lerp( oldbonepose->dualquat, bonepose->dualquat, frontlerp, out->dualquat );

					if( bone->parent >= 0 ) {
						DualQuat_Copy( out->dualquat, tp.dualquat );
						DualQuat_Multiply( tempbonepose[bone->parent].dualquat, tp.dualquat, out->dualquat );
					}
				}
			}
		}

		bonePoseRelativeDQ = ( dualquat_t * )R_AllocSkeletalDataCache( R_ENT2NUM( e ), mod->lodnum, 
			bonePoseRelativeDQSize + bonePoseRelativeMatSize );

		// generate dual quaternions for all bones
		for( i = 0; i < skmodel->numbones; i++ ) {
			DualQuat_Multiply( lerpedbonepose[i].dualquat, skmodel->invbaseposes[i].dualquat, bonePoseRelativeDQ[i] );
			DualQuat_Normalize( bonePoseRelativeDQ[i] );
		}

		// CPU transforms
		if( !hardwareTransform ) {
			bonePoseRelativeMat = ( mat4_t * )(( qbyte * )bonePoseRelativeDQ + bonePoseRelativeDQSize);

			// generate matrices for all bones
			for( i = 0; i < skmodel->numbones; i++ ) {
				Matrix4_FromDualQuaternion( bonePoseRelativeDQ[i], bonePoseRelativeMat[i] );
			}

			// generate matrices for all blend combinations
			R_SkeletalBlendPoses( skmodel->numblends, skmodel->blends, skmodel->numbones, bonePoseRelativeMat );
		}
	}

	if( hardwareTransform )
	{
		RB_BindVBO( skmesh->vbo->index, GL_TRIANGLES );
		RB_SetBonesData( skmodel->numbones, bonePoseRelativeDQ, skmesh->maxWeights );
		RB_DrawElements( 0, skmesh->numverts, 0, skmesh->numtris * 3 );
	}
	else
	{
		mesh_t *rb_mesh;

		RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLES );

		rb_mesh = RB_MapBatchMesh( skmesh->numverts, skmesh->numtris * 3 );
		if( !rb_mesh ) {
			ri.Com_DPrintf( S_COLOR_YELLOW "R_DrawAliasSurf: RB_MapBatchMesh returned NULL for (%s)(%s)", 
				drawSurf->model->name, skmesh->name );
			return qfalse;
		}

		R_SkeletalTransformVerts( skmesh->numverts, skmesh->vertexBlends, bonePoseRelativeMat,
			( vec_t * )skmesh->xyzArray[0], ( vec_t * )rb_mesh->xyzArray );

		if( vattribs & VATTRIB_SVECTOR_BIT ) {
			R_SkeletalTransformNormalsAndSVecs( skmesh->numverts, skmesh->vertexBlends, bonePoseRelativeMat,
			( vec_t * )skmesh->normalsArray[0], ( vec_t * )rb_mesh->normalsArray,
			( vec_t * )skmesh->sVectorsArray[0], ( vec_t * )rb_mesh->sVectorsArray );
		} else if( vattribs & VATTRIB_NORMAL_BIT ) {
			R_SkeletalTransformNormals( skmesh->numverts, skmesh->vertexBlends, bonePoseRelativeMat,
			( vec_t * )skmesh->normalsArray[0], ( vec_t * )rb_mesh->normalsArray );
		}

		rb_mesh->elems = skmesh->elems;
		rb_mesh->numElems = skmesh->numtris * 3;
		rb_mesh->numVerts = skmesh->numverts;
		rb_mesh->stArray = skmesh->stArray;

		RB_UploadMesh( rb_mesh );
		RB_EndBatch();
	}

	return qfalse;
}
Example #4
0
/*
* R_AddSkeletalModelToDrawList
*/
qboolean R_AddSkeletalModelToDrawList( const entity_t *e )
{
	int i;
	const mfog_t *fog;
	const model_t *mod;
	const shader_t *shader;
	const mskmesh_t *mesh;
	const mskmodel_t *skmodel;
	vec3_t mins, maxs;
	float radius;
	float distance;
	int clipped;

	mod = R_SkeletalModelLOD( e );
	if( !( skmodel = ( ( mskmodel_t * )mod->extradata ) ) || !skmodel->nummeshes )
		return qfalse;

	radius = R_SkeletalModelLerpBBox( e, mod, mins, maxs );
	clipped = R_CullModelEntity( e, mins, maxs, radius, qtrue );
	if( clipped )
		return qfalse;

	// never render weapon models or non-occluders into shadowmaps
	if( rn.renderFlags & RF_SHADOWMAPVIEW ) {
		if( e->renderfx & RF_WEAPONMODEL ) {
			return qtrue;
		}
		if( rsc.entShadowGroups[R_ENT2NUM(e)] != rn.shadowGroup->id ) {
			return qtrue;
		}
	}

	// make sure weapon model is always closest to the viewer
	if( e->renderfx & RF_WEAPONMODEL ) {
		distance = 0;
	}
	else {
		distance = Distance( e->origin, rn.viewOrigin ) + 1;
	}

	fog = R_FogForSphere( e->origin, radius );
#if 0
	if( !( e->flags & RF_WEAPONMODEL ) && fog )
	{
		R_SkeletalModelLerpBBox( e, mod );
		if( R_CompletelyFogged( fog, e->origin, skm_radius ) )
			return qfalse;
	}
#endif

	for( i = 0, mesh = skmodel->meshes; i < (int)skmodel->nummeshes; i++, mesh++ )
	{
		shader = NULL;
		if( e->customSkin ) {
			shader = R_FindShaderForSkinFile( e->customSkin, mesh->name );
		} else if( e->customShader ) {
			shader = e->customShader;
		} else {
			shader = mesh->skin.shader;
		}

		if( shader ) {
			R_AddDSurfToDrawList( e, fog, shader, distance, 0, NULL, skmodel->drawSurfs + i );
		}
	}

	return qtrue;
}
Example #5
0
/*
* R_AddLightOccluder
*/
bool R_AddLightOccluder( const entity_t *ent ) {
	int i;
	float maxSide;
	vec3_t origin;
	unsigned int hash_key;
	shadowGroup_t *group;
	mleaf_t *leaf;
	vec3_t mins, maxs, bbox[8];
	bool bmodelRotated = false;

	if( rn.refdef.rdflags & RDF_NOWORLDMODEL ) {
		return false;
	}
	if( !ent->model || ent->model->type == mod_brush ) {
		return false;
	}

	VectorCopy( ent->lightingOrigin, origin );
	if( ent->model->type == mod_brush ) {
		vec3_t t;
		VectorAdd( ent->model->mins, ent->model->maxs, t );
		VectorMA( ent->origin, 0.5, t, origin );
	}

	if( VectorCompare( origin, vec3_origin ) ) {
		return false;
	}

	// find lighting group containing entities with same lightingOrigin as ours
	hash_key = (unsigned int)( origin[0] * 7 + origin[1] * 5 + origin[2] * 3 );
	hash_key &= ( SHADOWGROUPS_HASH_SIZE - 1 );

	for( group = r_shadowGroups_hash[hash_key]; group; group = group->hashNext ) {
		if( VectorCompare( group->origin, origin ) ) {
			goto add; // found an existing one, add
		}
	}

	if( rsc.numShadowGroups == MAX_SHADOWGROUPS ) {
		return false; // no free groups

	}
	leaf = Mod_PointInLeaf( origin, rsh.worldModel );

	// start a new group
	group = &rsc.shadowGroups[rsc.numShadowGroups];
	memset( group, 0, sizeof( *group ) );
	group->id = group - rsc.shadowGroups + 1;
	group->bit = ( 1 << rsc.numShadowGroups );
	group->vis = Mod_ClusterPVS( leaf->cluster, rsh.worldModel );
	group->useOrtho = true;
	group->alpha = r_shadows_alpha->value;

	// clear group bounds
	VectorCopy( origin, group->origin );
	ClearBounds( group->mins, group->maxs );
	ClearBounds( group->visMins, group->visMaxs );

	// add to hash table
	group->hashNext = r_shadowGroups_hash[hash_key];
	r_shadowGroups_hash[hash_key] = group;

	rsc.numShadowGroups++;
add:
	// get model bounds
	if( ent->model->type == mod_alias ) {
		R_AliasModelBBox( ent, mins, maxs );
	} else if( ent->model->type == mod_skeletal ) {
		R_SkeletalModelBBox( ent, mins, maxs );
	} else if( ent->model->type == mod_brush ) {
		R_BrushModelBBox( ent, mins, maxs, &bmodelRotated );
	} else {
		ClearBounds( mins, maxs );
	}

	maxSide = 0;
	for( i = 0; i < 3; i++ ) {
		if( mins[i] >= maxs[i] ) {
			return false;
		}
		maxSide = max( maxSide, maxs[i] - mins[i] );
	}

	// ignore tiny objects
	if( maxSide < 10 ) {
		return false;
	}

	rsc.entShadowGroups[R_ENT2NUM( ent )] = group->id;
	if( ent->flags & RF_WEAPONMODEL ) {
		return true;
	}

	if( ent->model->type == mod_brush ) {
		VectorCopy( mins, group->mins );
		VectorCopy( maxs, group->maxs );
	} else {
		// rotate local bounding box and compute the full bounding box for this group
		R_TransformBounds( ent->origin, ent->axis, mins, maxs, bbox );
		for( i = 0; i < 8; i++ ) {
			AddPointToBounds( bbox[i], group->mins, group->maxs );
		}
	}

	// increase projection distance if needed
	VectorSubtract( group->mins, origin, mins );
	VectorSubtract( group->maxs, origin, maxs );
	group->radius = RadiusFromBounds( mins, maxs );
	group->projDist = max( group->projDist, group->radius + min( r_shadows_projection_distance->value, 64.0f ) );

	return true;
}