diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 6fa5601a807e..9846496c0a5b 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -165,7 +165,7 @@ internal static void StartGame(string mapUID, WorldType type) using (new PerfTimer("PrepareMap")) map = ModData.PrepareMap(mapUID); using (new PerfTimer("NewWorld")) - OrderManager.World = new World(map, OrderManager, type); + OrderManager.World = new World(ModData, map, OrderManager, type); worldRenderer = new WorldRenderer(ModData, OrderManager.World); @@ -633,9 +633,9 @@ static void RenderTick() using (new PerfSample("render_widgets")) { - Renderer.WorldVoxelRenderer.BeginFrame(); + Renderer.WorldModelRenderer.BeginFrame(); Ui.PrepareRenderables(); - Renderer.WorldVoxelRenderer.EndFrame(); + Renderer.WorldModelRenderer.EndFrame(); Ui.Draw(); diff --git a/OpenRA.Game/GameRules/Ruleset.cs b/OpenRA.Game/GameRules/Ruleset.cs index d256144bb498..a5720d51adfd 100644 --- a/OpenRA.Game/GameRules/Ruleset.cs +++ b/OpenRA.Game/GameRules/Ruleset.cs @@ -29,6 +29,7 @@ public class Ruleset public readonly IReadOnlyDictionary Music; public readonly TileSet TileSet; public readonly SequenceProvider Sequences; + public readonly IReadOnlyDictionary ModelSequences; public Ruleset( IReadOnlyDictionary actors, @@ -37,7 +38,8 @@ public class Ruleset IReadOnlyDictionary notifications, IReadOnlyDictionary music, TileSet tileSet, - SequenceProvider sequences) + SequenceProvider sequences, + IReadOnlyDictionary modelSequences) { Actors = actors; Weapons = weapons; @@ -46,6 +48,7 @@ public class Ruleset Music = music; TileSet = tileSet; Sequences = sequences; + ModelSequences = modelSequences; foreach (var a in Actors.Values) { @@ -119,8 +122,11 @@ public static Ruleset LoadDefaults(ModData modData) var music = MergeOrDefault("Manifest,Music", fs, m.Music, null, null, k => new MusicInfo(k.Key, k.Value)); + var modelSequences = MergeOrDefault("Manifest,ModelSequences", fs, m.ModelSequences, null, null, + k => k); + // The default ruleset does not include a preferred tileset or sequence set - ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null); + ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null, modelSequences); }; if (modData.IsOnMainThread) @@ -145,12 +151,13 @@ public static Ruleset LoadDefaultsForTileSet(ModData modData, string tileSet) var dr = modData.DefaultRules; var ts = modData.DefaultTileSets[tileSet]; var sequences = modData.DefaultSequences[tileSet]; - return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences); + + return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences, dr.ModelSequences); } public static Ruleset Load(ModData modData, IReadOnlyFileSystem fileSystem, string tileSet, MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications, - MiniYaml mapMusic, MiniYaml mapSequences) + MiniYaml mapMusic, MiniYaml mapSequences, MiniYaml mapModelSequences) { var m = modData.Manifest; var dr = modData.DefaultRules; @@ -180,8 +187,12 @@ public static Ruleset LoadDefaultsForTileSet(ModData modData, string tileSet) var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] : new SequenceProvider(fileSystem, modData, ts, mapSequences); - // TODO: Add support for custom voxel sequences - ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences); + var modelSequences = dr.ModelSequences; + if (mapModelSequences != null) + modelSequences = MergeOrDefault("ModelSequences", fileSystem, m.ModelSequences, mapModelSequences, dr.ModelSequences, + k => k); + + ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences, modelSequences); }; if (modData.IsOnMainThread) diff --git a/OpenRA.Game/Graphics/Model.cs b/OpenRA.Game/Graphics/Model.cs new file mode 100644 index 000000000000..a05ffe6d41c4 --- /dev/null +++ b/OpenRA.Game/Graphics/Model.cs @@ -0,0 +1,83 @@ +#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 OpenRA.FileSystem; + +namespace OpenRA.Graphics +{ + public interface IModel + { + uint Frames { get; } + uint Sections { get; } + + float[] TransformationMatrix(uint section, uint frame); + float[] Size { get; } + float[] Bounds(uint frame); + 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 + { + IModel GetModelSequence(string model, string sequence); + bool HasModelSequence(string model, string sequence); + IVertexBuffer VertexBuffer { get; } + } + + public interface IModelSequenceLoader + { + Action OnMissingModelError { get; set; } + IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary modelDefinitions); + } + + public class PlaceholderModelSequenceLoader : IModelSequenceLoader + { + public Action OnMissingModelError { get; set; } + + class PlaceholderModelCache : IModelCache + { + public IVertexBuffer VertexBuffer { get { throw new NotImplementedException(); } } + + public void Dispose() { } + + public IModel GetModelSequence(string model, string sequence) + { + throw new NotImplementedException(); + } + + public bool HasModelSequence(string model, string sequence) + { + throw new NotImplementedException(); + } + } + + public PlaceholderModelSequenceLoader(ModData modData) { } + + public IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary modelDefinitions) + { + return new PlaceholderModelCache(); + } + } +} diff --git a/OpenRA.Game/Graphics/VoxelAnimation.cs b/OpenRA.Game/Graphics/ModelAnimation.cs similarity index 78% rename from OpenRA.Game/Graphics/VoxelAnimation.cs rename to OpenRA.Game/Graphics/ModelAnimation.cs index ff510bb26440..1fb15e7a7ea9 100644 --- a/OpenRA.Game/Graphics/VoxelAnimation.cs +++ b/OpenRA.Game/Graphics/ModelAnimation.cs @@ -14,18 +14,18 @@ namespace OpenRA.Graphics { - public struct VoxelAnimation + public struct ModelAnimation { - public readonly Voxel Voxel; + public readonly IModel Model; public readonly Func OffsetFunc; public readonly Func> RotationFunc; public readonly Func DisableFunc; public readonly Func FrameFunc; public readonly bool ShowShadow; - public VoxelAnimation(Voxel voxel, Func offset, Func> rotation, Func disable, Func frame, bool showshadow) + public ModelAnimation(IModel model, Func offset, Func> rotation, Func disable, Func frame, bool showshadow) { - Voxel = voxel; + Model = model; OffsetFunc = offset; RotationFunc = rotation; DisableFunc = disable; diff --git a/OpenRA.Game/Graphics/VoxelRenderer.cs b/OpenRA.Game/Graphics/ModelRenderer.cs similarity index 90% rename from OpenRA.Game/Graphics/VoxelRenderer.cs rename to OpenRA.Game/Graphics/ModelRenderer.cs index 215fcd794c44..916ed0ad7897 100644 --- a/OpenRA.Game/Graphics/VoxelRenderer.cs +++ b/OpenRA.Game/Graphics/ModelRenderer.cs @@ -17,14 +17,14 @@ namespace OpenRA.Graphics { - public class VoxelRenderProxy + public class ModelRenderProxy { public readonly Sprite Sprite; public readonly Sprite ShadowSprite; public readonly float ShadowDirection; public readonly float3[] ProjectedShadowBounds; - public VoxelRenderProxy(Sprite sprite, Sprite shadowSprite, float3[] projectedShadowBounds, float shadowDirection) + public ModelRenderProxy(Sprite sprite, Sprite shadowSprite, float3[] projectedShadowBounds, float shadowDirection) { Sprite = sprite; ShadowSprite = shadowSprite; @@ -33,7 +33,7 @@ public VoxelRenderProxy(Sprite sprite, Sprite shadowSprite, float3[] projectedSh } } - public sealed class VoxelRenderer : IDisposable + public sealed class ModelRenderer : IDisposable { // Static constants static readonly float[] ShadowDiffuse = new float[] { 0, 0, 0 }; @@ -53,7 +53,7 @@ public sealed class VoxelRenderer : IDisposable SheetBuilder sheetBuilder; - public VoxelRenderer(Renderer renderer, IShader shader) + public ModelRenderer(Renderer renderer, IShader shader) { this.renderer = renderer; this.shader = shader; @@ -78,8 +78,8 @@ public void SetViewportParams(Size screen, float zoom, int2 scroll) shader.SetMatrix("View", view); } - public VoxelRenderProxy RenderAsync( - WorldRenderer wr, IEnumerable voxels, WRot camera, float scale, + public ModelRenderProxy RenderAsync( + WorldRenderer wr, IEnumerable models, WRot camera, float scale, float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette) { @@ -105,18 +105,18 @@ public void SetViewportParams(Size screen, float zoom, int2 scroll) var stl = new float2(float.MaxValue, float.MaxValue); var sbr = new float2(float.MinValue, float.MinValue); - foreach (var v in voxels) + foreach (var m in models) { // Convert screen offset back to world coords - var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(v.OffsetFunc())); + var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); - var worldTransform = v.RotationFunc().Aggregate(Util.IdentityMatrix(), + var worldTransform = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); - var bounds = v.Voxel.Bounds(v.FrameFunc()); + var bounds = m.Model.Bounds(m.FrameFunc()); var worldBounds = Util.MatrixAABBMultiply(worldTransform, bounds); var screenBounds = Util.MatrixAABBMultiply(cameraTransform, worldBounds); var shadowBounds = Util.MatrixAABBMultiply(shadowTransform, worldBounds); @@ -177,13 +177,13 @@ public void SetViewportParams(Size screen, float zoom, int2 scroll) doRender.Add(Pair.New(sprite.Sheet, () => { - foreach (var v in voxels) + foreach (var m in models) { // Convert screen offset to world offset - var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(v.OffsetFunc())); + var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); - var rotations = v.RotationFunc().Aggregate(Util.IdentityMatrix(), + var rotations = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); var worldTransform = Util.MatrixMultiply(scaleTransform, rotations); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); @@ -196,11 +196,11 @@ public void SetViewportParams(Size screen, float zoom, int2 scroll) var lightTransform = Util.MatrixMultiply(Util.MatrixInverse(rotations), invShadowTransform); - var frame = v.FrameFunc(); - for (uint i = 0; i < v.Voxel.Limbs; i++) + var frame = m.FrameFunc(); + for (uint i = 0; i < m.Model.Sections; i++) { - var rd = v.Voxel.RenderData(i); - var t = v.Voxel.TransformationMatrix(i, frame); + var rd = m.Model.RenderData(i); + var t = m.Model.TransformationMatrix(i, frame); var it = Util.MatrixInverse(t); if (it == null) throw new InvalidOperationException("Failed to invert the transformed matrix of frame {0} during RenderAsync.".F(i)); @@ -208,12 +208,12 @@ public void SetViewportParams(Size screen, float zoom, int2 scroll) // 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, + if (m.ShowShadow) + Render(rd, wr.World.ModelCache, Util.MatrixMultiply(shadow, t), lightDirection, ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex); } } @@ -221,7 +221,7 @@ public void SetViewportParams(Size screen, float zoom, int2 scroll) var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, ZVector); screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector); - return new VoxelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1]); + return new ModelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1]); } static void CalculateSpriteGeometry(float2 tl, float2 br, float scale, out Size size, out int2 offset) @@ -258,7 +258,8 @@ static float[] ExtractRotationVector(float[] mtx) } void Render( - VoxelRenderData renderData, + ModelRenderData renderData, + IModelCache cache, float[] t, float[] lightDirection, float[] ambientLight, float[] diffuseLight, float colorPaletteTextureMidIndex, float normalsPaletteTextureMidIndex) @@ -270,7 +271,7 @@ static float[] ExtractRotationVector(float[] mtx) 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() diff --git a/OpenRA.Game/Graphics/VoxelProvider.cs b/OpenRA.Game/Graphics/VoxelProvider.cs deleted file mode 100644 index 03f8424cf478..000000000000 --- a/OpenRA.Game/Graphics/VoxelProvider.cs +++ /dev/null @@ -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> units; - - public static void Initialize(VoxelLoader loader, IReadOnlyFileSystem fileSystem, List sequences) - { - units = new Dictionary>(); - 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); - } - } -} diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 6c6399536b51..2b97a357eefe 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -113,9 +113,9 @@ List GenerateRenderables() worldRenderables = worldRenderables.Concat(World.Effects.SelectMany(e => e.Render(this))); worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey); - Game.Renderer.WorldVoxelRenderer.BeginFrame(); + Game.Renderer.WorldModelRenderer.BeginFrame(); var renderables = worldRenderables.Select(r => r.PrepareRender(this)).ToList(); - Game.Renderer.WorldVoxelRenderer.EndFrame(); + Game.Renderer.WorldModelRenderer.EndFrame(); return renderables; } @@ -182,14 +182,14 @@ public void Draw() if (World.OrderGenerator != null) aboveShroudOrderGenerator = World.OrderGenerator.RenderAboveShroud(this, World); - Game.Renderer.WorldVoxelRenderer.BeginFrame(); + Game.Renderer.WorldModelRenderer.BeginFrame(); var finalOverlayRenderables = aboveShroud .Concat(aboveShroudSelected) .Concat(aboveShroudEffects) .Concat(aboveShroudOrderGenerator) .Select(r => r.PrepareRender(this)) .ToList(); - Game.Renderer.WorldVoxelRenderer.EndFrame(); + Game.Renderer.WorldModelRenderer.EndFrame(); // HACK: Keep old grouping behaviour foreach (var g in finalOverlayRenderables.GroupBy(prs => prs.GetType())) @@ -241,7 +241,7 @@ public float3 Screen3DPxPosition(WPos pos) return new float3((float)Math.Round(px.X), (float)Math.Round(px.Y), px.Z); } - // For scaling vectors to pixel sizes in the voxel renderer + // For scaling vectors to pixel sizes in the model renderer public float3 ScreenVectorComponents(WVec vec) { return new float3( @@ -250,7 +250,7 @@ public float3 ScreenVectorComponents(WVec vec) (float)TileSize.Height * vec.Z / TileScale); } - // For scaling vectors to pixel sizes in the voxel renderer + // For scaling vectors to pixel sizes in the model renderer public float[] ScreenVector(WVec vec) { var xyz = ScreenVectorComponents(vec); diff --git a/OpenRA.Game/Manifest.cs b/OpenRA.Game/Manifest.cs index ba617f53203e..fd0df0f62f1e 100644 --- a/OpenRA.Game/Manifest.cs +++ b/OpenRA.Game/Manifest.cs @@ -31,6 +31,17 @@ public SpriteSequenceFormat(MiniYaml yaml) } } + public sealed class ModelSequenceFormat : IGlobalModData + { + public readonly string Type; + public readonly IReadOnlyDictionary Metadata; + public ModelSequenceFormat(MiniYaml yaml) + { + Type = yaml.Value; + Metadata = new ReadOnlyDictionary(yaml.ToDictionary()); + } + } + public class ModMetadata { public string Title; @@ -46,7 +57,7 @@ public class Manifest public readonly ModMetadata Metadata; public readonly string[] Rules, ServerTraits, - Sequences, VoxelSequences, Cursors, Chrome, Assemblies, ChromeLayout, + Sequences, ModelSequences, Cursors, Chrome, Assemblies, ChromeLayout, Weapons, Voices, Notifications, Music, Translations, TileSets, ChromeMetrics, MapCompatibility, Missions; @@ -60,7 +71,7 @@ public class Manifest public readonly string[] PackageFormats = { }; readonly string[] reservedModuleNames = { "Metadata", "Folders", "MapFolders", "Packages", "Rules", - "Sequences", "VoxelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons", + "Sequences", "ModelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons", "Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions", "ServerTraits", "LoadScreen", "Fonts", "SupportsMapsFrom", "SoundFormats", "SpriteFormats", "RequiresMods", "PackageFormats" }; @@ -87,7 +98,7 @@ public Manifest(string modId, IReadOnlyPackage package) Rules = YamlList(yaml, "Rules"); Sequences = YamlList(yaml, "Sequences"); - VoxelSequences = YamlList(yaml, "VoxelSequences"); + ModelSequences = YamlList(yaml, "ModelSequences"); Cursors = YamlList(yaml, "Cursors"); Chrome = YamlList(yaml, "Chrome"); Assemblies = YamlList(yaml, "Assemblies"); diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index adf35dba2f5e..79f12b494bdb 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -18,6 +18,7 @@ using System.Reflection; using System.Text; using OpenRA.FileSystem; +using OpenRA.Graphics; using OpenRA.Support; using OpenRA.Traits; @@ -168,7 +169,7 @@ public class Map : IReadOnlyFileSystem new MapField("Actors", "ActorDefinitions"), new MapField("Rules", "RuleDefinitions", required: false), new MapField("Sequences", "SequenceDefinitions", required: false), - new MapField("VoxelSequences", "VoxelSequenceDefinitions", required: false), + new MapField("ModelSequences", "ModelSequenceDefinitions", required: false), new MapField("Weapons", "WeaponDefinitions", required: false), new MapField("Voices", "VoiceDefinitions", required: false), new MapField("Music", "MusicDefinitions", required: false), @@ -199,7 +200,7 @@ public class Map : IReadOnlyFileSystem // Custom map yaml. Public for access by the map importers and lint checks public readonly MiniYaml RuleDefinitions; public readonly MiniYaml SequenceDefinitions; - public readonly MiniYaml VoxelSequenceDefinitions; + public readonly MiniYaml ModelSequenceDefinitions; public readonly MiniYaml WeaponDefinitions; public readonly MiniYaml VoiceDefinitions; public readonly MiniYaml MusicDefinitions; @@ -386,7 +387,7 @@ void PostInit() try { Rules = Ruleset.Load(modData, this, Tileset, RuleDefinitions, WeaponDefinitions, - VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions); + VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions, ModelSequenceDefinitions); } catch (Exception e) { diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index 00a8c45be094..dd2976cd6b81 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -307,8 +307,9 @@ public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassi var musicDefinitions = LoadRuleSection(yaml, "Music"); var notificationDefinitions = LoadRuleSection(yaml, "Notifications"); var sequenceDefinitions = LoadRuleSection(yaml, "Sequences"); + var modelSequenceDefinitions = LoadRuleSection(yaml, "ModelSequences"); var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions, - voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions); + voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions, modelSequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); return Pair.New(rules, flagged); @@ -390,8 +391,9 @@ public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml, Action(); var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader"); - var ctor = sequenceLoader != null ? sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null; - if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || ctor == null) + var sequenceCtor = sequenceLoader != null ? sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null; + if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || sequenceCtor == null) throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type)); - SpriteSequenceLoader = (ISpriteSequenceLoader)ctor.Invoke(new[] { this }); + SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this }); SpriteSequenceLoader.OnMissingSpriteError = s => Log.Write("debug", s); + var modelFormat = Manifest.Get(); + var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader"); + var modelCtor = modelLoader != null ? modelLoader.GetConstructor(new[] { typeof(ModData) }) : null; + if (modelLoader == null || !modelLoader.GetInterfaces().Contains(typeof(IModelSequenceLoader)) || modelCtor == null) + throw new InvalidOperationException("Unable to find a model loader for type '{0}'.".F(modelFormat.Type)); + + ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this }); + ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s); + defaultRules = Exts.Lazy(() => Ruleset.LoadDefaults(this)); defaultTileSets = Exts.Lazy(() => { @@ -122,10 +131,6 @@ public void InitializeLoaders(IReadOnlyFileSystem fileSystem) Game.Sound.Initialize(SoundLoaders, fileSystem); - if (VoxelLoader != null) - VoxelLoader.Dispose(); - VoxelLoader = new VoxelLoader(fileSystem); - CursorProvider = new CursorProvider(this); } @@ -189,9 +194,6 @@ public Map PrepareMap(string uid) 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; } @@ -200,8 +202,6 @@ public void Dispose() if (LoadScreen != null) LoadScreen.Dispose(); MapCache.Dispose(); - if (VoxelLoader != null) - VoxelLoader.Dispose(); if (ObjectCreator != null) ObjectCreator.Dispose(); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index d852f4584597..b42d659a3650 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -195,11 +195,8 @@ - - - - - + + @@ -256,6 +253,7 @@ + @@ -267,9 +265,7 @@ - - diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 6684734b13a4..7e6b084b197e 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -23,7 +23,7 @@ public sealed class Renderer : IDisposable public SpriteRenderer WorldSpriteRenderer { get; private set; } public SpriteRenderer WorldRgbaSpriteRenderer { get; private set; } public RgbaColorRenderer WorldRgbaColorRenderer { get; private set; } - public VoxelRenderer WorldVoxelRenderer { get; private set; } + public ModelRenderer WorldModelRenderer { get; private set; } public RgbaColorRenderer RgbaColorRenderer { get; private set; } public SpriteRenderer RgbaSpriteRenderer { get; private set; } public SpriteRenderer SpriteRenderer { get; private set; } @@ -59,7 +59,7 @@ public Renderer(IPlatform platform, GraphicSettings graphicSettings) WorldSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); WorldRgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); WorldRgbaColorRenderer = new RgbaColorRenderer(this, Device.CreateShader("color")); - WorldVoxelRenderer = new VoxelRenderer(this, Device.CreateShader("vxl")); + WorldModelRenderer = new ModelRenderer(this, Device.CreateShader("model")); RgbaColorRenderer = new RgbaColorRenderer(this, Device.CreateShader("color")); RgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); SpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); @@ -136,7 +136,7 @@ public void SetViewportParams(int2 scroll, float zoom) lastZoom = zoom; WorldRgbaSpriteRenderer.SetViewportParams(Resolution, depthScale, depthOffset, zoom, scroll); WorldSpriteRenderer.SetViewportParams(Resolution, depthScale, depthOffset, zoom, scroll); - WorldVoxelRenderer.SetViewportParams(Resolution, zoom, scroll); + WorldModelRenderer.SetViewportParams(Resolution, zoom, scroll); WorldRgbaColorRenderer.SetViewportParams(Resolution, depthScale, depthOffset, zoom, scroll); } } @@ -153,7 +153,7 @@ public void SetPalette(HardwarePalette palette) SpriteRenderer.SetPalette(currentPaletteTexture); WorldSpriteRenderer.SetPalette(currentPaletteTexture); WorldRgbaSpriteRenderer.SetPalette(currentPaletteTexture); - WorldVoxelRenderer.SetPalette(currentPaletteTexture); + WorldModelRenderer.SetPalette(currentPaletteTexture); } public void EndFrame(IInputHandler inputHandler) @@ -267,7 +267,7 @@ public void ReleaseWindowMouseFocus() public void Dispose() { Device.Dispose(); - WorldVoxelRenderer.Dispose(); + WorldModelRenderer.Dispose(); tempBuffer.Dispose(); if (fontSheetBuilder != null) fontSheetBuilder.Dispose(); diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index a6311b4c10c7..37774d7db213 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -40,6 +40,7 @@ public sealed class World : IDisposable public Session LobbyInfo { get { return OrderManager.LobbyInfo; } } public readonly MersenneTwister SharedRandom; + public readonly IModelCache ModelCache; public Player[] Players = new Player[0]; @@ -147,7 +148,7 @@ public bool ToggleInputMode() where T : IOrderGenerator, new() } } - internal World(Map map, OrderManager orderManager, WorldType type) + internal World(ModData modData, Map map, OrderManager orderManager, WorldType type) { Type = type; OrderManager = orderManager; @@ -156,6 +157,8 @@ internal World(Map map, OrderManager orderManager, WorldType type) Timestep = orderManager.LobbyInfo.GlobalSettings.Timestep; SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed); + ModelCache = modData.ModelSequenceLoader.CacheModels(map, modData, map.Rules.ModelSequences); + var worldActorType = type == WorldType.Editor ? "EditorWorld" : "World"; WorldActor = CreateActor(worldActorType, new TypeDictionary()); ActorMap = WorldActor.Trait(); @@ -437,6 +440,8 @@ public void Dispose() Game.Sound.StopAudio(); Game.Sound.StopVideo(); + ModelCache.Dispose(); + // Dispose newer actors first, and the world actor last foreach (var a in actors.Values.Reverse()) a.Dispose(); diff --git a/OpenRA.Game/FileFormats/HvaReader.cs b/OpenRA.Mods.Cnc/FileFormats/HvaReader.cs similarity index 98% rename from OpenRA.Game/FileFormats/HvaReader.cs rename to OpenRA.Mods.Cnc/FileFormats/HvaReader.cs index 57155fe5a175..dd3a98da56ee 100644 --- a/OpenRA.Game/FileFormats/HvaReader.cs +++ b/OpenRA.Mods.Cnc/FileFormats/HvaReader.cs @@ -14,7 +14,7 @@ using System.IO; using OpenRA.Graphics; -namespace OpenRA.FileFormats +namespace OpenRA.Mods.Cnc.FileFormats { public class HvaReader { diff --git a/OpenRA.Game/FileFormats/VxlReader.cs b/OpenRA.Mods.Cnc/FileFormats/VxlReader.cs similarity index 98% rename from OpenRA.Game/FileFormats/VxlReader.cs rename to OpenRA.Mods.Cnc/FileFormats/VxlReader.cs index a21c4f872477..9aea730acfd3 100644 --- a/OpenRA.Game/FileFormats/VxlReader.cs +++ b/OpenRA.Mods.Cnc/FileFormats/VxlReader.cs @@ -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 diff --git a/OpenRA.Game/Graphics/Voxel.cs b/OpenRA.Mods.Cnc/Graphics/Voxel.cs similarity index 80% rename from OpenRA.Game/Graphics/Voxel.cs rename to OpenRA.Mods.Cnc/Graphics/Voxel.cs index bb5d28fb9cde..14e2d98f43e3 100644 --- a/OpenRA.Game/Graphics/Voxel.cs +++ b/OpenRA.Mods.Cnc/Graphics/Voxel.cs @@ -11,25 +11,28 @@ 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 + public class Voxel : IModel { - Limb[] limbData; - float[] transforms; + readonly Limb[] limbData; + readonly float[] transforms; + readonly uint frames; + readonly uint limbs; - public readonly uint Frames; - public readonly uint Limbs; + uint IModel.Frames { get { return frames; } } + uint IModel.Sections { get { return limbs; } } public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva) { @@ -37,8 +40,8 @@ public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva) throw new InvalidOperationException("Voxel and hva limb counts don't match"); transforms = hva.Transforms; - Frames = hva.FrameCount; - Limbs = hva.LimbCount; + frames = hva.FrameCount; + limbs = hva.LimbCount; limbData = new Limb[vxl.LimbCount]; for (var i = 0; i < vxl.LimbCount; i++) @@ -55,14 +58,14 @@ public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva) public float[] TransformationMatrix(uint limb, uint frame) { - if (frame >= Frames) - throw new ArgumentOutOfRangeException("frame", "Only {0} frames exist.".F(Frames)); - if (limb >= Limbs) - throw new ArgumentOutOfRangeException("limb", "Only {1} limbs exist.".F(Limbs)); + if (frame >= frames) + throw new ArgumentOutOfRangeException("frame", "Only {0} frames exist.".F(frames)); + if (limb >= limbs) + throw new ArgumentOutOfRangeException("limb", "Only {1} limbs exist.".F(limbs)); var l = limbData[limb]; var t = new float[16]; - Array.Copy(transforms, 16 * (Limbs * frame + limb), t, 0, 16); + Array.Copy(transforms, 16 * (limbs * frame + limb), t, 0, 16); // Fix limb position t[12] *= l.Scale * (l.Bounds[3] - l.Bounds[0]) / l.Size[0]; @@ -76,7 +79,7 @@ public float[] TransformationMatrix(uint limb, uint frame) return t; } - public VoxelRenderData RenderData(uint limb) + public ModelRenderData RenderData(uint limb) { return limbData[limb].RenderData; } @@ -100,7 +103,7 @@ public float[] Bounds(uint frame) var ret = new float[] { float.MaxValue, float.MaxValue, float.MaxValue, float.MinValue, float.MinValue, float.MinValue }; - for (uint j = 0; j < Limbs; j++) + for (uint j = 0; j < limbs; j++) { var l = limbData[j]; var b = new float[] diff --git a/OpenRA.Game/Graphics/VoxelLoader.cs b/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs similarity index 92% rename from OpenRA.Game/Graphics/VoxelLoader.cs rename to OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs index f36ca1e1df94..7aa026eb4761 100644 --- a/OpenRA.Game/Graphics/VoxelLoader.cs +++ b/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs @@ -13,26 +13,13 @@ 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 @@ IEnumerable GenerateSlicePlanes(VxlLimb l) (u, v) => new float3(u, v, z)); } - public VoxelRenderData GenerateRenderData(VxlLimb l) + public ModelRenderData GenerateRenderData(VxlLimb l) { Vertex[] v; try @@ -203,14 +190,14 @@ public VoxelRenderData GenerateRenderData(VxlLimb l) 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; } diff --git a/OpenRA.Mods.Cnc/Graphics/VoxelModelSequenceLoader.cs b/OpenRA.Mods.Cnc/Graphics/VoxelModelSequenceLoader.cs new file mode 100644 index 000000000000..9a2d3ccf6006 --- /dev/null +++ b/OpenRA.Mods.Cnc/Graphics/VoxelModelSequenceLoader.cs @@ -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 OnMissingModelError { get; set; } + + public VoxelModelSequenceLoader(ModData modData) { } + + public IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary 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> models = new Dictionary>(); + + 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 VertexBuffer { get { return loader.VertexBuffer; } } + + public void Dispose() + { + loader.Dispose(); + } + } +} diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index fa3b96809572..8aa16bc425ee 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -147,6 +147,12 @@ + + + + + + diff --git a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs index 6c81d550175d..30b815c17dd0 100644 --- a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs +++ b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelUnloadBody.cs @@ -33,12 +33,12 @@ public class WithVoxelUnloadBodyInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo public object Create(ActorInitializer init) { return new WithVoxelUnloadBody(init.Self, this); } - public IEnumerable RenderPreviewVoxels( + public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) { var body = init.Actor.TraitInfo(); - var voxel = VoxelProvider.GetVoxel(image, IdleSequence); - yield return new VoxelAnimation(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 @@ public WithVoxelUnloadBody(Actor self, WithVoxelUnloadBodyInfo info) var body = self.Trait(); var rv = self.Trait(); - var idleVoxel = VoxelProvider.GetVoxel(rv.Image, info.IdleSequence); - rv.Add(new VoxelAnimation(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(); - 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 VoxelAnimation(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)); diff --git a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs index 2ba41825b7bd..1e1bd5e986b9 100644 --- a/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs +++ b/OpenRA.Mods.Cnc/Traits/Render/WithVoxelWalkerBody.cs @@ -34,14 +34,14 @@ public class WithVoxelWalkerBodyInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo public readonly bool ShowShadow = true; public object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.Self, this); } - public IEnumerable RenderPreviewVoxels( + public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) { - var voxel = VoxelProvider.GetVoxel(image, Sequence); + var model = init.World.ModelCache.GetModelSequence(image, Sequence); var body = init.Actor.TraitInfo(); var frame = init.Contains() ? init.Get() : 0; - yield return new VoxelAnimation(voxel, () => WVec.Zero, + yield return new ModelAnimation(model, () => WVec.Zero, () => new[] { body.QuantizeOrientation(orientation(), facings) }, () => false, () => frame, ShowShadow); } @@ -65,15 +65,15 @@ public WithVoxelWalkerBody(Actor self, WithVoxelWalkerBodyInfo info) var body = self.Trait(); var rv = self.Trait(); - var voxel = VoxelProvider.GetVoxel(rv.Image, info.Sequence); - frames = voxel.Frames; - rv.Add(new VoxelAnimation(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(); - 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); } diff --git a/OpenRA.Mods.Common/Traits/World/VoxelNormalsPalette.cs b/OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs similarity index 99% rename from OpenRA.Mods.Common/Traits/World/VoxelNormalsPalette.cs rename to OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs index 37531397f180..47e5b040c654 100644 --- a/OpenRA.Mods.Common/Traits/World/VoxelNormalsPalette.cs +++ b/OpenRA.Mods.Cnc/Traits/World/VoxelNormalsPalette.cs @@ -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 { diff --git a/OpenRA.Mods.Common/Graphics/VoxelActorPreview.cs b/OpenRA.Mods.Common/Graphics/ModelActorPreview.cs similarity index 89% rename from OpenRA.Mods.Common/Graphics/VoxelActorPreview.cs rename to OpenRA.Mods.Common/Graphics/ModelActorPreview.cs index dc6d52efa8b1..4d5ec1437c8c 100644 --- a/OpenRA.Mods.Common/Graphics/VoxelActorPreview.cs +++ b/OpenRA.Mods.Common/Graphics/ModelActorPreview.cs @@ -14,9 +14,9 @@ namespace OpenRA.Mods.Common.Graphics { - public class VoxelPreview : IActorPreview + public class ModelPreview : IActorPreview { - readonly VoxelAnimation[] components; + readonly ModelAnimation[] components; readonly float scale; readonly float[] lightAmbientColor; readonly float[] lightDiffuseColor; @@ -28,7 +28,7 @@ public class VoxelPreview : IActorPreview readonly WVec offset; readonly int zOffset; - public VoxelPreview(VoxelAnimation[] components, WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw, + public ModelPreview(ModelAnimation[] components, WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw, float[] lightAmbientColor, float[] lightDiffuseColor, WAngle cameraPitch, PaletteReference colorPalette, PaletteReference normalsPalette, PaletteReference shadowPalette) { @@ -52,7 +52,7 @@ public class VoxelPreview : IActorPreview public IEnumerable Render(WorldRenderer wr, WPos pos) { - yield return new VoxelRenderable(components, pos + offset, zOffset, camera, scale, + yield return new ModelRenderable(components, pos + offset, zOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, colorPalette, normalsPalette, shadowPalette); } diff --git a/OpenRA.Mods.Common/Graphics/VoxelRenderable.cs b/OpenRA.Mods.Common/Graphics/ModelRenderable.cs similarity index 77% rename from OpenRA.Mods.Common/Graphics/VoxelRenderable.cs rename to OpenRA.Mods.Common/Graphics/ModelRenderable.cs index ada39287a838..539a96f4652f 100644 --- a/OpenRA.Mods.Common/Graphics/VoxelRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/ModelRenderable.cs @@ -18,9 +18,9 @@ namespace OpenRA.Mods.Common.Graphics { - public struct VoxelRenderable : IRenderable + public struct ModelRenderable : IRenderable { - readonly IEnumerable voxels; + readonly IEnumerable models; readonly WPos pos; readonly int zOffset; readonly WRot camera; @@ -32,12 +32,12 @@ public struct VoxelRenderable : IRenderable readonly PaletteReference shadowPalette; readonly float scale; - public VoxelRenderable( - IEnumerable voxels, WPos pos, int zOffset, WRot camera, float scale, + public ModelRenderable( + IEnumerable models, WPos pos, int zOffset, WRot camera, float scale, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadow) { - this.voxels = voxels; + this.models = models; this.pos = pos; this.zOffset = zOffset; this.scale = scale; @@ -57,24 +57,24 @@ public struct VoxelRenderable : IRenderable public IRenderable WithPalette(PaletteReference newPalette) { - return new VoxelRenderable( - voxels, pos, zOffset, camera, scale, + return new ModelRenderable( + models, pos, zOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, newPalette, normalsPalette, shadowPalette); } public IRenderable WithZOffset(int newOffset) { - return new VoxelRenderable( - voxels, pos, newOffset, camera, scale, + return new ModelRenderable( + models, pos, newOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, palette, normalsPalette, shadowPalette); } public IRenderable OffsetBy(WVec vec) { - return new VoxelRenderable( - voxels, pos + vec, zOffset, camera, scale, + return new ModelRenderable( + models, pos + vec, zOffset, camera, scale, lightSource, lightAmbientColor, lightDiffuseColor, palette, normalsPalette, shadowPalette); } @@ -85,32 +85,32 @@ public IRenderable OffsetBy(WVec vec) static readonly float[] GroundNormal = new float[] { 0, 0, 1, 1 }; public IFinalizedRenderable PrepareRender(WorldRenderer wr) { - return new FinalizedVoxelRenderable(wr, this); + return new FinalizedModelRenderable(wr, this); } - struct FinalizedVoxelRenderable : IFinalizedRenderable + struct FinalizedModelRenderable : IFinalizedRenderable { - readonly VoxelRenderable voxel; - readonly VoxelRenderProxy renderProxy; + readonly ModelRenderable model; + readonly ModelRenderProxy renderProxy; - public FinalizedVoxelRenderable(WorldRenderer wr, VoxelRenderable voxel) + public FinalizedModelRenderable(WorldRenderer wr, ModelRenderable model) { - this.voxel = voxel; - var draw = voxel.voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); + this.model = model; + var draw = model.models.Where(v => v.DisableFunc == null || !v.DisableFunc()); - renderProxy = Game.Renderer.WorldVoxelRenderer.RenderAsync( - wr, draw, voxel.camera, voxel.scale, GroundNormal, voxel.lightSource, - voxel.lightAmbientColor, voxel.lightDiffuseColor, - voxel.palette, voxel.normalsPalette, voxel.shadowPalette); + renderProxy = Game.Renderer.WorldModelRenderer.RenderAsync( + wr, draw, model.camera, model.scale, GroundNormal, model.lightSource, + model.lightAmbientColor, model.lightDiffuseColor, + model.palette, model.normalsPalette, model.shadowPalette); } public void Render(WorldRenderer wr) { - var groundPos = voxel.pos - new WVec(0, 0, wr.World.Map.DistanceAboveTerrain(voxel.pos).Length); + var groundPos = model.pos - new WVec(0, 0, wr.World.Map.DistanceAboveTerrain(model.pos).Length); var tileScale = wr.World.Map.Grid.Type == MapGridType.RectangularIsometric ? 1448f : 1024f; - var groundZ = wr.World.Map.Grid.TileSize.Height * (groundPos.Z - voxel.pos.Z) / tileScale; - var pxOrigin = wr.Screen3DPosition(voxel.pos); + var groundZ = wr.World.Map.Grid.TileSize.Height * (groundPos.Z - model.pos.Z) / tileScale; + var pxOrigin = wr.Screen3DPosition(model.pos); // HACK: We don't have enough texture channels to pass the depth data to the shader // so for now just offset everything forward so that the back corner is rendered at pos. @@ -129,9 +129,9 @@ public void Render(WorldRenderer wr) public void RenderDebugGeometry(WorldRenderer wr) { - var groundPos = voxel.pos - new WVec(0, 0, wr.World.Map.DistanceAboveTerrain(voxel.pos).Length); - var groundZ = wr.World.Map.Grid.TileSize.Height * (groundPos.Z - voxel.pos.Z) / 1024f; - var pxOrigin = wr.Screen3DPosition(voxel.pos); + var groundPos = model.pos - new WVec(0, 0, wr.World.Map.DistanceAboveTerrain(model.pos).Length); + var groundZ = wr.World.Map.Grid.TileSize.Height * (groundPos.Z - model.pos.Z) / 1024f; + var pxOrigin = wr.Screen3DPosition(model.pos); var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); var iz = 1 / wr.Viewport.Zoom; @@ -151,14 +151,14 @@ public void RenderDebugGeometry(WorldRenderer wr) shadowOrigin + psb[2] }, iz, c); - // Draw voxel bounding box - var draw = voxel.voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); - var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(voxel.scale, voxel.scale, voxel.scale); - var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(voxel.camera.AsMatrix()); + // Draw bounding box + var draw = model.models.Where(v => v.DisableFunc == null || !v.DisableFunc()); + var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(model.scale, model.scale, model.scale); + var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(model.camera.AsMatrix()); foreach (var v in draw) { - var bounds = v.Voxel.Bounds(v.FrameFunc()); + var bounds = v.Model.Bounds(v.FrameFunc()); var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, (x, y) => OpenRA.Graphics.Util.MatrixMultiply(x, OpenRA.Graphics.Util.MakeFloatMatrix(y.AsMatrix()))); @@ -202,10 +202,10 @@ public Rectangle ScreenBounds(WorldRenderer wr) Pair Screen3DBounds(WorldRenderer wr) { - var pxOrigin = wr.ScreenPosition(voxel.pos); - var draw = voxel.voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); - var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(voxel.scale, voxel.scale, voxel.scale); - var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(voxel.camera.AsMatrix()); + var pxOrigin = wr.ScreenPosition(model.pos); + var draw = model.models.Where(v => v.DisableFunc == null || !v.DisableFunc()); + var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(model.scale, model.scale, model.scale); + var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(model.camera.AsMatrix()); var minX = float.MaxValue; var minY = float.MaxValue; @@ -216,7 +216,7 @@ public Rectangle ScreenBounds(WorldRenderer wr) foreach (var v in draw) { - var bounds = v.Voxel.Bounds(v.FrameFunc()); + var bounds = v.Model.Bounds(v.FrameFunc()); var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, (x, y) => OpenRA.Graphics.Util.MatrixMultiply(x, OpenRA.Graphics.Util.MakeFloatMatrix(y.AsMatrix()))); diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 650ab2e15ae6..bb3fe505cee5 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -164,8 +164,8 @@ - - + + @@ -520,7 +520,6 @@ - diff --git a/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs b/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs index 94a3b94e676a..ae03812e3e3b 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits.Render { public interface IRenderActorPreviewVoxelsInfo : ITraitInfo { - IEnumerable RenderPreviewVoxels( + IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p); } @@ -63,7 +63,7 @@ public virtual IEnumerable RenderPreview(ActorPreviewInitializer .SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, init.GetOrientation(), facings, palette)) .ToArray(); - yield return new VoxelPreview(components, WVec.Zero, 0, Scale, LightPitch, + yield return new ModelPreview(components, WVec.Zero, 0, Scale, LightPitch, LightYaw, LightAmbientColor, LightDiffuseColor, body.CameraPitch, palette, init.WorldRenderer.Palette(NormalsPalette), init.WorldRenderer.Palette(ShadowPalette)); } @@ -71,7 +71,7 @@ public virtual IEnumerable RenderPreview(ActorPreviewInitializer public class RenderVoxels : IRender, INotifyOwnerChanged { - readonly List components = new List(); + readonly List components = new List(); readonly Actor self; readonly RenderVoxelsInfo info; readonly BodyOrientation body; @@ -102,14 +102,14 @@ public IEnumerable Render(Actor self, WorldRenderer wr) initializePalettes = false; } - return new IRenderable[] { new VoxelRenderable( + return new IRenderable[] { new ModelRenderable( components, self.CenterPosition, 0, camera, info.Scale, lightSource, info.LightAmbientColor, info.LightDiffuseColor, colorPalette, normalsPalette, shadowPalette) }; } public string Image { get { return info.Image ?? self.Info.Name; } } - public void Add(VoxelAnimation v) { components.Add(v); } - public void Remove(VoxelAnimation v) { components.Remove(v); } + public void Add(ModelAnimation v) { components.Add(v); } + public void Remove(ModelAnimation v) { components.Remove(v); } } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs b/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs index 80537f32acfc..23e245d5e8a9 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithVoxelBarrel.cs @@ -37,7 +37,7 @@ public class WithVoxelBarrelInfo : ConditionalTraitInfo, IRenderActorPreviewVoxe public override object Create(ActorInitializer init) { return new WithVoxelBarrel(init.Self, this); } - public IEnumerable RenderPreviewVoxels( + public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) { if (!EnabledByDefault) @@ -49,7 +49,7 @@ public class WithVoxelBarrelInfo : ConditionalTraitInfo, IRenderActorPreviewVoxe var t = init.Actor.TraitInfos() .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 turretOrientation = () => body.QuantizeOrientation(WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw), facings); @@ -58,7 +58,7 @@ public class WithVoxelBarrelInfo : ConditionalTraitInfo, IRenderActorPreviewVoxe Func quantizedBody = () => body.QuantizeOrientation(orientation(), facings); Func barrelOffset = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret())).Rotate(quantizedBody())); - yield return new VoxelAnimation(voxel, barrelOffset, () => new[] { turretOrientation(), orientation() }, + yield return new ModelAnimation(model, barrelOffset, () => new[] { turretOrientation(), orientation() }, () => false, () => 0, ShowShadow); } } @@ -86,7 +86,7 @@ public WithVoxelBarrel(Actor self, WithVoxelBarrelInfo info) buildComplete = !self.Info.HasTraitInfo(); // always render instantly for units var rv = self.Trait(); - rv.Add(new VoxelAnimation(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)); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs b/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs index c1469ea1932b..9b5d45389f41 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithVoxelBody.cs @@ -28,12 +28,12 @@ public class WithVoxelBodyInfo : ConditionalTraitInfo, IRenderActorPreviewVoxels public override object Create(ActorInitializer init) { return new WithVoxelBody(init.Self, this); } - public IEnumerable RenderPreviewVoxels( + public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) { var body = init.Actor.TraitInfo(); - var voxel = VoxelProvider.GetVoxel(image, Sequence); - yield return new VoxelAnimation(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 @@ public WithVoxelBody(Actor self, WithVoxelBodyInfo info) var body = self.Trait(); var rv = self.Trait(); - var voxel = VoxelProvider.GetVoxel(rv.Image, info.Sequence); - rv.Add(new VoxelAnimation(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(); - 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); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs b/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs index d50271c5dded..042fd3dbcecc 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithVoxelTurret.cs @@ -31,7 +31,7 @@ public class WithVoxelTurretInfo : ConditionalTraitInfo, IRenderActorPreviewVoxe public override object Create(ActorInitializer init) { return new WithVoxelTurret(init.Self, this); } - public IEnumerable RenderPreviewVoxels( + public IEnumerable RenderPreviewVoxels( ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func orientation, int facings, PaletteReference p) { if (!EnabledByDefault) @@ -41,12 +41,12 @@ public class WithVoxelTurretInfo : ConditionalTraitInfo, IRenderActorPreviewVoxe var t = init.Actor.TraitInfos() .First(tt => tt.Turret == Turret); - var voxel = VoxelProvider.GetVoxel(image, Sequence); + var model = init.World.ModelCache.GetModelSequence(image, Sequence); Func turretOffset = () => body.LocalToWorld(t.Offset.Rotate(orientation())); var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, Turret); Func turretBodyOrientation = () => WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw); - yield return new VoxelAnimation(voxel, turretOffset, + yield return new ModelAnimation(model, turretOffset, () => new[] { turretBodyOrientation(), body.QuantizeOrientation(orientation(), facings) }, () => false, () => 0, ShowShadow); } } @@ -70,7 +70,7 @@ public WithVoxelTurret(Actor self, WithVoxelTurretInfo info) buildComplete = !self.Info.HasTraitInfo(); // always render instantly for units var rv = self.Trait(); - rv.Add(new VoxelAnimation(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)); } diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs index 8466d602c6ce..61be56a3adc2 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractMapRules.cs @@ -57,7 +57,7 @@ void IUtilityCommand.Run(Utility utility, string[] args) var map = new Map(modData, new Folder(".").OpenPackage(args[1], modData.ModFiles)); MergeAndPrint(map, "Rules", map.RuleDefinitions); MergeAndPrint(map, "Sequences", map.SequenceDefinitions); - MergeAndPrint(map, "VoxelSequences", map.VoxelSequenceDefinitions); + MergeAndPrint(map, "ModelSequences", map.ModelSequenceDefinitions); MergeAndPrint(map, "Weapons", map.WeaponDefinitions); MergeAndPrint(map, "Voices", map.VoiceDefinitions); MergeAndPrint(map, "Music", map.MusicDefinitions); diff --git a/glsl/vxl.frag b/glsl/model.frag similarity index 100% rename from glsl/vxl.frag rename to glsl/model.frag diff --git a/glsl/vxl.vert b/glsl/model.vert similarity index 100% rename from glsl/vxl.vert rename to glsl/model.vert diff --git a/mods/all/mod.yaml b/mods/all/mod.yaml index b71f22ff5b1b..47b3e269a0c7 100644 --- a/mods/all/mod.yaml +++ b/mods/all/mod.yaml @@ -30,3 +30,5 @@ SoundFormats: SpriteFormats: SpriteSequenceFormat: DefaultSpriteSequence + +ModelSequenceFormat: PlaceholderModelSequence diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index f29ee495e581..371e951e0278 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -197,6 +197,8 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence DESERT: .des JUNGLE: .jun +ModelSequenceFormat: PlaceholderModelSequence + GameSpeeds: slower: Name: Slower diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 5c60cdb37e30..43768456ecda 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -174,6 +174,8 @@ SpriteFormats: R8, ShpTD, TmpRA SpriteSequenceFormat: DefaultSpriteSequence +ModelSequenceFormat: PlaceholderModelSequence + GameSpeeds: slower: Name: Slower diff --git a/mods/modcontent/mod.yaml b/mods/modcontent/mod.yaml index da8167c69128..488bdd1f188e 100644 --- a/mods/modcontent/mod.yaml +++ b/mods/modcontent/mod.yaml @@ -55,3 +55,5 @@ SoundFormats: SpriteFormats: ShpTD SpriteSequenceFormat: DefaultSpriteSequence + +ModelSequenceFormat: PlaceholderModelSequence diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 34a6ae3a3c08..00c035a1116f 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -200,6 +200,8 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence INTERIOR: .int DESERT: .des +ModelSequenceFormat: PlaceholderModelSequence + GameSpeeds: slower: Name: Slower diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index 4d1c3156a7c8..81aa4a8e9915 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -100,7 +100,7 @@ Sequences: ts|sequences/bridges.yaml ts|sequences/critters.yaml -VoxelSequences: +ModelSequences: ts|sequences/voxels.yaml TileSets: @@ -236,6 +236,8 @@ SpriteSequenceFormat: TilesetSpecificSpriteSequence TEMPERATE: t SNOW: a +ModelSequenceFormat: VoxelModelSequence + GameSpeeds: slower: Name: Slower