Move Voxel code to Mods.Cnc.

This commit is contained in:
Paul Chote
2017-06-09 15:58:00 +00:00
committed by reaperrr
parent dc4c3fd546
commit 34810756c2
19 changed files with 185 additions and 157 deletions

View File

@@ -22,7 +22,21 @@ namespace OpenRA.Graphics
float[] TransformationMatrix(uint section, uint frame);
float[] Size { get; }
float[] Bounds(uint frame);
VoxelRenderData RenderData(uint section);
ModelRenderData RenderData(uint section);
}
public struct ModelRenderData
{
public readonly int Start;
public readonly int Count;
public readonly Sheet Sheet;
public ModelRenderData(int start, int count, Sheet sheet)
{
Start = start;
Count = count;
Sheet = sheet;
}
}
public interface IModelCache : IDisposable

View File

@@ -208,12 +208,12 @@ namespace OpenRA.Graphics
// Transform light vector from shadow -> world -> limb coords
var lightDirection = ExtractRotationVector(Util.MatrixMultiply(it, lightTransform));
Render(rd, Util.MatrixMultiply(transform, t), lightDirection,
Render(rd, wr.World.ModelCache, Util.MatrixMultiply(transform, t), lightDirection,
lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex);
// Disable shadow normals by forcing zero diffuse and identity ambient light
if (v.ShowShadow)
Render(rd, Util.MatrixMultiply(shadow, t), lightDirection,
Render(rd, wr.World.ModelCache, Util.MatrixMultiply(shadow, t), lightDirection,
ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex);
}
}
@@ -258,7 +258,8 @@ namespace OpenRA.Graphics
}
void Render(
VoxelRenderData renderData,
ModelRenderData renderData,
IModelCache cache,
float[] t, float[] lightDirection,
float[] ambientLight, float[] diffuseLight,
float colorPaletteTextureMidIndex, float normalsPaletteTextureMidIndex)
@@ -270,7 +271,7 @@ namespace OpenRA.Graphics
shader.SetVec("AmbientLight", ambientLight, 3);
shader.SetVec("DiffuseLight", diffuseLight, 3);
shader.Render(() => renderer.DrawBatch(Game.ModData.VoxelLoader.VertexBuffer, renderData.Start, renderData.Count, PrimitiveType.TriangleList));
shader.Render(() => renderer.DrawBatch(cache.VertexBuffer, renderData.Start, renderData.Count, PrimitiveType.TriangleList));
}
public void BeginFrame()

View File

@@ -1,84 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileSystem;
namespace OpenRA.Graphics
{
public static class VoxelProvider
{
static Dictionary<string, Dictionary<string, Voxel>> units;
public static void Initialize(VoxelLoader loader, IReadOnlyFileSystem fileSystem, List<MiniYamlNode> sequences)
{
units = new Dictionary<string, Dictionary<string, Voxel>>();
foreach (var s in sequences)
LoadVoxelsForUnit(loader, s.Key, s.Value);
loader.RefreshBuffer();
}
static Voxel LoadVoxel(VoxelLoader voxelLoader, string unit, MiniYaml info)
{
var vxl = unit;
var hva = unit;
if (info.Value != null)
{
var fields = info.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (fields.Length >= 1)
vxl = hva = fields[0].Trim();
if (fields.Length >= 2)
hva = fields[1].Trim();
}
return voxelLoader.Load(vxl, hva);
}
static void LoadVoxelsForUnit(VoxelLoader loader, string unit, MiniYaml sequences)
{
Game.ModData.LoadScreen.Display();
try
{
var seq = sequences.ToDictionary(my => LoadVoxel(loader, unit, my));
units.Add(unit, seq);
}
catch (FileNotFoundException) { } // Do nothing; we can crash later if we actually wanted art
}
public static Voxel GetVoxel(string unitName, string voxelName)
{
try { return units[unitName][voxelName]; }
catch (KeyNotFoundException)
{
if (units.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have a voxel `{1}`".F(unitName, voxelName));
else
throw new InvalidOperationException(
"Unit `{0}` does not have any voxels defined.".F(unitName));
}
}
public static bool HasVoxel(string unit, string seq)
{
if (!units.ContainsKey(unit))
throw new InvalidOperationException(
"Unit `{0}` does not have any voxels defined.".F(unit));
return units[unit].ContainsKey(seq);
}
}
}

View File

@@ -32,7 +32,6 @@ namespace OpenRA
public readonly ISpriteSequenceLoader SpriteSequenceLoader;
public readonly IModelSequenceLoader ModelSequenceLoader;
public ILoadScreen LoadScreen { get; private set; }
public VoxelLoader VoxelLoader { get; private set; }
public CursorProvider CursorProvider { get; private set; }
public FS ModFiles;
public IReadOnlyFileSystem DefaultFileSystem { get { return ModFiles; } }
@@ -132,10 +131,6 @@ namespace OpenRA
Game.Sound.Initialize(SoundLoaders, fileSystem);
if (VoxelLoader != null)
VoxelLoader.Dispose();
VoxelLoader = new VoxelLoader(fileSystem);
CursorProvider = new CursorProvider(this);
}
@@ -199,9 +194,6 @@ namespace OpenRA
foreach (var entry in map.Rules.Music)
entry.Value.Load(map);
VoxelProvider.Initialize(VoxelLoader, map, MiniYaml.Load(map, Manifest.VoxelSequences, map.VoxelSequenceDefinitions));
VoxelLoader.Finish();
return map;
}
@@ -210,8 +202,6 @@ namespace OpenRA
if (LoadScreen != null)
LoadScreen.Dispose();
MapCache.Dispose();
if (VoxelLoader != null)
VoxelLoader.Dispose();
if (ObjectCreator != null)
ObjectCreator.Dispose();

View File

@@ -195,10 +195,7 @@
<Compile Include="Traits\DebugPauseState.cs" />
<Compile Include="Network\UPnP.cs" />
<Compile Include="Graphics\Renderable.cs" />
<Compile Include="Graphics\Voxel.cs" />
<Compile Include="Graphics\ModelRenderer.cs" />
<Compile Include="Graphics\VoxelLoader.cs" />
<Compile Include="Graphics\VoxelProvider.cs" />
<Compile Include="Graphics\ModelAnimation.cs" />
<Compile Include="Traits\Player\FrozenActorLayer.cs" />
<Compile Include="Graphics\Theater.cs" />
@@ -268,9 +265,7 @@
<Compile Include="FieldSaver.cs" />
<Compile Include="Manifest.cs" />
<Compile Include="Graphics\Vertex.cs" />
<Compile Include="FileFormats\HvaReader.cs" />
<Compile Include="FileFormats\PngLoader.cs" />
<Compile Include="FileFormats\VxlReader.cs" />
<Compile Include="Primitives\ActionQueue.cs" />
<Compile Include="Primitives\Bits.cs" />
<Compile Include="Primitives\Cache.cs" />

View File

