mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-08-20 17:09:19 +08:00
1303 lines
51 KiB
C#
1303 lines
51 KiB
C#
using CodeWalker.GameFiles;
|
|
using CodeWalker.Properties;
|
|
using CodeWalker.World;
|
|
using SharpDX;
|
|
using SharpDX.Direct3D11;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace CodeWalker.Rendering
|
|
{
|
|
public class ShaderManager
|
|
{
|
|
private DXManager DXMan;
|
|
|
|
private int GeometryCount;
|
|
public int RenderedGeometries;
|
|
|
|
private Device Device;
|
|
|
|
public bool wireframe = Settings.Default.Wireframe;
|
|
RasterizerState rsSolid;
|
|
RasterizerState rsWireframe;
|
|
RasterizerState rsSolidDblSided;
|
|
RasterizerState rsWireframeDblSided;
|
|
BlendState bsDefault;
|
|
BlendState bsAlpha;
|
|
BlendState bsAdd;
|
|
DepthStencilState dsEnabled;
|
|
DepthStencilState dsDisableAll;
|
|
DepthStencilState dsDisableComp;
|
|
DepthStencilState dsDisableWrite;
|
|
|
|
|
|
|
|
public PostProcessor HDR { get; set; }
|
|
public BasicShader Basic { get; set; }
|
|
public CableShader Cable { get; set; }
|
|
public WaterShader Water { get; set; }
|
|
public TerrainShader Terrain { get; set; }
|
|
public TreesLodShader TreesLod { get; set; }
|
|
public SkydomeShader Skydome { get; set; }
|
|
public CloudsShader Clouds { get; set; }
|
|
public MarkerShader Marker { get; set; }
|
|
public BoundsShader Bounds { get; set; }
|
|
public ShadowShader Shadow { get; set; }
|
|
public DistantLightsShader DistLights { get; set; }
|
|
public PathShader Paths { get; set; }
|
|
public WidgetShader Widgets { get; set; }
|
|
|
|
public bool shadows = Settings.Default.Shadows;
|
|
public Shadowmap Shadowmap { get; set; }
|
|
List<RenderableGeometryInst> shadowcasters = new List<RenderableGeometryInst>();
|
|
List<RenderableGeometryInst> shadowbatch = new List<RenderableGeometryInst>();
|
|
List<ShaderBatch> shadowbatches = new List<ShaderBatch>();
|
|
int shadowcastercount = 0; //total casters rendered
|
|
|
|
public bool hdr = Settings.Default.HDR;
|
|
public float hdrLumBlendSpeed = 1.0f;
|
|
int Width;
|
|
int Height;
|
|
|
|
private bool disposed = false;
|
|
|
|
|
|
public List<ShaderRenderBucket> RenderBuckets = new List<ShaderRenderBucket>();
|
|
public List<RenderableBoundGeometryInst> RenderBoundGeoms = new List<RenderableBoundGeometryInst>();
|
|
public List<RenderableInstanceBatchInst> RenderInstBatches = new List<RenderableInstanceBatchInst>();
|
|
public List<RenderableDistantLODLights> RenderDistLODLights = new List<RenderableDistantLODLights>();
|
|
public List<RenderablePathBatch> RenderPathBatches = new List<RenderablePathBatch>();
|
|
public List<RenderableWaterQuad> RenderWaterQuads = new List<RenderableWaterQuad>();
|
|
|
|
public bool AnisotropicFiltering = true;
|
|
public WorldRenderMode RenderMode = WorldRenderMode.Default;
|
|
public int RenderVertexColourIndex = 1;
|
|
public int RenderTextureCoordIndex = 1;
|
|
public int RenderTextureSamplerCoord = 1;
|
|
public MetaName RenderTextureSampler = MetaName.DiffuseSampler;
|
|
public double CurrentRealTime = 0;
|
|
public float CurrentElapsedTime = 0;
|
|
|
|
private Camera Camera;
|
|
public ShaderGlobalLights GlobalLights = new ShaderGlobalLights();
|
|
public bool PathsDepthClip = true;//false;//
|
|
|
|
private GameFileCache GameFileCache;
|
|
private RenderableCache RenderableCache;
|
|
|
|
|
|
public long TotalGraphicsMemoryUse
|
|
{
|
|
get
|
|
{
|
|
long u = 0;
|
|
if (HDR != null)
|
|
{
|
|
u += HDR.VramUsage;
|
|
}
|
|
if (Shadowmap != null)
|
|
{
|
|
u += Shadowmap.VramUsage;
|
|
}
|
|
return u;
|
|
}
|
|
}
|
|
|
|
|
|
public ShaderManager(Device device, DXManager dxman)
|
|
{
|
|
Device = device;
|
|
DXMan = dxman;
|
|
|
|
//HDR = new PostProcessor(dxman);
|
|
Basic = new BasicShader(device);
|
|
Cable = new CableShader(device);
|
|
Water = new WaterShader(device);
|
|
Terrain = new TerrainShader(device);
|
|
TreesLod = new TreesLodShader(device);
|
|
Skydome = new SkydomeShader(device);
|
|
Clouds = new CloudsShader(device);
|
|
Marker = new MarkerShader(device);
|
|
Bounds = new BoundsShader(device);
|
|
Shadow = new ShadowShader(device);
|
|
DistLights = new DistantLightsShader(device);
|
|
Paths = new PathShader(device);
|
|
Widgets = new WidgetShader(device);
|
|
|
|
|
|
RasterizerStateDescription rsd = new RasterizerStateDescription()
|
|
{
|
|
CullMode = CullMode.Back,
|
|
DepthBias = 0,
|
|
DepthBiasClamp = 0.0f,
|
|
FillMode = FillMode.Solid,
|
|
IsAntialiasedLineEnabled = true,
|
|
IsDepthClipEnabled = true,
|
|
IsFrontCounterClockwise = true,
|
|
IsMultisampleEnabled = true,
|
|
IsScissorEnabled = false,
|
|
SlopeScaledDepthBias = 0.0f
|
|
};
|
|
rsSolid = new RasterizerState(device, rsd);
|
|
rsd.FillMode = FillMode.Wireframe;
|
|
rsWireframe = new RasterizerState(device, rsd);
|
|
rsd.CullMode = CullMode.None;
|
|
rsWireframeDblSided = new RasterizerState(device, rsd);
|
|
rsd.FillMode = FillMode.Solid;
|
|
rsSolidDblSided = new RasterizerState(device, rsd);
|
|
|
|
|
|
BlendStateDescription bsd = new BlendStateDescription()
|
|
{
|
|
AlphaToCoverageEnable = false,//true,
|
|
IndependentBlendEnable = false,
|
|
};
|
|
bsd.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add;
|
|
bsd.RenderTarget[0].BlendOperation = BlendOperation.Add;
|
|
bsd.RenderTarget[0].DestinationAlphaBlend = BlendOption.One;
|
|
bsd.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha;
|
|
bsd.RenderTarget[0].IsBlendEnabled = true;
|
|
bsd.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;
|
|
bsd.RenderTarget[0].SourceAlphaBlend = BlendOption.Zero;
|
|
bsd.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha;
|
|
bsDefault = new BlendState(device, bsd);
|
|
|
|
bsd.AlphaToCoverageEnable = true;
|
|
bsAlpha = new BlendState(device, bsd);
|
|
|
|
bsd.AlphaToCoverageEnable = false;
|
|
bsd.RenderTarget[0].DestinationBlend = BlendOption.One;
|
|
bsAdd = new BlendState(device, bsd);
|
|
|
|
DepthStencilStateDescription dsd = new DepthStencilStateDescription()
|
|
{
|
|
BackFace = new DepthStencilOperationDescription()
|
|
{
|
|
Comparison = Comparison.LessEqual,
|
|
DepthFailOperation = StencilOperation.Zero,
|
|
FailOperation = StencilOperation.Zero,
|
|
PassOperation = StencilOperation.Zero,
|
|
},
|
|
DepthComparison = Comparison.LessEqual,
|
|
DepthWriteMask = DepthWriteMask.All,
|
|
FrontFace = new DepthStencilOperationDescription()
|
|
{
|
|
Comparison = Comparison.LessEqual,
|
|
DepthFailOperation = StencilOperation.Zero,
|
|
FailOperation = StencilOperation.Zero,
|
|
PassOperation = StencilOperation.Zero
|
|
},
|
|
IsDepthEnabled = true,
|
|
IsStencilEnabled = false,
|
|
StencilReadMask = 0,
|
|
StencilWriteMask = 0
|
|
};
|
|
dsEnabled = new DepthStencilState(device, dsd);
|
|
dsd.DepthWriteMask = DepthWriteMask.Zero;
|
|
dsDisableWrite = new DepthStencilState(device, dsd);
|
|
dsd.DepthComparison = Comparison.Always;
|
|
dsDisableComp = new DepthStencilState(device, dsd);
|
|
dsd.IsDepthEnabled = false;
|
|
dsDisableAll = new DepthStencilState(device, dsd);
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
{
|
|
if (disposed) return;
|
|
disposed = true;
|
|
|
|
dsEnabled.Dispose();
|
|
dsDisableWrite.Dispose();
|
|
dsDisableComp.Dispose();
|
|
dsDisableAll.Dispose();
|
|
bsDefault.Dispose();
|
|
bsAlpha.Dispose();
|
|
bsAdd.Dispose();
|
|
rsSolid.Dispose();
|
|
rsWireframe.Dispose();
|
|
|
|
Widgets.Dispose();
|
|
Paths.Dispose();
|
|
DistLights.Dispose();
|
|
Shadow.Dispose();
|
|
Bounds.Dispose();
|
|
Marker.Dispose();
|
|
Terrain.Dispose();
|
|
TreesLod.Dispose();
|
|
Skydome.Dispose();
|
|
Clouds.Dispose();
|
|
Basic.Dispose();
|
|
Cable.Dispose();
|
|
Water.Dispose();
|
|
|
|
if (HDR != null)
|
|
{
|
|
HDR.Dispose();
|
|
HDR = null;
|
|
}
|
|
|
|
if (Shadowmap != null)
|
|
{
|
|
Shadowmap.Dispose();
|
|
Shadowmap = null;
|
|
}
|
|
}
|
|
|
|
|
|
public void SetGlobalLightParams(ShaderGlobalLights lights)
|
|
{
|
|
GlobalLights.CurrentSunDir = lights.CurrentSunDir;
|
|
GlobalLights.CurrentMoonDir = lights.CurrentMoonDir;
|
|
GlobalLights.HdrEnabled = lights.HdrEnabled;
|
|
GlobalLights.HdrIntensity = lights.HdrIntensity;
|
|
GlobalLights.SpecularEnabled = lights.SpecularEnabled;
|
|
GlobalLights.Weather = lights.Weather;
|
|
GlobalLights.Params = lights.Params;
|
|
}
|
|
|
|
public void BeginFrame(DeviceContext context, double currentRealTime, float elapsedTime)
|
|
{
|
|
CurrentRealTime = currentRealTime;
|
|
CurrentElapsedTime = elapsedTime;
|
|
|
|
shadowcasters.Clear();
|
|
if (shadows && (Shadowmap == null))
|
|
{
|
|
Shadowmap = new Shadowmap(Device);
|
|
}
|
|
if (!shadows && (Shadowmap != null))
|
|
{
|
|
Shadowmap.Dispose();
|
|
Shadowmap = null;
|
|
}
|
|
if (hdr && (HDR == null))
|
|
{
|
|
HDR = new PostProcessor(DXMan);
|
|
HDR.OnWindowResize(DXMan);
|
|
HDR.LumBlendSpeed = hdrLumBlendSpeed;
|
|
}
|
|
if (!hdr && (HDR != null))
|
|
{
|
|
HDR.Dispose();
|
|
HDR = null;
|
|
}
|
|
|
|
|
|
foreach (var bucket in RenderBuckets)
|
|
{
|
|
bucket.Clear();
|
|
}
|
|
|
|
RenderBoundGeoms.Clear();
|
|
RenderInstBatches.Clear();
|
|
RenderDistLODLights.Clear();
|
|
RenderPathBatches.Clear();
|
|
RenderWaterQuads.Clear();
|
|
|
|
if (HDR != null)
|
|
{
|
|
HDR.Clear(context);
|
|
HDR.ClearDepth(context);
|
|
HDR.SetPrimary(context); //for rendering some things before shadowmaps... (eg sky)
|
|
}
|
|
else
|
|
{
|
|
DXMan.SetDefaultRenderTarget(context);
|
|
}
|
|
|
|
Skydome.EnableHDR = hdr;
|
|
Clouds.EnableHDR = hdr;
|
|
}
|
|
|
|
|
|
public void EnsureShaderTextures(GameFileCache gameFileCache, RenderableCache renderableCache)
|
|
{
|
|
if (!gameFileCache.IsInited) return;
|
|
|
|
GameFileCache = gameFileCache;
|
|
RenderableCache = renderableCache;
|
|
|
|
uint graphics = 3154743001; //JenkHash.GenHash("graphics");
|
|
uint waterbump = 2826194296; //JenkHash.GenHash("waterbump");
|
|
uint waterbump2 = 209023451; //JenkHash.GenHash("waterbump2");
|
|
uint waterfog = 4047019542;
|
|
Water.waterbump = EnsureTexture(graphics, waterbump);
|
|
Water.waterbump2 = EnsureTexture(graphics, waterbump2);
|
|
Water.waterfog = EnsureTexture(graphics, waterfog);
|
|
|
|
|
|
|
|
}
|
|
|
|
private RenderableTexture EnsureTexture(uint texDict, uint texName)
|
|
{
|
|
YtdFile ytd = GameFileCache.GetYtd(texDict);
|
|
if ((ytd != null) && (ytd.Loaded) && (ytd.TextureDict != null))
|
|
{
|
|
var dtex = ytd.TextureDict.Lookup(texName);
|
|
return RenderableCache.GetRenderableTexture(dtex);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void RenderQueued(DeviceContext context, Camera camera, Vector4 wind)
|
|
{
|
|
GeometryCount = 0;
|
|
Camera = camera;
|
|
|
|
|
|
SetShaderRenderModeParams();
|
|
|
|
Basic.WindVector = wind;
|
|
Shadow.WindVector = wind;
|
|
Water.CurrentRealTime = CurrentRealTime;
|
|
Water.CurrentElapsedTime = CurrentElapsedTime;
|
|
|
|
shadowbatches.Clear();
|
|
for (int i = 0; i < RenderBuckets.Count; i++)
|
|
{
|
|
var bucket = RenderBuckets[i];
|
|
|
|
//sort the bucket's batches based on the shader file hashes
|
|
bucket.GroupBatches();
|
|
|
|
if (shadows)
|
|
{
|
|
shadowbatches.AddRange(bucket.BasicBatches);
|
|
shadowbatches.AddRange(bucket.TerrainBatches);
|
|
shadowbatches.AddRange(bucket.CableBatches);
|
|
shadowbatches.AddRange(bucket.AlphaBatches);
|
|
shadowbatches.AddRange(bucket.CutoutBatches);
|
|
shadowbatches.AddRange(bucket.ClothBatches);
|
|
}
|
|
}
|
|
|
|
|
|
if (shadows)
|
|
{
|
|
RenderShadowmap(context);
|
|
}
|
|
|
|
|
|
if (HDR != null)
|
|
{
|
|
HDR.SetPrimary(context);
|
|
}
|
|
else
|
|
{
|
|
DXMan.SetDefaultRenderTarget(context);
|
|
}
|
|
|
|
for (int i = 0; i < RenderBuckets.Count; i++) //"solid" objects pass
|
|
{
|
|
var bucket = RenderBuckets[i];
|
|
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
context.Rasterizer.State = wireframe ? rsWireframe : rsSolid;
|
|
|
|
if (bucket.TerrainBatches.Count > 0)
|
|
{
|
|
RenderGeometryBatches(context, bucket.TerrainBatches, Terrain);
|
|
}
|
|
if (bucket.BasicBatches.Count > 0)
|
|
{
|
|
RenderGeometryBatches(context, bucket.BasicBatches, Basic);
|
|
}
|
|
if (bucket.TreesLodBatches.Count > 0)
|
|
{
|
|
context.Rasterizer.State = wireframe ? rsWireframeDblSided : rsSolidDblSided;
|
|
RenderGeometryBatches(context, bucket.TreesLodBatches, TreesLod);
|
|
}
|
|
if (bucket.CutoutBatches.Count > 0)
|
|
{
|
|
context.Rasterizer.State = wireframe ? rsWireframeDblSided : rsSolidDblSided;
|
|
RenderGeometryBatches(context, bucket.CutoutBatches, Basic);
|
|
}
|
|
if (bucket.ClothBatches.Count > 0)
|
|
{
|
|
context.Rasterizer.State = wireframe ? rsWireframeDblSided : rsSolidDblSided;
|
|
RenderGeometryBatches(context, bucket.ClothBatches, Basic);
|
|
}
|
|
if (bucket.CableBatches.Count > 0)
|
|
{
|
|
context.Rasterizer.State = wireframe ? rsWireframe : rsSolid;
|
|
RenderGeometryBatches(context, bucket.CableBatches, Cable);
|
|
}
|
|
if (bucket.DecalBatches.Count > 0)
|
|
{
|
|
context.Rasterizer.State = wireframe ? rsWireframe : rsSolid;
|
|
context.OutputMerger.DepthStencilState = dsDisableWrite;
|
|
Basic.DecalMode = true;
|
|
RenderGeometryBatches(context, bucket.DecalBatches, Basic);
|
|
Basic.DecalMode = false;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
}
|
|
}
|
|
|
|
|
|
if (RenderInstBatches.Count > 0) //grass pass
|
|
{
|
|
context.Rasterizer.State = wireframe ? rsWireframeDblSided : rsSolidDblSided;
|
|
context.OutputMerger.BlendState = bsAlpha; //alpha to coverage for grass...
|
|
Basic.DecalMode = true;
|
|
Basic.AlphaScale = 7.0f; //instanced grass alpha scale...
|
|
Basic.SetShader(context);
|
|
Basic.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
|
for (int i = 0; i < RenderInstBatches.Count; i++)
|
|
{
|
|
RenderInstancedBatch(context, RenderInstBatches[i]);
|
|
}
|
|
Basic.UnbindResources(context);
|
|
Basic.AlphaScale = 1.0f;
|
|
Basic.DecalMode = false;
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
}
|
|
|
|
if (RenderDistLODLights.Count > 0) //LOD lights pass
|
|
{
|
|
context.Rasterizer.State = rsSolidDblSided;
|
|
context.OutputMerger.BlendState = bsAdd; //additive blend for distant lod lights...
|
|
context.OutputMerger.DepthStencilState = dsDisableWrite;
|
|
DistLights.SetShader(context);
|
|
DistLights.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
|
for (int i = 0; i < RenderDistLODLights.Count; i++)
|
|
{
|
|
DistLights.RenderBatch(context, RenderDistLODLights[i]);
|
|
}
|
|
DistLights.UnbindResources(context);
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
}
|
|
|
|
|
|
|
|
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.Rasterizer.State = wireframe ? rsWireframeDblSided : rsSolidDblSided;
|
|
context.OutputMerger.DepthStencilState = dsDisableWrite;
|
|
|
|
for (int i = 0; i < RenderBuckets.Count; i++) //water pass
|
|
{
|
|
var bucket = RenderBuckets[i];
|
|
if (bucket.WaterBatches.Count > 0)
|
|
{
|
|
RenderGeometryBatches(context, bucket.WaterBatches, Water);
|
|
}
|
|
if (bucket.Water2Batches.Count > 0)
|
|
{
|
|
RenderGeometryBatches(context, bucket.Water2Batches, Water);
|
|
}
|
|
}
|
|
if (RenderWaterQuads.Count > 0) //also render water quads here
|
|
{
|
|
Water.SetShader(context);
|
|
Water.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
|
for (int i = 0; i < RenderWaterQuads.Count; i++)
|
|
{
|
|
Water.RenderWaterQuad(context, RenderWaterQuads[i]);
|
|
}
|
|
Water.UnbindResources(context);
|
|
}
|
|
|
|
Basic.DecalMode = true;
|
|
for (int i = 0; i < RenderBuckets.Count; i++) //alphablended and glass pass
|
|
{
|
|
var bucket = RenderBuckets[i];
|
|
|
|
if (bucket.AlphaBatches.Count > 0)
|
|
{
|
|
//context.OutputMerger.BlendState = bsAlpha;
|
|
RenderGeometryBatches(context, bucket.AlphaBatches, Basic);
|
|
}
|
|
if (bucket.GlassBatches.Count > 0)
|
|
{
|
|
RenderGeometryBatches(context, bucket.GlassBatches, Basic);
|
|
}
|
|
}
|
|
Basic.DecalMode = false;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
|
|
|
|
|
|
if (RenderBoundGeoms.Count > 0) //collision meshes pass
|
|
{
|
|
ClearDepth(context); //draw over everything else
|
|
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
context.Rasterizer.State = wireframe ? rsWireframe : rsSolid;
|
|
|
|
RenderBoundGeometryBatch(context, RenderBoundGeoms);
|
|
}
|
|
|
|
|
|
if (RenderPathBatches.Count > 0) //paths pass
|
|
{
|
|
//ClearDepth(context); //draw over everything else
|
|
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = PathsDepthClip ? dsDisableWrite : dsDisableAll;// dsEnabled; //
|
|
context.Rasterizer.State = rsSolid;
|
|
|
|
Paths.RenderBatches(context, RenderPathBatches, camera, GlobalLights);
|
|
}
|
|
|
|
|
|
|
|
RenderedGeometries = GeometryCount;
|
|
|
|
}
|
|
|
|
public void RenderFinalPass(DeviceContext context)
|
|
{
|
|
context.Rasterizer.State = rsSolid;
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
|
|
if (HDR != null)
|
|
{
|
|
HDR.Render(DXMan, CurrentElapsedTime);
|
|
}
|
|
|
|
}
|
|
|
|
private void RenderShadowmap(DeviceContext context)
|
|
{
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
context.Rasterizer.State = rsSolid;
|
|
|
|
float maxdist = 3000.0f;// cascade.IntervalFar * 5.0f;
|
|
|
|
//find the casters within range
|
|
shadowcasters.Clear();
|
|
shadowcastercount = 0;
|
|
for (int b = 0; b < shadowbatches.Count; b++)
|
|
{
|
|
//shadowcasters.AddRange(shadowbatches[b].Geometries);
|
|
var sbgeoms = shadowbatches[b].Geometries;
|
|
for (int g = 0; g < sbgeoms.Count; g++)
|
|
{
|
|
var sbgeom = sbgeoms[g];
|
|
float idist = sbgeom.Inst.Distance - sbgeom.Inst.Radius;
|
|
if (idist <= maxdist)
|
|
{
|
|
shadowcasters.Add(sbgeom);
|
|
}
|
|
}
|
|
}
|
|
|
|
//render cascades
|
|
Shadowmap.BeginUpdate(context, Camera, GlobalLights.Params.LightDir, shadowcasters);
|
|
for (int i = 0; i < Shadowmap.CascadeCount; i++)
|
|
{
|
|
var cascade = Shadowmap.Cascades[i];
|
|
|
|
Shadowmap.BeginDepthRender(context, i);
|
|
|
|
float worldtocascade = cascade.WorldUnitsToCascadeUnits * 2.0f;
|
|
float minrad = cascade.WorldUnitsPerTexel * 3.0f;
|
|
|
|
shadowbatch.Clear();
|
|
for (int c = 0; c < shadowcasters.Count; c++)
|
|
{
|
|
//if the caster overlaps the cascade, draw it
|
|
var caster = shadowcasters[c];
|
|
if (caster.Inst.Radius <= minrad) continue; //don't render little things
|
|
Vector3 iscenepos = caster.Inst.Position - Shadowmap.SceneOrigin;
|
|
Vector3 ilightpos = cascade.Matrix.Multiply(iscenepos + caster.Inst.BSCenter);
|
|
float ilightradf = caster.Inst.Radius * worldtocascade;
|
|
float ilightminx = ilightpos.X - ilightradf;
|
|
float ilightmaxx = ilightpos.X + ilightradf;
|
|
float ilightminy = ilightpos.Y - ilightradf;
|
|
float ilightmaxy = ilightpos.Y + ilightradf;
|
|
if ((ilightmaxx > -1.0f) && (ilightminx < 1.0f) && (ilightmaxy > -1.0f) && (ilightminy < 1.0f))
|
|
{
|
|
shadowcastercount++;
|
|
caster.Inst.CamRel = iscenepos;
|
|
shadowbatch.Add(caster);
|
|
}
|
|
}
|
|
|
|
Shadow.SetShader(context);
|
|
Shadow.SetSceneVars(context, cascade.Matrix);
|
|
RenderGeometryBatch(context, shadowbatch, Shadow);
|
|
|
|
}
|
|
Shadowmap.EndUpdate(context);
|
|
Shadow.UnbindResources(context);
|
|
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
context.Rasterizer.State = rsSolid;
|
|
}
|
|
|
|
|
|
private void RenderGeometryBatches(DeviceContext context, List<ShaderBatch> batches, Shader shader)
|
|
{
|
|
shader.SetShader(context);
|
|
shader.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
|
foreach (var batch in batches)
|
|
{
|
|
RenderGeometryBatch(context, batch.Geometries, shader);
|
|
}
|
|
shader.UnbindResources(context);
|
|
}
|
|
private void RenderGeometryBatch(DeviceContext context, List<RenderableGeometryInst> batch, Shader shader)
|
|
{
|
|
GeometryCount += batch.Count;
|
|
|
|
RenderableModel model = null;
|
|
|
|
VertexType vtyp = 0;
|
|
bool vtypok = false;
|
|
for (int i = 0; i < batch.Count; i++)
|
|
{
|
|
var geom = batch[i];
|
|
var gmodel = geom.Geom.Owner;
|
|
shader.SetEntityVars(context, ref geom.Inst);
|
|
|
|
if (gmodel != model)
|
|
{
|
|
model = gmodel;
|
|
shader.SetModelVars(context, model);
|
|
}
|
|
if (geom.Geom.VertexType != vtyp)
|
|
{
|
|
vtyp = geom.Geom.VertexType;
|
|
if (!shader.SetInputLayout(context, vtyp))
|
|
{
|
|
//vertex type not supported...
|
|
vtypok = false;
|
|
}
|
|
else
|
|
{
|
|
vtypok = true;
|
|
}
|
|
}
|
|
if (vtypok)
|
|
{
|
|
|
|
shader.SetGeomVars(context, geom.Geom);
|
|
geom.Geom.Render(context);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void RenderBoundGeometryBatch(DeviceContext context, List<RenderableBoundGeometryInst> batch)
|
|
{
|
|
Basic.RenderMode = WorldRenderMode.VertexColour;
|
|
Basic.SetShader(context);
|
|
Basic.SetSceneVars(context, Camera, Shadowmap, GlobalLights);
|
|
Basic.SetInputLayout(context, VertexType.Default);
|
|
|
|
GeometryCount += batch.Count;
|
|
|
|
foreach (var geom in batch)
|
|
{
|
|
Basic.RenderBoundGeom(context, geom);
|
|
}
|
|
|
|
Basic.UnbindResources(context);
|
|
}
|
|
|
|
private void RenderInstancedBatch(DeviceContext context, RenderableInstanceBatchInst batch)
|
|
{
|
|
Basic.SetInstanceVars(context, batch.Batch);
|
|
|
|
if (batch.Renderable.HDModels.Length > 1)
|
|
{ }
|
|
|
|
foreach (var model in batch.Renderable.HDModels)
|
|
{
|
|
if (model.Geometries.Length > 1)
|
|
{ }
|
|
|
|
Basic.SetModelVars(context, model);
|
|
foreach (var geom in model.Geometries)
|
|
{
|
|
if (Basic.SetInputLayout(context, geom.VertexType))
|
|
{
|
|
Basic.SetGeomVars(context, geom);
|
|
geom.RenderInstanced(context, batch.Batch.InstanceCount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void Enqueue(ref RenderableGeometryInst geom)
|
|
{
|
|
var shader = geom.Geom.DrawableGeom.Shader;
|
|
|
|
var b = (shader!=null) ? shader.Unknown_11h : 0; //rage render bucket?
|
|
|
|
var bucket = EnsureRenderBucket(b);
|
|
|
|
ShaderBatch batch = null;
|
|
ShaderKey key = new ShaderKey();
|
|
key.ShaderName = (shader!=null) ? shader.Name : new MetaHash(0);
|
|
key.ShaderFile = (shader!=null) ? shader.FileName : new MetaHash(0);
|
|
|
|
if (!bucket.Batches.TryGetValue(key, out batch))
|
|
{
|
|
batch = new ShaderBatch(key);
|
|
bucket.Batches.Add(key, batch);
|
|
}
|
|
|
|
batch.Geometries.Add(geom);
|
|
}
|
|
public void Enqueue(ref RenderableBoundGeometryInst geom)
|
|
{
|
|
RenderBoundGeoms.Add(geom);
|
|
}
|
|
public void Enqueue(ref RenderableInstanceBatchInst batch)
|
|
{
|
|
RenderInstBatches.Add(batch);
|
|
}
|
|
public void Enqueue(RenderableDistantLODLights lights)
|
|
{
|
|
RenderDistLODLights.Add(lights);
|
|
}
|
|
public void Enqueue(RenderablePathBatch paths)
|
|
{
|
|
RenderPathBatches.Add(paths);
|
|
}
|
|
public void Enqueue(RenderableWaterQuad waterquad)
|
|
{
|
|
RenderWaterQuads.Add(waterquad);
|
|
}
|
|
|
|
|
|
public ShaderRenderBucket EnsureRenderBucket(int index)
|
|
{
|
|
ShaderRenderBucket bucket = null;
|
|
while (index >= RenderBuckets.Count)
|
|
{
|
|
RenderBuckets.Add(new ShaderRenderBucket(RenderBuckets.Count));
|
|
}
|
|
if (index < RenderBuckets.Count)
|
|
{
|
|
bucket = RenderBuckets[index];
|
|
}
|
|
return bucket;
|
|
}
|
|
|
|
|
|
private void SetShaderRenderModeParams()
|
|
{
|
|
Basic.RenderMode = RenderMode;
|
|
Basic.RenderVertexColourIndex = RenderVertexColourIndex;
|
|
Basic.RenderTextureCoordIndex = RenderTextureCoordIndex;
|
|
Basic.RenderTextureSamplerCoord = RenderTextureSamplerCoord;
|
|
Basic.RenderTextureSampler = RenderTextureSampler;
|
|
Basic.AnisotropicFilter = AnisotropicFiltering;
|
|
Clouds.AnisotropicFilter = AnisotropicFiltering;
|
|
Water.RenderMode = RenderMode;
|
|
Water.RenderVertexColourIndex = RenderVertexColourIndex;
|
|
Water.RenderTextureCoordIndex = RenderTextureCoordIndex;
|
|
Water.RenderTextureSamplerCoord = RenderTextureSamplerCoord;
|
|
Water.RenderTextureSampler = RenderTextureSampler;
|
|
Water.AnisotropicFilter = AnisotropicFiltering;
|
|
Terrain.RenderMode = RenderMode;
|
|
Terrain.RenderVertexColourIndex = RenderVertexColourIndex;
|
|
Terrain.RenderTextureCoordIndex = RenderTextureCoordIndex;
|
|
Terrain.RenderTextureSamplerCoord = RenderTextureSamplerCoord;
|
|
Terrain.RenderTextureSampler = RenderTextureSampler;
|
|
Terrain.AnisotropicFilter = AnisotropicFiltering;
|
|
}
|
|
|
|
|
|
|
|
public void ClearDepth(DeviceContext context, bool firstpass = true)
|
|
{
|
|
if ((HDR != null) && firstpass)
|
|
{
|
|
HDR.ClearDepth(context);
|
|
}
|
|
else
|
|
{
|
|
DXMan.ClearDepth(context);
|
|
}
|
|
}
|
|
public void SetRasterizerMode(DeviceContext context, RasterizerMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
default:
|
|
case RasterizerMode.Solid:
|
|
context.Rasterizer.State = rsSolid;
|
|
break;
|
|
case RasterizerMode.Wireframe:
|
|
context.Rasterizer.State = rsWireframe;
|
|
break;
|
|
case RasterizerMode.SolidDblSided:
|
|
context.Rasterizer.State = rsSolidDblSided;
|
|
break;
|
|
case RasterizerMode.WireframeDblSided:
|
|
context.Rasterizer.State = rsWireframeDblSided;
|
|
break;
|
|
}
|
|
}
|
|
public void SetDepthStencilMode(DeviceContext context, DepthStencilMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
default:
|
|
case DepthStencilMode.Enabled:
|
|
context.OutputMerger.DepthStencilState = dsEnabled;
|
|
break;
|
|
case DepthStencilMode.DisableWrite:
|
|
context.OutputMerger.DepthStencilState = dsDisableWrite;
|
|
break;
|
|
case DepthStencilMode.DisableComp:
|
|
context.OutputMerger.DepthStencilState = dsDisableComp;
|
|
break;
|
|
case DepthStencilMode.DisableAll:
|
|
context.OutputMerger.DepthStencilState = dsDisableAll;
|
|
break;
|
|
}
|
|
}
|
|
public void SetDefaultBlendState(DeviceContext context)
|
|
{
|
|
context.OutputMerger.BlendState = bsDefault;
|
|
}
|
|
public void SetAlphaBlendState(DeviceContext context)
|
|
{
|
|
context.OutputMerger.BlendState = bsAlpha;
|
|
}
|
|
|
|
public void OnWindowResize(int w, int h)
|
|
{
|
|
Width = w;
|
|
Height = h;
|
|
if (HDR != null)
|
|
{
|
|
HDR.OnWindowResize(DXMan);
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum RasterizerMode
|
|
{
|
|
Solid = 1,
|
|
Wireframe = 2,
|
|
SolidDblSided = 3,
|
|
WireframeDblSided = 4,
|
|
}
|
|
public enum DepthStencilMode
|
|
{
|
|
Enabled = 1,
|
|
DisableWrite = 2,
|
|
DisableComp = 3,
|
|
DisableAll = 4,
|
|
}
|
|
|
|
|
|
public struct ShaderKey
|
|
{
|
|
public MetaHash ShaderName;
|
|
public MetaHash ShaderFile;
|
|
|
|
public override string ToString()
|
|
{
|
|
return ShaderFile.ToString() + ": " + ShaderName.ToString();
|
|
}
|
|
}
|
|
public class ShaderRenderBucket
|
|
{
|
|
public int Index;
|
|
public Dictionary<ShaderKey, ShaderBatch> Batches = new Dictionary<ShaderKey, ShaderBatch>();
|
|
|
|
public List<ShaderBatch> BasicBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> DecalBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> WaterBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> Water2Batches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> AlphaBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> GlassBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> CutoutBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> TerrainBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> TreesLodBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> CableBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> ClothBatches = new List<ShaderBatch>();
|
|
public List<ShaderBatch> VehicleBatches = new List<ShaderBatch>();
|
|
|
|
|
|
public ShaderRenderBucket(int index)
|
|
{
|
|
Index = index;
|
|
}
|
|
public void Clear()
|
|
{
|
|
foreach (var batch in Batches.Values)
|
|
{
|
|
batch.Clear();
|
|
}
|
|
}
|
|
|
|
public void GroupBatches()
|
|
{
|
|
BasicBatches.Clear();
|
|
DecalBatches.Clear();
|
|
WaterBatches.Clear();
|
|
Water2Batches.Clear();
|
|
AlphaBatches.Clear();
|
|
GlassBatches.Clear();
|
|
CutoutBatches.Clear();
|
|
TerrainBatches.Clear();
|
|
TreesLodBatches.Clear();
|
|
CableBatches.Clear();
|
|
ClothBatches.Clear();
|
|
VehicleBatches.Clear();
|
|
|
|
foreach (var kvp in Batches)
|
|
{
|
|
if (kvp.Value.Geometries.Count == 0) continue;
|
|
|
|
List<ShaderBatch> b = null;
|
|
switch (kvp.Key.ShaderFile.Hash)
|
|
{
|
|
#region default batches
|
|
case 0://default
|
|
case 413996436://{default.sps}
|
|
case 1581835696://{default_um.sps}
|
|
case 200682448://{default_tnt.sps}
|
|
case 1891750326://{default_spec.sps}
|
|
case 3080824371://{default_detail.sps}
|
|
case 3939256279://{default_terrain_wet.sps}
|
|
case 2948410525://{normal.sps}
|
|
case 3326705511://{normal_um.sps}
|
|
case 1891558834://{normal_pxm.sps}
|
|
case 3348158737://{normal_pxm_tnt.sps}
|
|
case 346521853://{normal_spec.sps}
|
|
case 1092618307://{normal_spec_dpm.sps}
|
|
case 505619005://{normal_spec_detail.sps}
|
|
case 10880875://{normal_spec_detail_tnt.sps}
|
|
case 3376941572://{normal_spec_detail_dpm_tnt.sps}
|
|
case 1315370658://{normal_spec_detail_dpm.sps}
|
|
case 4246136089://{normal_spec_detail_dpm_vertdecal_tnt.sps}
|
|
case 810202407://{normal_spec_tnt.sps}
|
|
case 2121232575://{normal_spec_tnt_pxm.sps}
|
|
case 1489449972://{normal_spec_pxm.sps}
|
|
case 1117835835://{normal_spec_pxm_tnt.sps}
|
|
case 3085209681://{normal_spec_um.sps}
|
|
case 1332909972://{normal_spec_emissive.sps}
|
|
case 3424303599://{normal_spec_reflect.sps}
|
|
case 2072061694://{normal_spec_reflect_emissivenight.sps}
|
|
case 3564197994://{normal_spec_cubemap_reflect.sps}
|
|
case 1808536605://{normal_detail.sps}
|
|
case 557170358://{normal_detail_dpm.sps}
|
|
case 3420295952://{normal_diffspec.sps}
|
|
case 559317884://{normal_diffspec_detail_dpm_tnt.sps}
|
|
case 2735427639://{normal_diffspec_detail_dpm.sps}
|
|
case 1845339284://{normal_diffspec_detail.sps}
|
|
case 601788410://{normal_diffspec_detail_tnt.sps}
|
|
case 3756536307://{normal_diffspec_tnt.sps}
|
|
case 2988770526://{normal_tnt.sps}
|
|
case 1728634142://{normal_tnt_pxm.sps}
|
|
case 3362038760://{normal_terrain_wet.sps}
|
|
case 1685791092://{normal_reflect.sps}
|
|
case 2626821864://{normal_cubemap_reflect.sps}
|
|
case 2635608835://{emissive.sps}
|
|
case 443538781://{emissive_clip.sps}
|
|
case 2049580179://{emissive_speclum.sps}
|
|
case 1193295596://{emissive_tnt.sps}
|
|
case 1434302180://{emissivenight.sps}
|
|
case 1897917258://{emissivenight_geomnightonly.sps}
|
|
case 140448747://{emissivestrong.sps}
|
|
case 2247429097://{spec.sps}
|
|
case 1396339721://{spec_const.sps}
|
|
case 689627308://{spec_tnt.sps}
|
|
case 873285799://{spec_reflect.sps}
|
|
case 3634763545://{reflect.sps}
|
|
case 1658580369://{mirror_default.sps}
|
|
case 129155404://{mirror_crack.sps}
|
|
case 2067933913://{parallax.sps}
|
|
case 1084945164://{parallax_specmap.sps}
|
|
case 3052800384://{blend_2lyr.sps}
|
|
case 154074948://{spec_twiddle_tnt.sps}
|
|
case 14185869://{weapon_normal_spec_tnt.sps}
|
|
b = BasicBatches;
|
|
break;
|
|
#endregion
|
|
#region cloth batches
|
|
case 1106229739://{cloth_default.sps}
|
|
case 1800418130://{cloth_normal_spec.sps}
|
|
case 476099326://{cloth_spec_cutout.sps}
|
|
case 170694389://{cloth_normal_spec_cutout.sps}
|
|
case 38543133://{cloth_normal_spec_tnt.sps}
|
|
b = ClothBatches;
|
|
break;
|
|
#endregion
|
|
#region cutout batches
|
|
case 1530399584://{cutout.sps}
|
|
case 3190732435://{cutout_um.sps}
|
|
case 3959636627://{cutout_tnt.sps}
|
|
case 2219447268://{cutout_fence.sps}
|
|
case 3091995132://{cutout_fence_normal.sps}
|
|
case 3187789425://{cutout_hard.sps}
|
|
case 3339370144://{cutout_spec_tnt.sps}
|
|
case 1264076685://{normal_cutout.sps}
|
|
case 46387092://{normal_cutout_tnt.sps}
|
|
case 748520668://{normal_cutout_um.sps}
|
|
case 807996366://{normal_spec_cutout.sps}
|
|
case 3300978494://{normal_spec_cutout_tnt.sps}
|
|
case 582493193://{trees_lod.sps} //not billboarded..
|
|
case 2322653400://{trees.sps}
|
|
case 3334613197://{trees_tnt.sps}
|
|
case 3192134330://{trees_normal.sps}
|
|
case 1224713457://{trees_normal_spec.sps}
|
|
case 1229591973://{trees_normal_spec_tnt.sps}
|
|
case 4265705004://{trees_normal_diffspec.sps}
|
|
case 2245870123://{trees_normal_diffspec_tnt.sps}
|
|
b = CutoutBatches;
|
|
break;
|
|
#endregion
|
|
#region alpha batches
|
|
case 2021887493://{normal_spec_alpha.sps}
|
|
case 1086592620://{normal_spec_reflect_alpha.sps}
|
|
case 1436689415://{normal_spec_reflect_emissivenight_alpha.sps}
|
|
case 4237650253://{normal_spec_screendooralpha.sps}
|
|
case 1564459451://{normal_alpha.sps}
|
|
case 763839200://{normal_reflect_alpha.sps}
|
|
case 179247185://{emissive_alpha.sps}
|
|
case 1314864030://{emissive_alpha_tnt.sps}
|
|
case 1478174766://{emissive_additive_alpha.sps}
|
|
case 3733846327://{emissivenight_alpha.sps}
|
|
case 3174327089://{emissivestrong_alpha.sps}
|
|
case 257450439://{spec_alpha.sps}
|
|
case 2116642565://{spec_reflect_alpha.sps}
|
|
case 298255408://{alpha.sps}
|
|
case 181295180://{reflect_alpha.sps}
|
|
case 1896243360://{normal_screendooralpha.sps}
|
|
case 3724703640://{spec_screendooralpha.sps}
|
|
case 2161953435://{cloth_spec_alpha.sps} //alpha cloth is ok in alpha batch for now...
|
|
case 3203310712://{cloth_normal_spec_alpha.sps}
|
|
b = AlphaBatches;
|
|
break;
|
|
#endregion
|
|
#region water batches
|
|
case 1529202445://{water_river.sps}
|
|
case 4064804434://{water_riverlod.sps}
|
|
case 2871265627://{water_riverocean.sps}
|
|
case 1507348828://{water_rivershallow.sps}
|
|
case 3945561843://{water_fountain.sps}
|
|
case 4234404348://{water_shallow.sps}
|
|
b = WaterBatches;
|
|
break;
|
|
case 1077877097://{water_poolenv.sps}
|
|
case 3053856997://{water_riverfoam.sps}
|
|
case 3066724854://{water_terrainfoam.sps}
|
|
case 1471966282://{water_decal.sps} (should this be in decal batch?)
|
|
b = Water2Batches;
|
|
break;
|
|
#endregion
|
|
#region glass batches
|
|
case 3928756789://{glass.sps}
|
|
case 4018753208://{glass_pv.sps}
|
|
case 2800545026://{glass_pv_env.sps}
|
|
case 1263059426://{glass_env.sps}
|
|
case 3398951093://{glass_spec.sps}
|
|
case 1520288031://{glass_reflect.sps}
|
|
case 3924045432://{glass_emissive.sps}
|
|
case 837003310://{glass_emissivenight.sps}
|
|
case 485710087://{glass_emissivenight_alpha.sps}
|
|
case 1359281054://{glass_breakable.sps}
|
|
case 4237090538://{glass_breakable_screendooralpha.sps}
|
|
case 430314084://{glass_displacement.sps}
|
|
case 2866652360://{glass_normal_spec_reflect.sps}
|
|
case 2055615352://{glass_emissive_alpha.sps}
|
|
b = GlassBatches;
|
|
break;
|
|
#endregion
|
|
#region decal batches
|
|
case 3140040342://{decal.sps}
|
|
case 1093522222://{decal_tnt.sps}
|
|
case 3948167519://{decal_glue.sps}
|
|
case 3880384844://{decal_spec_only.sps}
|
|
case 341123999://{decal_normal_only.sps}
|
|
case 2918136469://{decal_emissive_only.sps}
|
|
case 2698880237://{decal_emissivenight_only.sps}
|
|
case 600733812://{decal_amb_only.sps}
|
|
case 1145906525://{normal_decal.sps}
|
|
case 1342302630://{normal_decal_pxm.sps}
|
|
case 2269053854://{normal_decal_pxm_tnt.sps}
|
|
case 108580378://{normal_decal_tnt.sps}
|
|
case 2189252961://{normal_spec_decal.sps}
|
|
case 992110385://{normal_spec_decal_detail.sps}
|
|
case 941334042://{normal_spec_decal_nopuddle.sps}
|
|
case 2739041469://{normal_spec_decal_tnt.sps}
|
|
case 3606424483://{normal_spec_decal_pxm.sps}
|
|
case 2842248626://{spec_decal.sps}
|
|
case 3717415672://{spec_reflect_decal.sps}
|
|
case 2457676400://{reflect_decal.sps}
|
|
case 2655725442://{decal_dirt.sps}
|
|
case 2706821972://{mirror_decal.sps}
|
|
case 1851110504://{distance_map.sps}
|
|
b = DecalBatches;
|
|
break;
|
|
#endregion
|
|
#region trees batches
|
|
case 4113118754://{trees_lod2.sps}
|
|
b = TreesLodBatches;
|
|
break;
|
|
#endregion
|
|
#region terrain batches
|
|
case 2131453483://{terrain_cb_w_4lyr.sps}
|
|
case 404312839://{terrain_cb_w_4lyr_lod.sps}
|
|
case 1196319128://{terrain_cb_w_4lyr_spec.sps}
|
|
case 1539365454://{terrain_cb_w_4lyr_spec_pxm.sps}
|
|
case 2415127391://{terrain_cb_w_4lyr_pxm_spm.sps}
|
|
case 4024079163://{terrain_cb_w_4lyr_pxm.sps}
|
|
case 1437909171://{terrain_cb_w_4lyr_cm_pxm.sps}
|
|
case 1185891401://{terrain_cb_w_4lyr_cm_tnt.sps} //golf
|
|
case 3254053796://{terrain_cb_w_4lyr_cm_pxm_tnt.sps} //golf
|
|
case 1567099655://{terrain_cb_w_4lyr_cm.sps}
|
|
case 3908107877://{terrain_cb_w_4lyr_2tex.sps}
|
|
case 341330913://{terrain_cb_w_4lyr_2tex_blend.sps}
|
|
case 673057355://{terrain_cb_w_4lyr_2tex_blend_lod.sps}
|
|
case 1046220944://{terrain_cb_w_4lyr_2tex_blend_pxm.sps}
|
|
case 2344506399://{terrain_cb_w_4lyr_2tex_blend_pxm_spm.sps}
|
|
case 3444846649://{terrain_cb_w_4lyr_2tex_pxm.sps}
|
|
case 3369161623://{terrain_cb_4lyr.sps}
|
|
case 1003015712://{terrain_cb_w_4lyr_spec_int_pxm.sps}
|
|
case 1927591706://{terrain_cb_w_4lyr_spec_int.sps}
|
|
case 3550605441://{terrain_cb_4lyr_lod.sps} //TODO! (used in custom stuff...)
|
|
b = TerrainBatches;
|
|
break;
|
|
#endregion
|
|
#region cable batches
|
|
case 3854885487://{cable.sps}
|
|
b = CableBatches;
|
|
break;
|
|
#endregion
|
|
#region vehicle batches
|
|
case 753908000://{vehicle_basic.sps}
|
|
case 1107511867://{vehicle_generic.sps}
|
|
case 3274951810://{vehicle_paint1.sps}
|
|
case 1009159769://{vehicle_paint2.sps}
|
|
case 2045642561://{vehicle_paint3.sps}
|
|
case 1534086746://{vehicle_paint3_enveff.sps}
|
|
case 60950417://{vehicle_paint4_enveff.sps}
|
|
case 249472155://{vehicle_paint5_enveff.sps}
|
|
case 354168229://{vehicle_paint6_enveff.sps}
|
|
case 617726044://{vehicle_mesh.sps}
|
|
case 2162256878://{vehicle_tire.sps}
|
|
case 3106021319://{vehicle_interior.sps}
|
|
case 2837548125://{vehicle_interior2.sps}
|
|
case 2094873540://{vehicle_shuts.sps}
|
|
case 2405328911://{vehicle_licenseplate.sps}
|
|
case 2226589567://{vehicle_lights.sps}
|
|
case 364912658://{vehicle_lightsemissive.sps}
|
|
case 3030872505://{vehicle_emissive_opaque.sps}
|
|
case 146667297://{vehicle_badges.sps}
|
|
case 4162395624://{vehicle_dash_emissive.sps}
|
|
case 254152173://{vehicle_dash_emissive_opaque.sps}
|
|
case 3355845283://{vehicle_detail2.sps}
|
|
case 4097152976://{vehicle_track.sps}
|
|
case 3631243954://{vehicle_blurredrotor.sps}
|
|
case 457610770://{vehicle_nosplash.sps}
|
|
case 3621563260://{vehicle_nowater.sps}
|
|
case 430888562://{vehicle_paint8.sps}
|
|
case 4118002252://{vehicle_paint9.sps}
|
|
case 158342452://{vehicle_detail.sps}
|
|
b = BasicBatches;
|
|
break;
|
|
case 1041778472://{vehicle_decal.sps}
|
|
case 1462664157://{vehicle_decal2.sps}
|
|
b = DecalBatches;
|
|
break;
|
|
case 3096299666://{vehicle_vehglass.sps}
|
|
case 588619930://{vehicle_vehglass_inner.sps}
|
|
b = GlassBatches;
|
|
break;
|
|
case 3986926894://{vehicle_cloth.sps}
|
|
b = ClothBatches;
|
|
break;
|
|
#endregion
|
|
#region TODO/unused batches
|
|
case 3333227093://{grass_fur.sps}
|
|
case 4256676773://{grass_fur_mask.sps}
|
|
break;//todo: grass_fur
|
|
|
|
case 83630553://{cpv_only.sps}
|
|
case 1238547107://{decal_shadow_only.sps}
|
|
case 1695474112://{trees_shadow_proxy.sps}
|
|
break; //should add this to a shadowproxies group.. but currently don't draw.
|
|
#endregion
|
|
#region TODO/clouds batches
|
|
case 4103916155://{clouds_animsoft.sps}
|
|
case 1097000161://{clouds_altitude.sps}
|
|
case 1481470665://{clouds_soft.sps}
|
|
case 2184108982://{clouds_fast.sps}
|
|
case 4192928948://{clouds_anim.sps}
|
|
b = BasicBatches; //todo: correct batched cloud rendering...
|
|
break;
|
|
#endregion
|
|
|
|
default:
|
|
b = BasicBatches;
|
|
break;
|
|
}
|
|
|
|
if (b != null)
|
|
{
|
|
b.Add(kvp.Value);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
public class ShaderBatch
|
|
{
|
|
public ShaderKey Key;
|
|
public List<RenderableGeometryInst> Geometries = new List<RenderableGeometryInst>();
|
|
|
|
public ShaderBatch(ShaderKey key)
|
|
{
|
|
Key = key;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
Geometries.Clear();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public class ShaderGlobalLights
|
|
{
|
|
public Weather Weather;
|
|
public ShaderGlobalLightParams Params;
|
|
public Vector3 CurrentSunDir;
|
|
public Vector3 CurrentMoonDir;
|
|
public Vector3 MoonAxis;
|
|
public bool HdrEnabled;
|
|
public float HdrIntensity;
|
|
public bool SpecularEnabled;
|
|
}
|
|
public struct ShaderGlobalLightParams
|
|
{
|
|
public Vector3 LightDir;
|
|
public float LightHdr; //global intensity
|
|
public Color4 LightDirColour;
|
|
public Color4 LightDirAmbColour;
|
|
public Color4 LightNaturalAmbUp;
|
|
public Color4 LightNaturalAmbDown;
|
|
public Color4 LightArtificialAmbUp;
|
|
public Color4 LightArtificialAmbDown;
|
|
}
|
|
|
|
|
|
}
|