Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn ModelRenderer and VoxelCache into traits #21066

Merged
merged 1 commit into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions OpenRA.Game/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ static void RenderTick()
// 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)
Expand All @@ -674,7 +674,7 @@ static void RenderTick()
}

Ui.PrepareRenderables();
Renderer.WorldModelRenderer.EndFrame();
worldRenderer?.EndFrame();
}

// worldRenderer is null during the initial install/download screen
Expand Down
55 changes: 12 additions & 43 deletions OpenRA.Game/Graphics/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
#endregion

using System;
using System.Collections.Generic;
using OpenRA.FileSystem;
using OpenRA.Primitives;
using OpenRA.Traits;

namespace OpenRA.Graphics
{
Expand All @@ -30,6 +29,14 @@ public interface IModel
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;
Expand All @@ -44,51 +51,13 @@ public ModelRenderData(int start, int count, Sheet sheet)
}
}

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();
}
}
}
7 changes: 7 additions & 0 deletions OpenRA.Game/Graphics/PlatformInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ public interface IGraphicsContext : IDisposable
string GLVersion { get; }
}

public interface IRenderer
{
void BeginFrame();
void EndFrame();
void SetPalette(ITexture palette);
}

public interface IVertexBuffer<T> : IDisposable where T : struct
{
void Bind();
Expand Down
244 changes: 0 additions & 244 deletions OpenRA.Game/Graphics/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -313,249 +313,5 @@ public static Color PremultipliedColorLerp(float t, Color c1, Color c2)
(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;
}
}
}
14 changes: 14 additions & 0 deletions OpenRA.Game/Graphics/WorldRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public sealed class WorldRenderer : IDisposable
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new();

readonly List<IRenderable> renderablesBuffer = new();
readonly IRenderer[] renderers;

internal WorldRenderer(ModData modData, World world)
{
Expand All @@ -66,11 +67,24 @@ internal WorldRenderer(ModData modData, World world)
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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions that come to mind.

Renderers would be independant of each other? No cross refences or shared state? Would some IRenderables references multiple renderers?

I see you pass the renderable when creating the IRenderable.

So this would mean the renderes could be active/called in any order.

This only ensures the order in which begin and end frame is called.

Might be an option to put MapEditor DebugRenderables in seperate renderer. But may not have much added value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will get much more polished once we turn SpriteRenderers into a trait. This current solution is as minimal as possible

}

public void UpdatePalettesForPlayer(string internalName, Color color, bool replaceExisting)
{
foreach (var pal in World.WorldActor.TraitsImplementing<ILoadsPlayerPalettes>())
Expand Down