@@ -14,7 +14,7 @@ using System;
using System.IO;
using OpenRA.Graphics;
namespace OpenRA.FileFormats
namespace OpenRA.Mods.Cnc.FileFormats
{
public class HvaReader
{

View File

@@ -13,7 +13,7 @@
using System.Collections.Generic;
using System.IO;
namespace OpenRA.FileFormats
namespace OpenRA.Mods.Cnc.FileFormats
{
public enum NormalType { TiberianSun = 2, RedAlert2 = 4 }
public class VxlElement

View File

@@ -11,16 +11,17 @@
using System;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.FileFormats;
namespace OpenRA.Graphics
namespace OpenRA.Mods.Cnc.Graphics
{
struct Limb
{
public float Scale;
public float[] Bounds;
public byte[] Size;
public VoxelRenderData RenderData;
public ModelRenderData RenderData;
}
public class Voxel : IModel
@@ -79,7 +80,7 @@ namespace OpenRA.Graphics
return t;
}
public VoxelRenderData RenderData(uint limb)
public ModelRenderData RenderData(uint limb)
{
return limbData[limb].RenderData;
}

View File

@@ -13,26 +13,13 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.FileFormats;
using OpenRA.Primitives;
namespace OpenRA.Graphics
namespace OpenRA.Mods.Cnc.Graphics
{
public struct VoxelRenderData
{
public readonly int Start;
public readonly int Count;
public readonly Sheet Sheet;
public VoxelRenderData(int start, int count, Sheet sheet)
{
Start = start;
Count = count;
Sheet = sheet;
}
}
public sealed class VoxelLoader : IDisposable
{
static readonly float[] ChannelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
@@ -182,7 +169,7 @@ namespace OpenRA.Graphics
(u, v) => new float3(u, v, z));
}
public VoxelRenderData GenerateRenderData(VxlLimb l)
public ModelRenderData GenerateRenderData(VxlLimb l)
{
Vertex[] v;
try
@@ -203,14 +190,14 @@ namespace OpenRA.Graphics
var start = totalVertexCount;
var count = v.Length;
totalVertexCount += count;
return new VoxelRenderData(start, count, sheetBuilder.Current);
return new ModelRenderData(start, count, sheetBuilder.Current);
}
public void RefreshBuffer()
{
if (vertexBuffer != null)
vertexBuffer.Dispose();
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(totalVertexCount);
vertexBuffer = Game.Renderer.CreateVertexBuffer(totalVertexCount);
vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount);
cachedVertexCount = totalVertexCount;
}

View File

@@ -0,0 +1,119 @@
#region Copyright & License Information
/*
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using OpenRA.FileSystem;
using OpenRA.Graphics;
namespace OpenRA.Mods.Cnc.Graphics
{
public class VoxelModelSequenceLoader : IModelSequenceLoader
{
public Action<string> OnMissingModelError { get; set; }
public VoxelModelSequenceLoader(ModData modData) { }
public IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary<string, MiniYamlNode> modelSequences)
{
var cache = new VoxelModelCache(fileSystem);
foreach (var kv in modelSequences)
{
modData.LoadScreen.Display();
try
{
cache.CacheModel(kv.Key, kv.Value.Value);
}
catch (FileNotFoundException ex)
{
Console.WriteLine(ex);
// Eat the FileNotFound exceptions from missing sprites
OnMissingModelError(ex.Message);
}
}
cache.LoadComplete();
return cache;
}
}
public class VoxelModelCache : IModelCache
{
readonly VoxelLoader loader;
readonly Dictionary<string, Dictionary<string, IModel>> models = new Dictionary<string, Dictionary<string, IModel>>();
public VoxelModelCache(IReadOnlyFileSystem fileSystem)
{
loader = new VoxelLoader(fileSystem);
}
public void CacheModel(string model, MiniYaml definition)
{
models.Add(model, definition.ToDictionary(my => LoadVoxel(model, my)));
}
public void LoadComplete()
{
loader.RefreshBuffer();
loader.Finish();
}
IModel LoadVoxel(string unit, MiniYaml info)
{
var vxl = unit;
var hva = unit;
if (info.Value != null)
{
var fields = info.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (fields.Length >= 1)
vxl = hva = fields[0].Trim();
if (fields.Length >= 2)
hva = fields[1].Trim();
}
return loader.Load(vxl, hva);
}
public IModel GetModelSequence(string model, string sequence)
{
try { return models[model][sequence]; }
catch (KeyNotFoundException)
{
if (models.ContainsKey(model))
throw new InvalidOperationException(
"Model `{0}` does not have a sequence `{1}`".F(model, sequence));
else
throw new InvalidOperationException(
"Model `{0}` does not have any sequences defined.".F(model));
}
}
public bool HasModelSequence(string model, string sequence)
{
if (!models.ContainsKey(model))
throw new InvalidOperationException(
"Model `{0}` does not have any sequences defined.".F(model));
return models[model].ContainsKey(sequence);
}
public IVertexBuffer<Vertex> VertexBuffer { get { return loader.VertexBuffer; } }
public void Dispose()
{
loader.Dispose();
}
}
}

View File

@@ -147,6 +147,12 @@
<Compile Include="FileFormats\XccGlobalDatabase.cs" />
<Compile Include="FileFormats\XccLocalDatabase.cs" />
<Compile Include="FileFormats\CRC32.cs" />
<Compile Include="Graphics\VoxelModelSequenceLoader.cs" />
<Compile Include="Graphics\VoxelLoader.cs" />
<Compile Include="Graphics\Voxel.cs" />
<Compile Include="FileFormats\HvaReader.cs" />
<Compile Include="FileFormats\VxlReader.cs" />
<Compile Include="Traits\World\VoxelNormalsPalette.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">

View File

@@ -37,8 +37,8 @@ namespace OpenRA.Mods.Cnc.Traits.Render
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var voxel = VoxelProvider.GetVoxel(image, IdleSequence);
yield return new ModelAnimation(voxel, () => WVec.Zero,
var model = init.World.ModelCache.GetModelSequence(image, IdleSequence);
yield return new ModelAnimation(model, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(orientation(), facings) },
() => false, () => 0, ShowShadow);
}
@@ -55,19 +55,19 @@ namespace OpenRA.Mods.Cnc.Traits.Render
var body = self.Trait<BodyOrientation>();
var rv = self.Trait<RenderVoxels>();
var idleVoxel = VoxelProvider.GetVoxel(rv.Image, info.IdleSequence);
rv.Add(new ModelAnimation(idleVoxel, () => WVec.Zero,
var idleModel = self.World.ModelCache.GetModelSequence(rv.Image, info.IdleSequence);
rv.Add(new ModelAnimation(idleModel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => Docked,
() => 0, info.ShowShadow));
// Selection size
var rvi = self.Info.TraitInfo<RenderVoxelsInfo>();
var s = (int)(rvi.Scale * idleVoxel.Size.Aggregate(Math.Max));
var s = (int)(rvi.Scale * idleModel.Size.Aggregate(Math.Max));
size = new int2(s, s);
var unloadVoxel = VoxelProvider.GetVoxel(rv.Image, info.UnloadSequence);
rv.Add(new ModelAnimation(unloadVoxel, () => WVec.Zero,
var unloadModel = self.World.ModelCache.GetModelSequence(rv.Image, info.UnloadSequence);
rv.Add(new ModelAnimation(unloadModel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => !Docked,
() => 0, info.ShowShadow));

View File

@@ -37,11 +37,11 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public IEnumerable<ModelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var frame = init.Contains<BodyAnimationFrameInit>() ? init.Get<BodyAnimationFrameInit, uint>() : 0;
yield return new ModelAnimation(voxel, () => WVec.Zero,
yield return new ModelAnimation(model, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(orientation(), facings) },
() => false, () => frame, ShowShadow);
}
@@ -65,15 +65,15 @@ namespace OpenRA.Mods.Cnc.Traits.Render
var body = self.Trait<BodyOrientation>();
var rv = self.Trait<RenderVoxels>();
var voxel = VoxelProvider.GetVoxel(rv.Image, info.Sequence);
frames = voxel.Frames;
rv.Add(new ModelAnimation(voxel, () => WVec.Zero,
var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence);
frames = model.Frames;
rv.Add(new ModelAnimation(model, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => false, () => frame, info.ShowShadow));
// Selection size
var rvi = self.Info.TraitInfo<RenderVoxelsInfo>();
var s = (int)(rvi.Scale * voxel.Size.Aggregate(Math.Max));
var s = (int)(rvi.Scale * model.Size.Aggregate(Math.Max));
size = new int2(s, s);
}

View File

@@ -9,11 +9,11 @@
*/
#endregion
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
namespace OpenRA.Mods.Cnc.Traits
{
public class VoxelNormalsPaletteInfo : ITraitInfo
{

View File

@@ -520,7 +520,6 @@
<Compile Include="Traits\World\PaletteFromFile.cs" />
<Compile Include="Traits\World\PaletteFromRGBA.cs" />
<Compile Include="Traits\World\ValidateOrder.cs" />
<Compile Include="Traits\World\VoxelNormalsPalette.cs" />
<Compile Include="Pathfinder\CellInfoLayerPool.cs" />
<Compile Include="Pathfinder\Constants.cs" />
<Compile Include="Pathfinder\PathGraph.cs" />

View File

@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == armament.Turret);
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, t.Turret);
Func<WRot> turretOrientation = () => body.QuantizeOrientation(WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw), facings);
@@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.Traits.Render
Func<WRot> quantizedBody = () => body.QuantizeOrientation(orientation(), facings);
Func<WVec> barrelOffset = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret())).Rotate(quantizedBody()));
yield return new ModelAnimation(voxel, barrelOffset, () => new[] { turretOrientation(), orientation() },
yield return new ModelAnimation(model, barrelOffset, () => new[] { turretOrientation(), orientation() },
() => false, () => 0, ShowShadow);
}
}
@@ -86,7 +86,7 @@ namespace OpenRA.Mods.Common.Traits.Render
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(VoxelProvider.GetVoxel(rv.Image, Info.Sequence),
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
BarrelOffset, BarrelRotation,
() => IsTraitDisabled || !buildComplete, () => 0, info.ShowShadow));
}

