Texture combiners

Posted 2010-05-14

What seems hard to achieve is basically very simple effect. The secret lies in additional render pass which overlays our new texture on top of source one (it's nothing that can't be done in UED, but this way reduces BSP complexity). Of course we're limited by UEngine 1 editor GUI but with few tricks effect can be quite impressive. What I've done is declared structure which holds all info about 'overlay' then in DrawComplexSurface I'm iterating through all of those overlays and render 'em. It's as simple as that. Below code snippet.

 

UBOOL UNMRenderDevice::DrawTextureCombiner(FSurfaceFacet& Facet, FSurfaceInfo& Surface)
{
	UNMTextureDDS* Texture = Cast(Surface.Texture->Texture);
	if( Texture != NULL && Texture->NumOverlays > 0 )
	{
		UBOOL bWasLit = 0;
		UBOOL bPerformRenderPass = 0;
		for(INT i=0; iNumOverlays; i++)
		{
			if( Texture->Overlays[i].Overlay == NULL )
				continue;		

			bPerformRenderPass = 1;
			UTexture* TmpTex = Texture->Overlays[i].Overlay->Get(Viewport->CurrentTime);
			FTextureInfo InfoX;
			TmpTex->Lock(InfoX,Viewport->CurrentTime, -1, this); 
			DWORD PFlags;
			
			if( Texture->Overlays[i].bSurfaceFlags )
				PFlags = Surface.PolyFlags;
			
			if( Texture->Overlays[i].bUnlit )
				PFlags |= PF_Unlit;

			if( Texture->Overlays[i].RenderStyle == RS_Translucent )
				PFlags |= PF_Translucent;
			else if( Texture->Overlays[i].RenderStyle == RS_Modulated )
				PFlags |= PF_Modulated;
			else if( Texture->Overlays[i].RenderStyle == RS_Alpha )
				PFlags |= PF_Masked;
			
			InfoX.Pan.X = Texture->Overlays[i].UOffset;
			InfoX.Pan.Y = Texture->Overlays[i].VOffset;	
			FLOAT T = Viewport->CurrentTime.GetFloat();

			if( Texture->Overlays[i].UScale > 0 )
				InfoX.UScale = Texture->Overlays[i].UScale;
			if( Texture->Overlays[i].VScale > 0 )
				InfoX.VScale = Texture->Overlays[i].VScale;

			if( Texture->Overlays[i].Wavy != WS_None )
			{
				InfoX.Pan.X += 7.0f * appSin(T) + 5.0f * appCos(3.14f*T);
				InfoX.Pan.Y += 7.0f * appCos(T) + 5.0f * appSin(3.14f*T);
			}
			else
			{
				if( Texture->Overlays[i].bUPan )
					Texture->UVModifiers[i].U += Texture->Overlays[i].UPanSpeed;
				if( Texture->Overlays[i].bVPan )
					Texture->UVModifiers[i].V += Texture->Overlays[i].VPanSpeed;
			
				if( Texture->Overlays[i].UOscillationType == OT_Pan )
					InfoX.Pan.X += Texture->Overlays[i].UOscillationAmplitude * appSin(T) + Texture->Overlays[i].UOscillationRate * appCos(Texture->Overlays[i].UOscillationPhase*T);
				
				if( Texture->Overlays[i].VOscillationType == OT_Pan )
					InfoX.Pan.Y += Texture->Overlays[i].VOscillationAmplitude * appCos(T) + Texture->Overlays[i].VOscillationRate * appSin(Texture->Overlays[i].VOscillationPhase*T);
			}
			InfoX.Pan.X += Texture->UVModifiers[i].U;
			InfoX.Pan.Y += Texture->UVModifiers[i].V;
			
			AddRenderPass(&InfoX, PFlags, 0.0f);
			TmpTex->Unlock(InfoX);

			if( !Texture->Overlays[i].bUnlit && Surface.LightMap && !bWasLit)
			{
				AddRenderPass(Surface.LightMap, PF_Modulated, -0.5f);
				bWasLit=1;
			}
			if( Texture->bSeparateRenderPass )
				RenderPasses();
		}
		if( !Texture->bSeparateRenderPass  && bPerformRenderPass)
				RenderPasses();
		return 1;
	}
	return 0;
}