Turn ModelRenderer and VoxelCache into traits

This commit is contained in:
Gustas
2023-09-19 18:40:57 +03:00
committed by Matthias Mailänder
parent d427072cc9
commit 686040a316
33 changed files with 481 additions and 469 deletions

View File

@@ -664,7 +664,7 @@ namespace OpenRA
// Prepare renderables (i.e. render voxels) before calling BeginFrame
using (new PerfSample("render_prepare"))
{
Renderer.WorldModelRenderer.BeginFrame();
worldRenderer?.BeginFrame();
// World rendering is disabled while the loading screen is displayed
if (worldRenderer != null && !worldRenderer.World.IsLoadingGameSave)
@@ -674,7 +674,7 @@ namespace OpenRA
}
Ui.PrepareRenderables();
Renderer.WorldModelRenderer.EndFrame();
worldRenderer?.EndFrame();
}
// worldRenderer is null during the initial install/download screen

View File

@@ -10,9 +10,8 @@
#endregion
using System;
using System.Collections.Generic;
using OpenRA.FileSystem;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
@@ -30,6 +29,14 @@ namespace OpenRA.Graphics
Rectangle AggregateBounds { get; }
}
public interface IModelWidget
{
public string Palette { get; }
public float Scale { get; }
public void Setup(Func<bool> isVisible, Func<string> getPalette, Func<string> getPlayerPalette,
Func<float> getScale, Func<IModel> getVoxel, Func<WRot> getRotation);
}
public readonly struct ModelRenderData
{
public readonly int Start;
@@ -44,51 +51,13 @@ namespace OpenRA.Graphics
}
}
public interface IModelCache : IDisposable
public interface IModelCacheInfo : ITraitInfoInterface { }
public interface IModelCache
{
IModel GetModel(string model);
IModel GetModelSequence(string model, string sequence);
bool HasModelSequence(string model, string sequence);
IVertexBuffer<ModelVertex> VertexBuffer { get; }
}
public interface IModelSequenceLoader
{
Action<string> OnMissingModelError { get; set; }
IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary<string, MiniYamlNode> modelDefinitions);
}
public class PlaceholderModelSequenceLoader : IModelSequenceLoader
{
public Action<string> OnMissingModelError { get; set; }
sealed class PlaceholderModelCache : IModelCache
{
public IVertexBuffer<ModelVertex> VertexBuffer => throw new NotImplementedException();
public void Dispose() { }
public IModel GetModel(string model)
{
throw new NotImplementedException();
}
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<string, MiniYamlNode> modelDefinitions)
{
return new PlaceholderModelCache();
}
}
}

View File

@@ -104,6 +104,13 @@ namespace OpenRA
string GLVersion { get; }
}
public interface IRenderer
{
void BeginFrame();
void EndFrame();
void SetPalette(ITexture palette);
}
public interface IVertexBuffer<T> : IDisposable where T : struct
{
void Bind();

View File

@@ -313,249 +313,5 @@ namespace OpenRA.Graphics
(int)((byte)(t * a2 * c2.G + 0.5f) + (1 - t) * (byte)(a1 * c1.G + 0.5f)),
(int)((byte)(t * a2 * c2.B + 0.5f) + (1 - t) * (byte)(a1 * c1.B + 0.5f))));
}
public static float[] IdentityMatrix()
{
return new float[]
{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
}
public static float[] ScaleMatrix(float sx, float sy, float sz)
{
return new float[]
{
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
0, 0, 0, 1,
};
}
public static float[] TranslationMatrix(float x, float y, float z)
{
return new float[]
{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1,
};
}
public static float[] MatrixMultiply(float[] lhs, float[] rhs)
{
var mtx = new float[16];
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
{
mtx[4 * i + j] = 0;
for (var k = 0; k < 4; k++)
mtx[4 * i + j] += lhs[4 * k + j] * rhs[4 * i + k];
}
return mtx;
}
public static float[] MatrixVectorMultiply(float[] mtx, float[] vec)
{
var ret = new float[4];
for (var j = 0; j < 4; j++)
{
ret[j] = 0;
for (var k = 0; k < 4; k++)
ret[j] += mtx[4 * k + j] * vec[k];
}
return ret;
}
public static float[] MatrixInverse(float[] m)
{
var mtx = new float[16];
mtx[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
mtx[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
mtx[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
mtx[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
mtx[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
mtx[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
mtx[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
mtx[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
mtx[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
mtx[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
mtx[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
mtx[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
mtx[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
mtx[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
mtx[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
mtx[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
var det = m[0] * mtx[0] + m[1] * mtx[4] + m[2] * mtx[8] + m[3] * mtx[12];
if (det == 0)
return null;
for (var i = 0; i < 16; i++)
mtx[i] *= 1 / det;
return mtx;
}
public static float[] MakeFloatMatrix(Int32Matrix4x4 imtx)
{
var multipler = 1f / imtx.M44;
return new[]
{
imtx.M11 * multipler,
imtx.M12 * multipler,
imtx.M13 * multipler,
imtx.M14 * multipler,
imtx.M21 * multipler,
imtx.M22 * multipler,
imtx.M23 * multipler,
imtx.M24 * multipler,
imtx.M31 * multipler,
imtx.M32 * multipler,
imtx.M33 * multipler,
imtx.M34 * multipler,
imtx.M41 * multipler,
imtx.M42 * multipler,
imtx.M43 * multipler,
imtx.M44 * multipler,
};
}
public static float[] MatrixAABBMultiply(float[] mtx, float[] bounds)
{
// Corner offsets
var ix = new uint[] { 0, 0, 0, 0, 3, 3, 3, 3 };
var iy = new uint[] { 1, 1, 4, 4, 1, 1, 4, 4 };
var iz = new uint[] { 2, 5, 2, 5, 2, 5, 2, 5 };
// Vectors to opposing corner
var ret = new[]
{
float.MaxValue, float.MaxValue, float.MaxValue,
float.MinValue, float.MinValue, float.MinValue
};
// Transform vectors and find new bounding box
for (var i = 0; i < 8; i++)
{
var vec = new[] { bounds[ix[i]], bounds[iy[i]], bounds[iz[i]], 1 };
var tvec = MatrixVectorMultiply(mtx, vec);
ret[0] = Math.Min(ret[0], tvec[0] / tvec[3]);
ret[1] = Math.Min(ret[1], tvec[1] / tvec[3]);
ret[2] = Math.Min(ret[2], tvec[2] / tvec[3]);
ret[3] = Math.Max(ret[3], tvec[0] / tvec[3]);
ret[4] = Math.Max(ret[4], tvec[1] / tvec[3]);
ret[5] = Math.Max(ret[5], tvec[2] / tvec[3]);
}
return ret;
}
}
}

View File

@@ -44,6 +44,7 @@ namespace OpenRA.Graphics
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new();
readonly List<IRenderable> renderablesBuffer = new();
readonly IRenderer[] renderers;
internal WorldRenderer(ModData modData, World world)
{
@@ -66,11 +67,24 @@ namespace OpenRA.Graphics
palette.Initialize();
TerrainLighting = world.WorldActor.TraitOrDefault<ITerrainLighting>();
renderers = world.WorldActor.TraitsImplementing<IRenderer>().ToArray();
terrainRenderer = world.WorldActor.TraitOrDefault<IRenderTerrain>();
debugVis = Exts.Lazy(() => world.WorldActor.TraitOrDefault<DebugVisualizations>());
}
public void BeginFrame()
{
foreach (var r in renderers)
r.BeginFrame();
}
public void EndFrame()
{
foreach (var r in renderers)
r.EndFrame();
}
public void UpdatePalettesForPlayer(string internalName, Color color, bool replaceExisting)
{
foreach (var pal in World.WorldActor.TraitsImplementing<ILoadsPlayerPalettes>())

View File

@@ -43,17 +43,6 @@ namespace OpenRA
}
}
public sealed class ModelSequenceFormat : IGlobalModData
{
public readonly string Type;
public readonly IReadOnlyDictionary<string, MiniYaml> Metadata;
public ModelSequenceFormat(MiniYaml yaml)
{
Type = yaml.Value;
Metadata = new ReadOnlyDictionary<string, MiniYaml>(yaml.ToDictionary());
}
}
public class ModMetadata
{
public string Title;

View File

@@ -33,7 +33,6 @@ namespace OpenRA
public readonly ISpriteLoader[] SpriteLoaders;
public readonly ITerrainLoader TerrainLoader;
public readonly ISpriteSequenceLoader SpriteSequenceLoader;
public readonly IModelSequenceLoader ModelSequenceLoader;
public readonly IVideoLoader[] VideoLoaders;
public readonly HotkeyManager Hotkeys;
public ILoadScreen LoadScreen { get; }
@@ -90,15 +89,6 @@ namespace OpenRA
SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this });
var modelFormat = Manifest.Get<ModelSequenceFormat>();
var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader");
var modelCtor = modelLoader?.GetConstructor(new[] { typeof(ModData) });
if (modelLoader == null || !modelLoader.GetInterfaces().Contains(typeof(IModelSequenceLoader)) || modelCtor == null)
throw new InvalidOperationException($"Unable to find a model loader for type '{modelFormat.Type}'.");
ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this });
ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s);
Hotkeys = new HotkeyManager(ModFiles, Game.Settings.Keys, Manifest);
defaultRules = Exts.Lazy(() => Ruleset.LoadDefaults(this));

View File

@@ -27,7 +27,7 @@ namespace OpenRA
public SpriteRenderer WorldSpriteRenderer { get; }
public RgbaSpriteRenderer WorldRgbaSpriteRenderer { get; }
public RgbaColorRenderer WorldRgbaColorRenderer { get; }
public ModelRenderer WorldModelRenderer { get; }
public IRenderer[] WorldRenderers = Array.Empty<IRenderer>();
public RgbaColorRenderer RgbaColorRenderer { get; }
public SpriteRenderer SpriteRenderer { get; }
public RgbaSpriteRenderer RgbaSpriteRenderer { get; }
@@ -92,7 +92,6 @@ namespace OpenRA
WorldSpriteRenderer = new SpriteRenderer(this, Context.CreateShader(combinedBindings));
WorldRgbaSpriteRenderer = new RgbaSpriteRenderer(WorldSpriteRenderer);
WorldRgbaColorRenderer = new RgbaColorRenderer(WorldSpriteRenderer);
WorldModelRenderer = new ModelRenderer(this, Context.CreateShader(new ModelShaderBindings()));
SpriteRenderer = new SpriteRenderer(this, Context.CreateShader(combinedBindings));
RgbaSpriteRenderer = new RgbaSpriteRenderer(SpriteRenderer);
RgbaColorRenderer = new RgbaColorRenderer(SpriteRenderer);
@@ -259,8 +258,6 @@ namespace OpenRA
if (lastWorldViewport != worldViewport)
{
WorldSpriteRenderer.SetViewportParams(worldSheet.Size, WorldDownscaleFactor, depthMargin, worldViewport.Location);
WorldModelRenderer.SetViewportParams();
lastWorldViewport = worldViewport;
}
@@ -308,7 +305,9 @@ namespace OpenRA
SpriteRenderer.SetPalette(currentPaletteTexture, palette.ColorShifts);
WorldSpriteRenderer.SetPalette(currentPaletteTexture, palette.ColorShifts);
WorldModelRenderer.SetPalette(currentPaletteTexture);
foreach (var r in WorldRenderers)
r.SetPalette(currentPaletteTexture);
}
public void EndFrame(IInputHandler inputHandler)
@@ -385,6 +384,16 @@ namespace OpenRA
}
}
public IFrameBuffer CreateFrameBuffer(Size s)
{
return Context.CreateFrameBuffer(s);
}
public IShader CreateShader(IShaderBindings bindings)
{
return Context.CreateShader(bindings);
}
public IVertexBuffer<T> CreateVertexBuffer<T>(int length) where T : struct
{
return Context.CreateVertexBuffer<T>(length);
@@ -514,7 +523,6 @@ namespace OpenRA
public void Dispose()
{
WorldModelRenderer.Dispose();
tempVertexBuffer.Dispose();
quadIndexBuffer.Dispose();
fontSheetBuilder?.Dispose();

View File

@@ -49,7 +49,6 @@ namespace OpenRA
public readonly MersenneTwister SharedRandom;
public readonly MersenneTwister LocalRandom;
public readonly IModelCache ModelCache;
public LongBitSet<PlayerBitMask> AllPlayersMask = default;
public readonly LongBitSet<PlayerBitMask> NoPlayersMask = default;
@@ -214,8 +213,6 @@ namespace OpenRA
SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
LocalRandom = new MersenneTwister();
ModelCache = modData.ModelSequenceLoader.CacheModels(Map, modData, Map.Rules.ModelSequences);
var worldActorType = type == WorldType.Editor ? SystemActors.EditorWorld : SystemActors.World;
WorldActor = CreateActor(worldActorType.ToString(), new TypeDictionary());
ActorMap = WorldActor.Trait<IActorMap>();
@@ -598,8 +595,6 @@ namespace OpenRA
if (IsLoadingGameSave)
Game.Sound.DisableAllSounds = false;
ModelCache.Dispose();
// Dispose newer actors first, and the world actor last
foreach (var a in actors.Values.Reverse())
a.Dispose();

View File

@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
Transforms[c + ids[k]] = s.ReadFloat();
Array.Copy(Transforms, 16 * (LimbCount * j + i), testMatrix, 0, 16);
if (OpenRA.Graphics.Util.MatrixInverse(testMatrix) == null)
if (Util.MatrixInverse(testMatrix) == null)
throw new InvalidDataException(
$"The transformation matrix for HVA file `{fileName}` section {i} frame {j} is invalid because it is not invertible!");
}

View File

@@ -11,12 +11,15 @@
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.Graphics
namespace OpenRA.Mods.Cnc.Graphics
{
public class ModelPreview : IActorPreview
{
readonly ModelRenderer renderer;
readonly ModelAnimation[] components;
readonly float scale;
readonly float[] lightAmbientColor;
@@ -29,10 +32,11 @@ namespace OpenRA.Mods.Common.Graphics
readonly WVec offset;
readonly int zOffset;
public ModelPreview(ModelAnimation[] components, in WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw,
public ModelPreview(ModelRenderer renderer, ModelAnimation[] components, in WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw,
float[] lightAmbientColor, float[] lightDiffuseColor, WAngle cameraPitch,
PaletteReference colorPalette, PaletteReference normalsPalette, PaletteReference shadowPalette)
{
this.renderer = renderer;
this.components = components;
this.scale = scale;
this.lightAmbientColor = lightAmbientColor;
@@ -53,14 +57,14 @@ namespace OpenRA.Mods.Common.Graphics
IEnumerable<IRenderable> IActorPreview.RenderUI(WorldRenderer wr, int2 pos, float scale)
{
yield return new UIModelRenderable(components, WPos.Zero + offset, pos, zOffset, camera, scale * this.scale,
yield return new UIModelRenderable(renderer, components, WPos.Zero + offset, pos, zOffset, camera, scale * this.scale,
lightSource, lightAmbientColor, lightDiffuseColor,
colorPalette, normalsPalette, shadowPalette);
}
IEnumerable<IRenderable> IActorPreview.Render(WorldRenderer wr, WPos pos)
{
yield return new ModelRenderable(components, pos + offset, zOffset, camera, scale,
yield return new ModelRenderable(renderer, components, pos + offset, zOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
colorPalette, normalsPalette, shadowPalette);
}

View File

@@ -13,12 +13,14 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.Graphics
namespace OpenRA.Mods.Cnc.Graphics
{
public class ModelRenderable : IPalettedRenderable, IModifyableRenderable
{
readonly ModelRenderer renderer;
readonly IEnumerable<ModelAnimation> models;
readonly WRot camera;
readonly WRot lightSource;
@@ -29,20 +31,21 @@ namespace OpenRA.Mods.Common.Graphics
readonly float scale;
public ModelRenderable(
IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,
in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadow)
: this(models, pos, zOffset, camera, scale,
: this(renderer, models, pos, zOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
color, normals, shadow, 1f,
float3.Ones, TintModifiers.None) { }
public ModelRenderable(
IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,
in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadow,
float alpha, in float3 tint, TintModifiers tintModifiers)
{
this.renderer = renderer;
this.models = models;
Pos = pos;
ZOffset = zOffset;
@@ -71,7 +74,7 @@ namespace OpenRA.Mods.Common.Graphics
public IPalettedRenderable WithPalette(PaletteReference newPalette)
{
return new ModelRenderable(
models, Pos, ZOffset, camera, scale,
renderer, models, Pos, ZOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
newPalette, normalsPalette, shadowPalette, Alpha, Tint, TintModifiers);
}
@@ -79,7 +82,7 @@ namespace OpenRA.Mods.Common.Graphics
public IRenderable WithZOffset(int newOffset)
{
return new ModelRenderable(
models, Pos, newOffset, camera, scale,
renderer, models, Pos, newOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
Palette, normalsPalette, shadowPalette, Alpha, Tint, TintModifiers);
}
@@ -87,7 +90,7 @@ namespace OpenRA.Mods.Common.Graphics
public IRenderable OffsetBy(in WVec vec)
{
return new ModelRenderable(
models, Pos + vec, ZOffset, camera, scale,
renderer, models, Pos + vec, ZOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
Palette, normalsPalette, shadowPalette, Alpha, Tint, TintModifiers);
}
@@ -97,7 +100,7 @@ namespace OpenRA.Mods.Common.Graphics
public IModifyableRenderable WithAlpha(float newAlpha)
{
return new ModelRenderable(
models, Pos, ZOffset, camera, scale,
renderer, models, Pos, ZOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
Palette, normalsPalette, shadowPalette, newAlpha, Tint, TintModifiers);
}
@@ -105,7 +108,7 @@ namespace OpenRA.Mods.Common.Graphics
public IModifyableRenderable WithTint(in float3 newTint, TintModifiers newTintModifiers)
{
return new ModelRenderable(
models, Pos, ZOffset, camera, scale,
renderer, models, Pos, ZOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
Palette, normalsPalette, shadowPalette, Alpha, newTint, newTintModifiers);
}
@@ -127,7 +130,7 @@ namespace OpenRA.Mods.Common.Graphics
var map = wr.World.Map;
var groundOrientation = map.TerrainOrientation(map.CellContaining(model.Pos));
renderProxy = Game.Renderer.WorldModelRenderer.RenderAsync(
renderProxy = model.renderer.RenderAsync(
wr, draw, model.camera, model.scale, groundOrientation, model.lightSource,
model.lightAmbientColor, model.lightDiffuseColor,
model.Palette, model.normalsPalette, model.shadowPalette);
@@ -199,17 +202,17 @@ namespace OpenRA.Mods.Common.Graphics
// Draw bounding box
var draw = model.models.Where(v => v.IsVisible);
var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(model.scale, model.scale, model.scale);
var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(model.camera.AsMatrix());
var scaleTransform = Util.ScaleMatrix(model.scale, model.scale, model.scale);
var cameraTransform = Util.MakeFloatMatrix(model.camera.AsMatrix());
foreach (var v in draw)
{
var bounds = v.Model.Bounds(v.FrameFunc());
var rotation = OpenRA.Graphics.Util.MakeFloatMatrix(v.RotationFunc().AsMatrix());
var worldTransform = OpenRA.Graphics.Util.MatrixMultiply(scaleTransform, rotation);
var rotation = Util.MakeFloatMatrix(v.RotationFunc().AsMatrix());
var worldTransform = Util.MatrixMultiply(scaleTransform, rotation);
var pxPos = pxOrigin + wr.ScreenVectorComponents(v.OffsetFunc());
var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform);
var screenTransform = Util.MatrixMultiply(cameraTransform, worldTransform);
DrawBoundsBox(wr, pxPos, screenTransform, bounds, 1, Color.Yellow);
}
}
@@ -224,7 +227,7 @@ namespace OpenRA.Mods.Common.Graphics
for (var i = 0; i < 8; i++)
{
var vec = new[] { bounds[CornerXIndex[i]], bounds[CornerYIndex[i]], bounds[CornerZIndex[i]], 1 };
var screen = OpenRA.Graphics.Util.MatrixVectorMultiply(transform, vec);
var screen = Util.MatrixVectorMultiply(transform, vec);
corners[i] = wr.Viewport.WorldToViewPx(pxPos + new float3(screen[0], screen[1], screen[2]));
}
@@ -250,8 +253,8 @@ namespace OpenRA.Mods.Common.Graphics
{
var pxOrigin = wr.ScreenPosition(model.Pos);
var draw = model.models.Where(v => v.IsVisible);
var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(model.scale, model.scale, model.scale);
var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(model.camera.AsMatrix());
var scaleTransform = Util.ScaleMatrix(model.scale, model.scale, model.scale);
var cameraTransform = Util.MakeFloatMatrix(model.camera.AsMatrix());
var minX = float.MaxValue;
var minY = float.MaxValue;
@@ -263,16 +266,16 @@ namespace OpenRA.Mods.Common.Graphics
foreach (var v in draw)
{
var bounds = v.Model.Bounds(v.FrameFunc());
var rotation = OpenRA.Graphics.Util.MakeFloatMatrix(v.RotationFunc().AsMatrix());
var worldTransform = OpenRA.Graphics.Util.MatrixMultiply(scaleTransform, rotation);
var rotation = Util.MakeFloatMatrix(v.RotationFunc().AsMatrix());
var worldTransform = Util.MatrixMultiply(scaleTransform, rotation);
var pxPos = pxOrigin + wr.ScreenVectorComponents(v.OffsetFunc());
var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform);
var screenTransform = Util.MatrixMultiply(cameraTransform, worldTransform);
for (var i = 0; i < 8; i++)
{
var vec = new float[] { bounds[CornerXIndex[i]], bounds[CornerYIndex[i]], bounds[CornerZIndex[i]], 1 };
var screen = OpenRA.Graphics.Util.MatrixVectorMultiply(screenTransform, vec);
var screen = Util.MatrixVectorMultiply(screenTransform, vec);
minX = Math.Min(minX, pxPos.X + screen[0]);
minY = Math.Min(minY, pxPos.Y + screen[1]);
minZ = Math.Min(minZ, pxPos.Z + screen[2]);

View File

@@ -13,12 +13,14 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Primitives;
namespace OpenRA.Mods.Common.Graphics
namespace OpenRA.Mods.Cnc.Graphics
{
public class UIModelRenderable : IRenderable, IPalettedRenderable
{
readonly ModelRenderer renderer;
readonly IEnumerable<ModelAnimation> models;
readonly int2 screenPos;
readonly WRot camera;
@@ -30,10 +32,11 @@ namespace OpenRA.Mods.Common.Graphics
readonly float scale;
public UIModelRenderable(
IEnumerable<ModelAnimation> models, WPos effectiveWorldPos, int2 screenPos, int zOffset,
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos effectiveWorldPos, int2 screenPos, int zOffset,
in WRot camera, float scale, in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadow)
{
this.renderer = renderer;
this.models = models;
Pos = effectiveWorldPos;
this.screenPos = screenPos;
@@ -56,7 +59,7 @@ namespace OpenRA.Mods.Common.Graphics
public IPalettedRenderable WithPalette(PaletteReference newPalette)
{
return new UIModelRenderable(
models, Pos, screenPos, ZOffset, camera, scale,
renderer, models, Pos, screenPos, ZOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
newPalette, normalsPalette, shadowPalette);
}
@@ -80,7 +83,7 @@ namespace OpenRA.Mods.Common.Graphics
this.model = model;
var draw = model.models.Where(v => v.IsVisible);
renderProxy = Game.Renderer.WorldModelRenderer.RenderAsync(
renderProxy = model.renderer.RenderAsync(
wr, draw, model.camera, model.scale, WRot.None, model.lightSource,
model.lightAmbientColor, model.lightDiffuseColor,
model.Palette, model.normalsPalette, model.shadowPalette);
@@ -112,8 +115,8 @@ namespace OpenRA.Mods.Common.Graphics
{
var pxOrigin = model.screenPos;
var draw = model.models.Where(v => v.IsVisible);
var scaleTransform = OpenRA.Graphics.Util.ScaleMatrix(model.scale, model.scale, model.scale);
var cameraTransform = OpenRA.Graphics.Util.MakeFloatMatrix(model.camera.AsMatrix());
var scaleTransform = Util.ScaleMatrix(model.scale, model.scale, model.scale);
var cameraTransform = Util.MakeFloatMatrix(model.camera.AsMatrix());
var minX = float.MaxValue;
var minY = float.MaxValue;
@@ -125,16 +128,16 @@ namespace OpenRA.Mods.Common.Graphics
foreach (var v in draw)
{
var bounds = v.Model.Bounds(v.FrameFunc());
var rotation = OpenRA.Graphics.Util.MakeFloatMatrix(v.RotationFunc().AsMatrix());
var worldTransform = OpenRA.Graphics.Util.MatrixMultiply(scaleTransform, rotation);
var rotation = Util.MakeFloatMatrix(v.RotationFunc().AsMatrix());
var worldTransform = Util.MatrixMultiply(scaleTransform, rotation);
var pxPos = pxOrigin + wr.ScreenVectorComponents(v.OffsetFunc());
var screenTransform = OpenRA.Graphics.Util.MatrixMultiply(cameraTransform, worldTransform);
var screenTransform = Util.MatrixMultiply(cameraTransform, worldTransform);
for (var i = 0; i < 8; i++)
{
var vec = new float[] { bounds[CornerXIndex[i]], bounds[CornerYIndex[i]], bounds[CornerZIndex[i]], 1 };
var screen = OpenRA.Graphics.Util.MatrixVectorMultiply(screenTransform, vec);
var screen = Util.MatrixVectorMultiply(screenTransform, vec);
minX = Math.Min(minX, pxPos.X + screen[0]);
minY = Math.Min(minY, pxPos.Y + screen[1]);
minZ = Math.Min(minZ, pxPos.Z + screen[2]);

View File

@@ -74,8 +74,8 @@ namespace OpenRA.Mods.Cnc.Graphics
t[14] *= l.Scale * (l.Bounds[5] - l.Bounds[2]) / l.Size[2];
// Center, flip and scale
t = OpenRA.Graphics.Util.MatrixMultiply(t, OpenRA.Graphics.Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2]));
t = OpenRA.Graphics.Util.MatrixMultiply(OpenRA.Graphics.Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t);
t = Util.MatrixMultiply(t, Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2]));
t = Util.MatrixMultiply(Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t);
return t;
}
@@ -119,7 +119,7 @@ namespace OpenRA.Mods.Cnc.Graphics
};
// Calculate limb bounding box
var bb = OpenRA.Graphics.Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b);
var bb = Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b);
for (var i = 0; i < 3; i++)
{
ret[i] = Math.Min(ret[i], bb[i]);

View File

@@ -14,7 +14,7 @@ using OpenRA.Mods.Cnc.Traits;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.CnC.Scripting
namespace OpenRA.Mods.Cnc.Scripting
{
[ScriptPropertyGroup("Support Powers")]
public class IonCannonProperties : ScriptActorProperties, Requires<IonCannonPowerInfo>

View File

@@ -13,15 +13,18 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Graphics;
using OpenRA.Mods.Common;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render
namespace OpenRA.Mods.Cnc.Traits.Render
{
public interface IRenderActorPreviewVoxelsInfo : ITraitInfoInterface
{
IEnumerable<ModelAnimation> RenderPreviewVoxels(
IEnumerable<ModelAnimation> RenderPreviewVoxels(IModelCache cache,
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p);
}
@@ -56,6 +59,8 @@ namespace OpenRA.Mods.Common.Traits.Render
public virtual IEnumerable<IActorPreview> RenderPreview(ActorPreviewInitializer init)
{
var renderer = init.World.WorldActor.Trait<ModelRenderer>();
var cache = init.World.WorldActor.Trait<IModelCache>();
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var faction = init.GetValue<FactionInit, string>(this);
var ownerName = init.Get<OwnerInit>().InternalName;
@@ -67,10 +72,10 @@ namespace OpenRA.Mods.Common.Traits.Render
var palette = init.WorldRenderer.Palette(Palette ?? PlayerPalette + ownerName);
var components = init.Actor.TraitInfos<IRenderActorPreviewVoxelsInfo>()
.SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, init.GetOrientation(), facings, palette))
.SelectMany(rvpi => rvpi.RenderPreviewVoxels(cache, init, this, image, init.GetOrientation(), facings, palette))
.ToArray();
yield return new ModelPreview(components, WVec.Zero, 0, Scale, LightPitch,
yield return new ModelPreview(renderer, components, WVec.Zero, 0, Scale, LightPitch,
LightYaw, LightAmbientColor, LightDiffuseColor, body.CameraPitch,
palette, init.WorldRenderer.Palette(NormalsPalette), init.WorldRenderer.Palette(ShadowPalette));
}
@@ -104,6 +109,7 @@ namespace OpenRA.Mods.Common.Traits.Render
}
public readonly RenderVoxelsInfo Info;
public readonly ModelRenderer Renderer;
readonly List<ModelAnimation> components = new();
readonly Dictionary<ModelAnimation, AnimationWrapper> wrappers = new();
@@ -116,6 +122,7 @@ namespace OpenRA.Mods.Common.Traits.Render
public RenderVoxels(Actor self, RenderVoxelsInfo info)
{
this.self = self;
Renderer = self.World.WorldActor.Trait<ModelRenderer>();
Info = info;
body = self.Trait<BodyOrientation>();
camera = new WRot(WAngle.Zero, body.CameraPitch - new WAngle(256), new WAngle(256));
@@ -150,7 +157,7 @@ namespace OpenRA.Mods.Common.Traits.Render
return new IRenderable[]
{
new ModelRenderable(
components, self.CenterPosition, 0, camera, Info.Scale,
Renderer, components, self.CenterPosition, 0, camera, Info.Scale,
lightSource, Info.LightAmbientColor, Info.LightDiffuseColor,
colorPalette, normalsPalette, shadowPalette)
};

View File

@@ -14,9 +14,10 @@ using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render
namespace OpenRA.Mods.Cnc.Traits.Render
{
public class WithVoxelBarrelInfo : ConditionalTraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>, Requires<ArmamentInfo>, Requires<TurretedInfo>
{
@@ -37,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelBarrel(init.Self, this); }
public IEnumerable<ModelAnimation> RenderPreviewVoxels(
public IEnumerable<ModelAnimation> RenderPreviewVoxels(IModelCache cache,
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
if (!EnabledByDefault)
@@ -49,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == armament.Turret);
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var model = cache.GetModelSequence(image, Sequence);
var turretOrientation = t.PreviewOrientation(init, orientation, facings);
WVec BarrelOffset() => body.LocalToWorld(t.Offset + LocalOffset.Rotate(turretOrientation()));
@@ -77,7 +78,7 @@ namespace OpenRA.Mods.Common.Traits.Render
.First(tt => tt.Name == armament.Info.Turret);
var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
rv.Add(new ModelAnimation(rv.Renderer.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
BarrelOffset, BarrelRotation,
() => IsTraitDisabled, () => 0, info.ShowShadow));
}

View File

@@ -13,10 +13,11 @@ using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render
namespace OpenRA.Mods.Cnc.Traits.Render
{
[Desc("Also returns a default selection size that is calculated automatically from the voxel dimensions.")]
public class WithVoxelBodyInfo : ConditionalTraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>
@@ -29,11 +30,11 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelBody(init.Self, this); }
public IEnumerable<ModelAnimation> RenderPreviewVoxels(
public IEnumerable<ModelAnimation> RenderPreviewVoxels(IModelCache cache,
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var model = cache.GetModelSequence(image, Sequence);
yield return new ModelAnimation(model, () => Offset,
() => body.QuantizeOrientation(orientation(), facings),
() => false, () => 0, ShowShadow);
@@ -51,7 +52,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var body = self.Trait<BodyOrientation>();
rv = self.Trait<RenderVoxels>();
var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence);
var model = rv.Renderer.ModelCache.GetModelSequence(rv.Image, info.Sequence);
modelAnimation = new ModelAnimation(model, () => info.Offset,
() => body.QuantizeOrientation(self.Orientation),
() => IsTraitDisabled, () => 0, info.ShowShadow);

View File

@@ -14,9 +14,10 @@ using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render
namespace OpenRA.Mods.Cnc.Traits.Render
{
public class WithVoxelTurretInfo : ConditionalTraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>, Requires<TurretedInfo>
{
@@ -31,7 +32,7 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelTurret(init.Self, this); }
public IEnumerable<ModelAnimation> RenderPreviewVoxels(
public IEnumerable<ModelAnimation> RenderPreviewVoxels(IModelCache cache,
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
if (!EnabledByDefault)
@@ -40,7 +41,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var model = cache.GetModelSequence(image, Sequence);
var turretOffset = t.PreviewPosition(init, orientation);
var turretOrientation = t.PreviewOrientation(init, orientation, facings);
yield return new ModelAnimation(model, turretOffset, turretOrientation, () => false, () => 0, ShowShadow);
@@ -58,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits.Render
.First(tt => tt.Name == Info.Turret);
var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
rv.Add(new ModelAnimation(rv.Renderer.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
() => turreted.Position(self), () => turreted.WorldOrientation,
() => IsTraitDisabled, () => 0, info.ShowShadow));
}

View File

@@ -14,7 +14,6 @@ using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -34,11 +33,11 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelUnloadBody(init.Self, this); }
public IEnumerable<ModelAnimation> RenderPreviewVoxels(
public IEnumerable<ModelAnimation> RenderPreviewVoxels(IModelCache cache,
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var model = init.World.ModelCache.GetModelSequence(image, IdleSequence);
var model = cache.GetModelSequence(image, IdleSequence);
yield return new ModelAnimation(model, () => WVec.Zero,
() => body.QuantizeOrientation(orientation(), facings),
() => false, () => 0, ShowShadow);
@@ -57,7 +56,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
var body = self.Trait<BodyOrientation>();
rv = self.Trait<RenderVoxels>();
var idleModel = self.World.ModelCache.GetModelSequence(rv.Image, info.IdleSequence);
var idleModel = rv.Renderer.ModelCache.GetModelSequence(rv.Image, info.IdleSequence);
modelAnimation = new ModelAnimation(idleModel, () => WVec.Zero,
() => body.QuantizeOrientation(self.Orientation),
() => docked,
@@ -65,7 +64,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
rv.Add(modelAnimation);
var unloadModel = self.World.ModelCache.GetModelSequence(rv.Image, info.UnloadSequence);
var unloadModel = rv.Renderer.ModelCache.GetModelSequence(rv.Image, info.UnloadSequence);
rv.Add(new ModelAnimation(unloadModel, () => WVec.Zero,
() => body.QuantizeOrientation(self.Orientation),
() => !docked,

View File

@@ -14,7 +14,6 @@ using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -31,10 +30,10 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public readonly bool ShowShadow = true;
public override object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.Self, this); }
public IEnumerable<ModelAnimation> RenderPreviewVoxels(
public IEnumerable<ModelAnimation> RenderPreviewVoxels(IModelCache cache,
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var model = cache.GetModelSequence(image, Sequence);
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var frame = init.GetValue<BodyAnimationFrameInit, uint>(this, 0);
@@ -61,7 +60,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
var body = self.Trait<BodyOrientation>();
rv = self.Trait<RenderVoxels>();
var model = self.World.ModelCache.GetModelSequence(rv.Image, info.Sequence);
var model = rv.Renderer.ModelCache.GetModelSequence(rv.Image, info.Sequence);
frames = model.Frames;
modelAnimation = new ModelAnimation(model, () => WVec.Zero,
() => body.QuantizeOrientation(self.Orientation),

View File

@@ -12,9 +12,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Graphics
namespace OpenRA.Mods.Cnc.Traits
{
public class ModelRenderProxy
{
@@ -32,7 +34,14 @@ namespace OpenRA.Graphics
}
}
public sealed class ModelRenderer : IDisposable
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
[Desc("Render voxels")]
public class ModelRendererInfo : TraitInfo, Requires<IModelCacheInfo>
{
public override object Create(ActorInitializer init) { return new ModelRenderer(this, init.Self); }
}
public sealed class ModelRenderer : IDisposable, IRenderer, INotifyActorDisposing
{
// Static constants
static readonly float[] ShadowDiffuse = new float[] { 0, 0, 0 };
@@ -46,28 +55,31 @@ namespace OpenRA.Graphics
readonly Renderer renderer;
readonly IShader shader;
public readonly IModelCache ModelCache;
readonly Dictionary<Sheet, IFrameBuffer> mappedBuffers = new();
readonly Stack<KeyValuePair<Sheet, IFrameBuffer>> unmappedBuffers = new();
readonly List<(Sheet Sheet, Action Func)> doRender = new();
readonly int sheetSize;
SheetBuilder sheetBuilderForFrame;
bool isInFrame;
public ModelRenderer(Renderer renderer, IShader shader)
{
this.renderer = renderer;
this.shader = shader;
}
public void SetPalette(ITexture palette)
{
shader.SetTexture("Palette", palette);
}
public void SetViewportParams()
public ModelRenderer(ModelRendererInfo info, Actor self)
{
var a = 2f / renderer.SheetSize;
renderer = Game.Renderer;
shader = renderer.CreateShader(new ModelShaderBindings());
renderer.WorldRenderers = renderer.WorldRenderers.Append(this).ToArray();
ModelCache = self.Trait<IModelCache>();
sheetSize = Game.Settings.Graphics.SheetSize;
var a = 2f / sheetSize;
var view = new[]
{
a, 0, 0, 0,
@@ -176,8 +188,8 @@ namespace OpenRA.Graphics
var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2);
var shadowCenter = new float2(ssb.Left + ssb.Width / 2, ssb.Top + ssb.Height / 2);
var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0);
var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0);
var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, sheetSize - (spriteCenter.Y - spriteOffset.Y), 0);
var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, sheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0);
var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx);
var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx);
@@ -213,12 +225,12 @@ namespace OpenRA.Graphics
// Transform light vector from shadow -> world -> limb coords
var lightDirection = ExtractRotationVector(Util.MatrixMultiply(it, lightTransform));
Render(rd, wr.World.ModelCache, Util.MatrixMultiply(transform, t), lightDirection,
Render(rd, ModelCache, Util.MatrixMultiply(transform, t), lightDirection,
lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex);
// Disable shadow normals by forcing zero diffuse and identity ambient light
if (m.ShowShadow)
Render(rd, wr.World.ModelCache, Util.MatrixMultiply(shadow, t), lightDirection,
Render(rd, ModelCache, Util.MatrixMultiply(shadow, t), lightDirection,
ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex);
}
}
@@ -298,14 +310,14 @@ namespace OpenRA.Graphics
Game.Renderer.Flush();
fbo.Bind();
Game.Renderer.Context.EnableDepthBuffer();
Game.Renderer.EnableDepthBuffer();
return fbo;
}
static void DisableFrameBuffer(IFrameBuffer fbo)
{
Game.Renderer.Flush();
Game.Renderer.Context.DisableDepthBuffer();
Game.Renderer.DisableDepthBuffer();
fbo.Unbind();
}
@@ -353,8 +365,7 @@ namespace OpenRA.Graphics
return kv.Key;
}
var size = new Size(renderer.SheetSize, renderer.SheetSize);
var framebuffer = renderer.Context.CreateFrameBuffer(size);
var framebuffer = renderer.CreateFrameBuffer(new Size(sheetSize, sheetSize));
var sheet = new Sheet(SheetType.BGRA, framebuffer.Texture);
mappedBuffers.Add(sheet, framebuffer);
@@ -371,6 +382,12 @@ namespace OpenRA.Graphics
mappedBuffers.Clear();
unmappedBuffers.Clear();
renderer.WorldRenderers = renderer.WorldRenderers.Where(r => r != this).ToArray();
}
void INotifyActorDisposing.Disposing(Actor a)
{
Dispose();
}
}
}

View File

@@ -12,50 +12,45 @@
using System;
using System.Collections.Generic;
using System.IO;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Graphics
namespace OpenRA.Mods.Cnc.Traits
{
public class VoxelModelSequenceLoader : IModelSequenceLoader
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
[Desc("Loads voxel models.")]
public sealed class VoxelCacheInfo : TraitInfo, IModelCacheInfo
{
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 override object Create(ActorInitializer init) { return new VoxelCache(this, init.Self); }
}
public sealed class VoxelModelCache : IModelCache
public sealed class VoxelCache : IModelCache, INotifyActorDisposing, IDisposable
{
readonly VoxelLoader loader;
readonly Dictionary<string, Dictionary<string, IModel>> models = new();
public VoxelModelCache(IReadOnlyFileSystem fileSystem)
public VoxelCache(VoxelCacheInfo info, Actor self)
{
loader = new VoxelLoader(fileSystem);
var map = self.World.Map;
loader = new VoxelLoader(map);
foreach (var kv in map.Rules.ModelSequences)
{
Game.ModData.LoadScreen.Display();
try
{
CacheModel(kv.Key, kv.Value.Value);
}
catch (FileNotFoundException ex)
{
// Eat the FileNotFound exceptions from missing sprites.
Console.WriteLine(ex);
Log.Write("debug", ex.Message);
}
}
loader.RefreshBuffer();
loader.Finish();
}
public void CacheModel(string model, MiniYaml definition)
@@ -63,12 +58,6 @@ namespace OpenRA.Mods.Cnc.Graphics
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;
@@ -120,5 +109,10 @@ namespace OpenRA.Mods.Cnc.Graphics
{
loader.Dispose();
}
void INotifyActorDisposing.Disposing(Actor a)
{
Dispose();
}
}
}

View File

@@ -9,6 +9,8 @@
*/
#endregion
using System;
namespace OpenRA.Mods.Cnc
{
public static class Util
@@ -65,5 +67,249 @@ namespace OpenRA.Mods.Cnc
return Common.Util.QuantizeFacing(facing, steps);
}
public static float[] IdentityMatrix()
{
return new float[]
{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
}
public static float[] ScaleMatrix(float sx, float sy, float sz)
{
return new float[]
{
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
0, 0, 0, 1,
};
}
public static float[] TranslationMatrix(float x, float y, float z)
{
return new float[]
{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1,
};
}
public static float[] MatrixMultiply(float[] lhs, float[] rhs)
{
var mtx = new float[16];
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
{
mtx[4 * i + j] = 0;
for (var k = 0; k < 4; k++)
mtx[4 * i + j] += lhs[4 * k + j] * rhs[4 * i + k];
}
return mtx;
}
public static float[] MatrixVectorMultiply(float[] mtx, float[] vec)
{
var ret = new float[4];
for (var j = 0; j < 4; j++)
{
ret[j] = 0;
for (var k = 0; k < 4; k++)
ret[j] += mtx[4 * k + j] * vec[k];
}
return ret;
}
public static float[] MatrixInverse(float[] m)
{
var mtx = new float[16];
mtx[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
mtx[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
mtx[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
mtx[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
mtx[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
mtx[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
mtx[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
mtx[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
mtx[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
mtx[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
mtx[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
mtx[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
mtx[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
mtx[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
mtx[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
mtx[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
var det = m[0] * mtx[0] + m[1] * mtx[4] + m[2] * mtx[8] + m[3] * mtx[12];
if (det == 0)
return null;
for (var i = 0; i < 16; i++)
mtx[i] *= 1 / det;
return mtx;
}
public static float[] MakeFloatMatrix(Int32Matrix4x4 imtx)
{
var multipler = 1f / imtx.M44;
return new[]
{
imtx.M11 * multipler,
imtx.M12 * multipler,
imtx.M13 * multipler,
imtx.M14 * multipler,
imtx.M21 * multipler,
imtx.M22 * multipler,
imtx.M23 * multipler,
imtx.M24 * multipler,
imtx.M31 * multipler,
imtx.M32 * multipler,
imtx.M33 * multipler,
imtx.M34 * multipler,
imtx.M41 * multipler,
imtx.M42 * multipler,
imtx.M43 * multipler,
imtx.M44 * multipler,
};
}
public static float[] MatrixAABBMultiply(float[] mtx, float[] bounds)
{
// Corner offsets.
var ix = new uint[] { 0, 0, 0, 0, 3, 3, 3, 3 };
var iy = new uint[] { 1, 1, 4, 4, 1, 1, 4, 4 };
var iz = new uint[] { 2, 5, 2, 5, 2, 5, 2, 5 };
// Vectors to opposing corner.
var ret = new[]
{
float.MaxValue, float.MaxValue, float.MaxValue,
float.MinValue, float.MinValue, float.MinValue
};
// Transform vectors and find new bounding box.
for (var i = 0; i < 8; i++)
{
var vec = new[] { bounds[ix[i]], bounds[iy[i]], bounds[iz[i]], 1 };
var tvec = MatrixVectorMultiply(mtx, vec);
ret[0] = Math.Min(ret[0], tvec[0] / tvec[3]);
ret[1] = Math.Min(ret[1], tvec[1] / tvec[3]);
ret[2] = Math.Min(ret[2], tvec[2] / tvec[3]);
ret[3] = Math.Max(ret[3], tvec[0] / tvec[3]);
ret[4] = Math.Max(ret[4], tvec[1] / tvec[3]);
ret[5] = Math.Max(ret[5], tvec[2] / tvec[3]);
}
return ret;
}
}
}

View File

@@ -11,12 +11,13 @@
using System;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Cnc.Graphics;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
namespace OpenRA.Mods.Cnc.Widgets
{
public class ModelWidget : Widget
public class ModelWidget : Widget, IModelWidget
{
public string Palette = "terrain";
public string PlayerPalette = "player";
@@ -75,6 +76,20 @@ namespace OpenRA.Mods.Common.Widgets
WorldRenderer = other.WorldRenderer;
}
string IModelWidget.Palette => GetPalette();
float IModelWidget.Scale => GetScale();
void IModelWidget.Setup(Func<bool> isVisible, Func<string> getPalette, Func<string> getPlayerPalette,
Func<float> getScale, Func<IModel> getVoxel, Func<WRot> getRotation)
{
IsVisible = isVisible;
GetPalette = getPalette;
GetPlayerPalette = getPlayerPalette;
GetScale = getScale;
GetVoxel = getVoxel;
GetRotation = getRotation;
}
public override Widget Clone()
{
return new ModelWidget(this);
@@ -188,7 +203,10 @@ namespace OpenRA.Mods.Common.Widgets
var animations = new ModelAnimation[] { animation };
var renderer = WorldRenderer.World.WorldActor.Trait<ModelRenderer>();
var preview = new ModelPreview(
renderer,
new ModelAnimation[] { animation }, WVec.Zero, 0,
cachedScale,
new WAngle(cachedLightPitch),
@@ -206,6 +224,7 @@ namespace OpenRA.Mods.Common.Widgets
var camera = new WRot(WAngle.Zero, cachedCameraAngle - new WAngle(256), new WAngle(256));
var modelRenderable = new UIModelRenderable(
renderer,
animations, WPos.Zero, origin, 0, camera, scale,
WRot.None, cachedLightAmbientColor, cachedLightDiffuseColor,
paletteReferencePlayer, paletteReferenceNormals, paletteReferenceShadow);

View File

@@ -151,17 +151,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (playerWidget != null)
playerWidget.IsVisible = () => isVideoLoaded && !isLoadError;
var modelWidget = panel.GetOrNull<ModelWidget>("VOXEL");
if (modelWidget != null)
if (panel.GetOrNull<Widget>("VOXEL") is IModelWidget modelWidget)
{
modelWidget.GetVoxel = () => currentVoxel;
currentPalette = modelWidget.Palette;
modelScale = modelWidget.Scale;
modelWidget.GetPalette = () => currentPalette;
modelWidget.GetPlayerPalette = () => currentPalette;
modelWidget.GetRotation = () => modelOrientation;
modelWidget.IsVisible = () => !isVideoLoaded && !isLoadError && currentVoxel != null;
modelWidget.GetScale = () => modelScale;
modelWidget.Setup(
() => !isVideoLoaded && !isLoadError && currentVoxel != null,
() => currentPalette,
() => currentPalette,
() => modelScale,
() => currentVoxel,
() => modelOrientation);
}
var errorLabelWidget = panel.GetOrNull("ERROR");
@@ -530,7 +530,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
else if (allowedModelExtensions.Contains(fileExtension))
{
var voxelName = Path.GetFileNameWithoutExtension(filename);
currentVoxel = world.ModelCache.GetModel(prefix + voxelName);
currentVoxel = world.WorldActor.Trait<IModelCache>().GetModel(prefix + voxelName);
currentSprites = null;
}
else if (allowedAudioExtensions.Contains(fileExtension))

View File

@@ -33,7 +33,5 @@ TerrainFormat: DefaultTerrain
SpriteSequenceFormat: DefaultSpriteSequence
ModelSequenceFormat: PlaceholderModelSequence
DiscordService:
ApplicationId: 699222659766026240

View File

@@ -240,8 +240,6 @@ TerrainFormat: DefaultTerrain
SpriteSequenceFormat: ClassicTilesetSpecificSpriteSequence
ModelSequenceFormat: PlaceholderModelSequence
AssetBrowser:
SpriteExtensions: .shp, .tem, .win, .sno, .des, .jun
AudioExtensions: .aud, .wav, .v00, .v01, .v02, .v03, .var

View File

@@ -222,8 +222,6 @@ TerrainFormat: DefaultTerrain
SpriteSequenceFormat: DefaultSpriteSequence
ModelSequenceFormat: PlaceholderModelSequence
AssetBrowser:
SpriteExtensions: .shp, .r8, .tmp
AudioExtensions: .aud, .wav

View File

@@ -71,5 +71,3 @@ SpriteFormats: PngSheet
TerrainFormat: DefaultTerrain
SpriteSequenceFormat: DefaultSpriteSequence
ModelSequenceFormat: PlaceholderModelSequence

View File

@@ -243,8 +243,6 @@ TerrainFormat: DefaultTerrain
SpriteSequenceFormat: ClassicTilesetSpecificSpriteSequence
ModelSequenceFormat: PlaceholderModelSequence
AssetBrowser:
SpriteExtensions: .shp, .tmp, .tem, .des, .sno, .int
AudioExtensions: .aud, .wav, .r00, .r01, .r02, .r03, .v00, .v01, .v02, .v03

View File

@@ -273,8 +273,6 @@ TerrainFormat: DefaultTerrain
SpriteSequenceFormat: TilesetSpecificSpriteSequence
ModelSequenceFormat: VoxelModelSequence
AssetBrowser:
SpriteExtensions: .shp, .tem, .sno
ModelExtensions: .vxl

View File

@@ -8,6 +8,8 @@
MusicPlaylist:
VictoryMusic: score
DefeatMusic: fsmap
VoxelCache:
ModelRenderer:
TerrainRenderer:
TerrainLighting:
ShroudRenderer: