Пример #1
0
/*
================
idBrittleFracture::CreateFractures
================
*/
void idBrittleFracture::CreateFractures( const idRenderModel* renderModel )
{
	if( !renderModel || renderModel->NumSurfaces() < 1 )
	{
		return;
	}
	
	physicsObj.SetSelf( this );
	physicsObj.SetOrigin( GetPhysics()->GetOrigin(), 0 );
	physicsObj.SetAxis( GetPhysics()->GetAxis(), 0 );
	
	const modelSurface_t* surf = renderModel->Surface( 0 );
	material = surf->shader;
	
	idMat3 physAxis;
	physAxis = physicsObj.GetAxis();
	if( isXraySurface )
	{
		idFixedWinding w;
		
		for( int i = 0; i < 4; i++ )
		{
			const idDrawVert* v = &surf->geometry->verts[i];
			w.AddPoint( idVec5( v->xyz, v->GetTexCoord() ) );
		}
		
		idRandom2 random( entityNumber );
		Fracture_r( w , random );
		
	}
	else
	{
		const idDrawVert* verts = surf->geometry->verts;
		triIndex_t* indexes = surf->geometry->indexes;
		
		for( int j = 0; j < surf->geometry->numIndexes; j += 3 )
		{
			int i0 = indexes[ j + 0 ];
			int i1 = indexes[ j + 1 ];
			int i2 = indexes[ j + 2 ];
			idFixedWinding w;
			w.AddPoint( idVec5( verts[i2].xyz, verts[i2].GetTexCoord() ) );
			w.AddPoint( idVec5( verts[i1].xyz, verts[i1].GetTexCoord() ) );
			w.AddPoint( idVec5( verts[i0].xyz, verts[i0].GetTexCoord() ) );
			idPlane p1;
			w.GetPlane( p1 );
			for( int k = j + 3; k < surf->geometry->numIndexes && ( w.GetNumPoints() + 1 < MAX_POINTS_ON_WINDING ); k += 3 )
			{
				int i3 = indexes[ k + 0 ];
				int i4 = indexes[ k + 1 ];
				int i5 = indexes[ k + 2 ];
				idFixedWinding w2;
				w2.AddPoint( idVec5( verts[i5].xyz, verts[i5].GetTexCoord() ) );
				w2.AddPoint( idVec5( verts[i4].xyz, verts[i4].GetTexCoord() ) );
				w2.AddPoint( idVec5( verts[i3].xyz, verts[i3].GetTexCoord() ) );
				idPlane p2;
				w2.GetPlane( p2 );
				if( p1 != p2 )
				{
					break;
				}
				bool found = false;
				for( int w1i = 0; w1i < w.GetNumPoints(); w1i++ )
				{
					for( int w2i = 0; w2i < w2.GetNumPoints(); w2i++ )
					{
						if( CompareVec5( w[w1i], w2[w2i] ) && CompareVec5( w[( w1i + 1 ) % w.GetNumPoints()], w2[( w2i + 2 ) % w2.GetNumPoints()] ) )
						{
							w.InsertPoint( w2[( w2i + 1 ) % w2.GetNumPoints()], ( w1i + 1 ) % w.GetNumPoints() );
							j = k;
							found = true;
							break;
						}
					}
					if( found )
					{
						break;
					}
				}
				if( !found )
				{
					break;
				}
			}
			
			idRandom2 random( entityNumber );
			Fracture_r( w, random );
		}
	}
	
	
	physicsObj.SetContents( material->GetContentFlags() );
	SetPhysics( &physicsObj );
}
Пример #2
0
/*
=============
DrawStretchPic
=============
*/
void idGuiModel::DrawStretchPic( const idDrawVert *dverts, const glIndex_t *dindexes, int vertCount, int indexCount, const idMaterial *hShader, 
									   bool clip, float min_x, float min_y, float max_x, float max_y ) {
	if ( !glConfig.isInitialized ) {
		return;
	}
	if ( !( dverts && dindexes && vertCount && indexCount && hShader ) ) {
		return;
	}

	// break the current surface if we are changing to a new material
	if ( hShader != surf->material ) {
		if ( surf->numVerts ) {
			AdvanceSurf();
		}
		const_cast<idMaterial *>(hShader)->EnsureNotPurged();	// in case it was a gui item started before a level change
		surf->material = hShader;
	}

	// add the verts and indexes to the current surface

	if ( clip ) {
		int i, j;

		// FIXME:	this is grim stuff, and should be rewritten if we have any significant
		//			number of guis asking for clipping
		idFixedWinding w;
		for ( i = 0; i < indexCount; i += 3 ) {
			w.Clear();
			w.AddPoint(idVec5(dverts[dindexes[i]].xyz.x, dverts[dindexes[i]].xyz.y, dverts[dindexes[i]].xyz.z, dverts[dindexes[i]].st.x, dverts[dindexes[i]].st.y));
			w.AddPoint(idVec5(dverts[dindexes[i+1]].xyz.x, dverts[dindexes[i+1]].xyz.y, dverts[dindexes[i+1]].xyz.z, dverts[dindexes[i+1]].st.x, dverts[dindexes[i+1]].st.y));
			w.AddPoint(idVec5(dverts[dindexes[i+2]].xyz.x, dverts[dindexes[i+2]].xyz.y, dverts[dindexes[i+2]].xyz.z, dverts[dindexes[i+2]].st.x, dverts[dindexes[i+2]].st.y));

			for ( j = 0; j < 3; j++ ) {
				if ( w[j].x < min_x || w[j].x > max_x ||
					w[j].y < min_y || w[j].y > max_y ) {
					break;
				}
			}
			if ( j < 3 ) {
				idPlane p;
				p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = 1.0f; p.SetDist( min_x );
				w.ClipInPlace( p );
				p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = -1.0f; p.SetDist( -max_x );
				w.ClipInPlace( p );
				p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = 1.0f; p.SetDist( min_y );
				w.ClipInPlace( p );
				p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = -1.0f; p.SetDist( -max_y );
				w.ClipInPlace( p );
			}

			int	numVerts = verts.Num();
			verts.SetNum( numVerts + w.GetNumPoints(), false );
			for ( j = 0 ; j < w.GetNumPoints() ; j++ ) {
				idDrawVert *dv = &verts[numVerts+j];

				dv->xyz.x = w[j].x;
				dv->xyz.y = w[j].y;
				dv->xyz.z = w[j].z;
				dv->st.x = w[j].s;
				dv->st.y = w[j].t;
				dv->normal.Set(0, 0, 1);
				dv->tangents[0].Set(1, 0, 0);
				dv->tangents[1].Set(0, 1, 0);
			}
			surf->numVerts += w.GetNumPoints();

			for ( j = 2; j < w.GetNumPoints(); j++ ) {
				indexes.Append( numVerts - surf->firstVert );
				indexes.Append( numVerts + j - 1 - surf->firstVert );
				indexes.Append( numVerts + j - surf->firstVert );
				surf->numIndexes += 3;
			}
		}

	} else {

		int numVerts = verts.Num();
		int numIndexes = indexes.Num();

		verts.AssureSize( numVerts + vertCount );
		indexes.AssureSize( numIndexes + indexCount );

		surf->numVerts += vertCount;
		surf->numIndexes += indexCount;

		for ( int i = 0; i < indexCount; i++ ) {
			indexes[numIndexes + i] = numVerts + dindexes[i] - surf->firstVert;
		}

		memcpy( &verts[numVerts], dverts, vertCount * sizeof( verts[0] ) );
	}
}
Пример #3
0
/*
==============
sdDeployMaskEditSession::UpdateProjection
==============
*/
void sdDeployMaskEditSession::UpdateProjection( const idVec3& position ) {
	if ( !decalMaterial ) {
		return;
	}

	if ( decalHandle == -1 ) {
		decalHandle = gameLocal.RegisterLoggedDecal( decalMaterial );
	}
	gameLocal.ResetLoggedDecal( decalHandle );

	gameDecalInfo_t* decalInfo = gameLocal.GetLoggedDecal( decalHandle );

	sdDeployMaskInstance* mask = GetMask( position );
	const sdHeightMapInstance* heightMap = GetHeightMap( position );

	if ( mask != NULL && mask->IsValid() && heightMap != NULL ) {
		sdDeployMask::extents_t extents;
		GetExtents( position, *mask, extents );

		float depth = 512.0f;

		int maxX, maxY;
		mask->GetDimensions( maxX, maxY );

		sdDeployMask::extents_t expandedExtents;

		expandedExtents.minx = Max( 0, extents.minx - 2 );
		expandedExtents.miny = Max( 0, extents.miny - 2 );

		expandedExtents.maxx = Min( maxX, extents.maxx + 2 );
		expandedExtents.maxy = Min( maxY, extents.maxy + 2 );

		idList< const idMaterial* > megaTextureMaterials;
		const idStrList& megaTextureMaterialNames = gameLocal.GetMapInfo().GetMegatextureMaterials();
		for ( int i = 0; i < megaTextureMaterialNames.Num(); i++ ) {
			megaTextureMaterials.Append( declHolder.FindMaterial( megaTextureMaterialNames[ i ] ) );
		}

		idFixedWinding winding;
		
		int spawnID = WORLD_SPAWN_ID;

		for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) {
			for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) {
				gameDecalInfo_t* info = decalInfo;
				if ( !info ) {
					continue;
				}

				sdDeployMask::extents_t localExtents;
				localExtents.minx = i;
				localExtents.maxx = i;
				localExtents.miny = j;
				localExtents.maxy = j;

				idBounds bounds;
				mask->GetBounds( localExtents, bounds, heightMap );

				idVec3 top = bounds.GetCenter();
				top[ 2 ] = bounds.GetMaxs()[ 2 ];				

				deployResult_t localResult = mask->IsValid( localExtents );

				idVec4 localColor;
				switch ( localResult ) {
					case DR_CLEAR:
						localColor = colorGreen;
						break;
					default:
					case DR_FAILED:
						localColor = colorDkRed;
						break;
				}

				if ( !( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ) {
					localColor.x *= 0.3f;
					localColor.y *= 0.3f;
					localColor.z *= 0.3f;
				}

				winding.Clear();
				winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 0.0f ) );
				winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 1.0f ) );
				winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 1.0f ) );
				winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 0.0f ) );

				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0, 0, 64.f + depth ), true, localColor, info->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );
			}
		}
	}
}
Пример #4
0
/*
==============
sdDeployMenu::Update
==============
*/
void sdDeployMenu::Update( void ) {
	sdHudModule::Update();

	idPlayer* localPlayer = gameLocal.GetLocalPlayer();

	if ( !deployableObject || !localPlayer ) {
		return;
	}

	deployResult_t result = localPlayer->GetDeployResult( position, deployableObject );

	if ( result != DR_OUT_OF_RANGE ) {

		if ( deployableRenderEntityHandle < 0 ) {
			deployableRenderEntityHandle = gameRenderWorld->AddEntityDef( &deployableRenderEntity );
		}

		idVec4 color;
		switch ( deployableState ) {
			case DR_CLEAR:
				color = colorGreen;
				break;
			case DR_WARNING:
				color = colorOrange;
				break;
			case DR_CONDITION_FAILED:
				color = colorWhite;
				break;
			default:
			case DR_FAILED:
				color = colorDkRed;
				break;
		}

		if ( decalHandle == -1 ) {
			decalHandle = gameLocal.RegisterLoggedDecal( decalMaterial );
			lastExpandedExtents.minx = -1;
		}
		if ( decalHandleOuter == -1 ) {
			decalHandleOuter = gameLocal.RegisterLoggedDecal( decalMaterialOuter );
			lastExpandedExtents.minx = -1;
		}
		if ( decalHandleArrows == -1 ) {
			decalHandleArrows = gameLocal.RegisterLoggedDecal( decalMaterialArrows );
		}
		gameLocal.ResetLoggedDecal( decalHandleArrows );

		gameDecalInfo_t* decalInfo = gameLocal.GetLoggedDecal( decalHandle );
		gameDecalInfo_t* decalInfoOuter = gameLocal.GetLoggedDecal( decalHandleOuter );
		gameDecalInfo_t* decalInfoArrows = gameLocal.GetLoggedDecal( decalHandleArrows );

		if ( !deployableObject->AllowRotation() ) {
			rotation = 0.0f;
		}

		idMat3 rotationStart;
		idAngles::YawToMat3( rotation, rotationStart );

		const sdPlayZone* playZone = gameLocal.GetPlayZone( position, sdPlayZone::PZF_DEPLOYMENT );

		const sdPlayZone* playZoneHeight = gameLocal.GetPlayZone( position, sdPlayZone::PZF_HEIGHTMAP );
		const sdHeightMapInstance* heightMap = NULL;
		if ( playZoneHeight ) {
			heightMap = &playZoneHeight->GetHeightMap();
		}

		const sdDeployMaskInstance* mask = NULL;

		if ( playZone ) {
			mask = playZone->GetMask( deployableObject->GetDeploymentMask() );
		}

		if ( mask && mask->IsValid() && heightMap && heightMap->IsValid() ) {
			idBounds bounds( position );
			bounds.ExpandSelf( deployableObject->GetObjectSize() );

			sdDeployMask::extents_t extents;
			mask->CoordsForBounds( bounds, extents );

			idBounds mainBounds;
			mask->GetBounds( extents, mainBounds, heightMap );

			float depth = 512.0f;
			idVec3 top;

			idBounds moveArrowBounds = mainBounds;
			idBounds rotateArrowBounds = mainBounds;

			// straight arrows
			moveArrowBounds.GetMaxs().y = moveArrowBounds.GetCenter().y;
			moveArrowBounds.GetMins().y += 0.25f * ( mainBounds.GetMaxs().y - mainBounds.GetMins().y );
			moveArrowBounds.GetMaxs().y += 0.25f * ( mainBounds.GetMaxs().y - mainBounds.GetMins().y );
			moveArrowBounds.GetMins().x = moveArrowBounds.GetCenter().x;
			{
				idVec3 center = moveArrowBounds.GetCenter();
				moveArrowBounds.TranslateSelf( -center );
				for ( int index = 0; index < 3; index++ ) {
					moveArrowBounds.GetMins()[ index ] *= 0.25f;
					moveArrowBounds.GetMaxs()[ index ] *= 0.25f;
				}
				moveArrowBounds.TranslateSelf( center );
			}

			// rotate arrows
			rotateArrowBounds.GetMins().x = rotateArrowBounds.GetCenter().x;
			{
				idVec3 center = rotateArrowBounds.GetCenter();
				rotateArrowBounds.TranslateSelf( -center );
				for ( int index = 0; index < 3; index++ ) {
					rotateArrowBounds.GetMins()[ index ] *= 0.2f;
					rotateArrowBounds.GetMaxs()[ index ] *= 0.2f;
				}
				rotateArrowBounds.TranslateSelf( center );
			}

			top = mainBounds.GetCenter();
			top[ 2 ] = mainBounds.GetMaxs()[ 2 ];

			idList< const idMaterial* > megaTextureMaterials;
			const idStrList& megaTextureMaterialNames = gameLocal.GetMapInfo().GetMegatextureMaterials();
			for ( int i = 0; i < megaTextureMaterialNames.Num(); i++ ) {
				megaTextureMaterials.Append( declHolder.FindMaterial( megaTextureMaterialNames[ i ] ) );
			}

			idFixedWinding winding;

			int spawnID = WORLD_SPAWN_ID;

			if ( GetDeployMode() ) {
				// rotate mode

				idMat3 rotationOffset;
				idAngles::YawToMat3( 120.0f, rotationOffset );

				// forward arrow
				winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.0f ) );
				winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.5f ) );
				winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.5f ) );
				winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.0f ) );

				winding.Rotate( mainBounds.GetCenter(), rotationStart );
				idVec3 offset = rotationStart[ 0 ] * ( 16.f * idMath::Sin( ( gameLocal.time / 500.f ) ) );
				for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
					winding[ i ].ToVec3() += offset;
				}
				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, idVec4( 0.87f, 0.59f, 0.f, 1.f ), decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );

				// rotate arrows
				winding.Clear();
				winding += idVec5( idVec3( rotateArrowBounds.GetMins().x, rotateArrowBounds.GetMins().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.0f, 0.0f ) );
				winding += idVec5( idVec3( rotateArrowBounds.GetMins().x, rotateArrowBounds.GetMaxs().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.0f, 1.0f ) );
				winding += idVec5( idVec3( rotateArrowBounds.GetMaxs().x, rotateArrowBounds.GetMaxs().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 1.0f ) );
				winding += idVec5( idVec3( rotateArrowBounds.GetMaxs().x, rotateArrowBounds.GetMins().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.0f ) );

				winding.Rotate( mainBounds.GetCenter(), rotationStart * rotationOffset );
				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );

				winding.Rotate( mainBounds.GetCenter(), rotationOffset );
				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );
			} else {
				// move mode

				idMat3 rotationOffset;
				idAngles::YawToMat3( 90.0f, rotationOffset );

				winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.0f ) );
				winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.5f ) );
				winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.5f ) );
				winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.0f ) );

				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );

				winding.Rotate( mainBounds.GetCenter(), rotationOffset );
				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );

				winding.Rotate( mainBounds.GetCenter(), rotationOffset );
				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );

				winding.Rotate( mainBounds.GetCenter(), rotationOffset );
				gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );
			}

			// the grid
			int maxX, maxY;
			mask->GetDimensions( maxX, maxY );

			sdDeployMask::extents_t expandedExtents;

			expandedExtents.minx = Max( 0, extents.minx - 2 );
			expandedExtents.miny = Max( 0, extents.miny - 2 );

			expandedExtents.maxx = Min( maxX, extents.maxx + 2 );
			expandedExtents.maxy = Min( maxY, extents.maxy + 2 );

			int w = expandedExtents.maxx - expandedExtents.minx + 1;
			int h = expandedExtents.maxx - expandedExtents.minx + 1;
			int terrIdx = 0;
			bool regen = false;

			if ( ( w * h ) > sizeof( lastTerritory ) / sizeof( lastTerritory[0] ) ) {
				common->Warning( "test territory size too large" );
				return;
			}

			for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) {
				for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) {
					gameDecalInfo_t* info = ( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ? decalInfo : decalInfoOuter;
					if ( !info ) {
						continue;
					}

					sdDeployMask::extents_t localExtents;
					localExtents.minx = i;
					localExtents.maxx = i;
					localExtents.miny = j;
					localExtents.maxy = j;

					mask->GetBounds( localExtents, bounds, heightMap );

					top = bounds.GetCenter();
					top[ 2 ] = bounds.GetMaxs()[ 2 ];

					deployResult_t localResult = localPlayer->CheckBoundsForDeployment( localExtents, *mask, deployableObject, playZoneHeight );

					bool hasTerritory;
					if ( localResult == DR_CLEAR ) {
						hasTerritory = gameLocal.TerritoryForPoint( top, localPlayer->GetGameTeam(), true ) != NULL;
					} else {
						hasTerritory = false;
					}
					if ( hasTerritory != lastTerritory[ terrIdx ] ) {
						regen = true;
					}
					lastTerritory[ terrIdx++ ] = hasTerritory;
				}
			}

			if ( expandedExtents.minx != lastExpandedExtents.minx || expandedExtents.maxx != lastExpandedExtents.maxx ||
				expandedExtents.miny != lastExpandedExtents.miny || expandedExtents.maxy != lastExpandedExtents.maxy || regen ) {
				gameLocal.ResetLoggedDecal( decalHandle );
				gameLocal.ResetLoggedDecal( decalHandleOuter );

				lastExpandedExtents = expandedExtents;

				terrIdx = 0;
				for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) {
					for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) {
						gameDecalInfo_t* info = ( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ? decalInfo : decalInfoOuter;
						if ( !info ) {
							continue;
						}

						sdDeployMask::extents_t localExtents;
						localExtents.minx = i;
						localExtents.maxx = i;
						localExtents.miny = j;
						localExtents.maxy = j;

						mask->GetBounds( localExtents, bounds, heightMap );

						top = bounds.GetCenter();
						top[ 2 ] = bounds.GetMaxs()[ 2 ];

						//bool hasTerritory = gameLocal.TerritoryForPoint( top, localPlayer->GetGameTeam(), true ) != NULL;
						deployResult_t localResult = localPlayer->CheckBoundsForDeployment( localExtents, *mask, deployableObject, playZoneHeight );

						idVec4 localColor;
						switch ( localResult ) {
							case DR_CLEAR:
								if ( !lastTerritory[ terrIdx ] ) {
									localColor = colorOrange;
								} else {
									localColor = colorGreen;
								}
								break;
							case DR_WARNING:
								localColor = colorOrange;
								break;
							case DR_FAILED:
								localColor = colorDkRed;
								break;
						}

						winding.Clear();
						winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 0.0f ) );
						winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 1.0f ) );
						winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 1.0f ) );
						winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 0.0f ) );

	//					gameRenderWorld->DebugBounds( localColor, bounds );
	//					gameRenderWorld->DrawText( va( "%i %i", i, j ), top, 0.5, colorWhite, gameLocal.GetLocalPlayer()->GetRenderView()->viewaxis );

						gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0, 0, 64.f + depth ), true, localColor, info->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() );
						terrIdx++;
					}
				}
			}
		} else {
			gameLocal.ResetLoggedDecal( decalHandle );
			gameLocal.ResetLoggedDecal( decalHandleOuter );
			lastExpandedExtents.minx = -1;
		}

		idVec3 modelPos = position;
		if ( playZoneHeight ) {
			const sdHeightMapInstance& heightMap = playZoneHeight->GetHeightMap();
			if ( heightMap.IsValid() ) {
				modelPos.z = heightMap.GetHeight( modelPos );
			}
		}

		sdDeployRequest::UpdateRenderEntity( deployableRenderEntity, color, modelPos );
		deployableRenderEntity.axis = rotationStart;
		gameRenderWorld->UpdateEntityDef( deployableRenderEntityHandle, &deployableRenderEntity );
	} else {
		if ( deployableRenderEntityHandle >= 0 ) {
			gameRenderWorld->FreeEntityDef( deployableRenderEntityHandle );
			deployableRenderEntityHandle = -1;
		}
		FreeDecals();
	}
}