View File

@@ -32,8 +32,8 @@ namespace OpenRA.Mods.Common.Traits.Render
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var voxel = VoxelProvider.GetVoxel(image, Sequence);
yield return new ModelAnimation(voxel, () => WVec.Zero,
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
yield return new ModelAnimation(model, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(orientation(), facings) },
() => false, () => 0, ShowShadow);
}
@@ -49,14 +49,14 @@ namespace OpenRA.Mods.Common.Traits.Render
var body = self.Trait<BodyOrientation>();
var rv = self.Trait<RenderVoxels>();
var voxel = VoxelProvider.GetVoxel(rv.Image, info.Sequence);
rv.Add(new ModelAnimation(voxel, () => WVec.Zero,
var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence);
rv.Add(new ModelAnimation(model, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => IsTraitDisabled, () => 0, info.ShowShadow));
// Selection size
var rvi = self.Info.TraitInfo<RenderVoxelsInfo>();
var s = (int)(rvi.Scale * voxel.Size.Aggregate(Math.Max));
var s = (int)(rvi.Scale * model.Size.Aggregate(Math.Max));
size = new int2(s, s);
}

View File

@@ -41,12 +41,12 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
Func<WVec> turretOffset = () => body.LocalToWorld(t.Offset.Rotate(orientation()));
var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, Turret);
Func<WRot> turretBodyOrientation = () => WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw);
yield return new ModelAnimation(voxel, turretOffset,
yield return new ModelAnimation(model, turretOffset,
() => new[] { turretBodyOrientation(), body.QuantizeOrientation(orientation(), facings) }, () => false, () => 0, ShowShadow);
}
}
@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits.Render
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(VoxelProvider.GetVoxel(rv.Image, Info.Sequence),
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
() => turreted.Position(self), TurretRotation,
() => IsTraitDisabled || !buildComplete, () => 0, info.ShowShadow));
}

View File

@@ -236,7 +236,7 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence
TEMPERATE: t
SNOW: a
ModelSequenceFormat: PlaceholderModelSequence
ModelSequenceFormat: VoxelModelSequence
GameSpeeds:
slower: