class ShadowProjector extends Projector; var() Actor ShadowActor; var() vector LightDirection; var() float LightDistance; var() bool RootMotion; var() bool bBlobShadow; var() bool bShadowActive; var ShadowBitmapMaterial ShadowTexture; event PostBeginPlay() { Super(Actor).PostBeginPlay(); } event Destroyed() { if(ShadowTexture != None) { ShadowTexture.ShadowActor = None; if(!ShadowTexture.Invalid) Level.ObjectPool.FreeObject(ShadowTexture); ShadowTexture = None; ProjTexture = None; } Super.Destroyed(); } function InitShadow() { local Plane BoundingSphere; if(ShadowActor != None) { BoundingSphere = ShadowActor.GetRenderBoundingSphere(); FOV = Atan(BoundingSphere.W * 2 + 160, LightDistance) * 180 / PI; ShadowTexture = ShadowBitmapMaterial(Level.ObjectPool.AllocateObject(class'ShadowBitmapMaterial')); ProjTexture = ShadowTexture; if(ShadowTexture != None) { SetDrawScale(LightDistance * tan(0.5 * FOV * PI / 180) / (0.5 * ShadowTexture.USize)); ShadowTexture.Invalid = False; ShadowTexture.bBlobShadow = bBlobShadow; ShadowTexture.ShadowActor = ShadowActor; ShadowTexture.LightDirection = Normal(LightDirection); ShadowTexture.LightDistance = LightDistance; ShadowTexture.LightFOV = FOV; ShadowTexture.CullDistance = CullDistance; Enable('Tick'); UpdateShadow(); } else Log(Name$".InitShadow: Failed to allocate texture"); } else Log(Name$".InitShadow: No actor"); } function UpdateShadow() { local coords C; DetachProjector(true); if( (ShadowActor != None) && !ShadowActor.bHidden && (Level.TimeSeconds - ShadowActor.LastRenderTime < 4) && (ShadowTexture != None) && bShadowActive ) { if( ShadowTexture.Invalid ) Destroy(); else { if(RootMotion && ShadowActor.DrawType == DT_Mesh && ShadowActor.Mesh != None) { C = ShadowActor.GetBoneCoords(''); SetLocation(C.Origin); } else SetLocation(ShadowActor.Location + vect(0,0,5)); SetRotation(Rotator(Normal(-LightDirection))); ShadowTexture.Dirty = true; AttachProjector(); } } } function Tick(float DeltaTime) { UpdateShadow(); } defaultproperties { bShadowActive=True bProjectActor=False bProjectOnParallelBSP=True bProjectOnAlpha=True bClipBSP=True bGradient=True bStatic=False bOwnerNoSee=True bBlobShadow=False RemoteRole=ROLE_None CullDistance=1200.0 bDynamicAttach=True }