Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
161
OpenRA.Mods.Cnc/Graphics/Voxel.cs
Normal file
161
OpenRA.Mods.Cnc/Graphics/Voxel.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* 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.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Cnc.FileFormats;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.Graphics
|
||||
{
|
||||
struct Limb
|
||||
{
|
||||
public float Scale;
|
||||
public float[] Bounds;
|
||||
public byte[] Size;
|
||||
public ModelRenderData RenderData;
|
||||
}
|
||||
|
||||
public class Voxel : IModel
|
||||
{
|
||||
readonly Limb[] limbData;
|
||||
readonly float[] transforms;
|
||||
readonly uint frames;
|
||||
readonly uint limbs;
|
||||
|
||||
uint IModel.Frames => frames;
|
||||
uint IModel.Sections => limbs;
|
||||
|
||||
public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva, (string Vxl, string Hva) files)
|
||||
{
|
||||
if (vxl.LimbCount != hva.LimbCount)
|
||||
throw new InvalidOperationException($"{files.Vxl}.vxl and {files.Hva}.hva limb counts don't match.");
|
||||
|
||||
transforms = hva.Transforms;
|
||||
frames = hva.FrameCount;
|
||||
limbs = hva.LimbCount;
|
||||
|
||||
limbData = new Limb[vxl.LimbCount];
|
||||
for (var i = 0; i < vxl.LimbCount; i++)
|
||||
{
|
||||
var vl = vxl.Limbs[i];
|
||||
var l = default(Limb);
|
||||
l.Scale = vl.Scale;
|
||||
l.Bounds = (float[])vl.Bounds.Clone();
|
||||
l.Size = (byte[])vl.Size.Clone();
|
||||
l.RenderData = loader.GenerateRenderData(vxl.Limbs[i]);
|
||||
limbData[i] = l;
|
||||
}
|
||||
}
|
||||
|
||||
public float[] TransformationMatrix(uint limb, uint frame)
|
||||
{
|
||||
if (frame >= frames)
|
||||
throw new ArgumentOutOfRangeException(nameof(frame), $"Only {frames} frames exist.");
|
||||
if (limb >= limbs)
|
||||
throw new ArgumentOutOfRangeException(nameof(limb), $"Only {limbs} limbs exist.");
|
||||
|
||||
var l = limbData[limb];
|
||||
var t = new float[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];
|
||||
t[13] *= l.Scale * (l.Bounds[4] - l.Bounds[1]) / l.Size[1];
|
||||
t[14] *= l.Scale * (l.Bounds[5] - l.Bounds[2]) / l.Size[2];
|
||||
|
||||
// Center, flip and scale
|
||||
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;
|
||||
}
|
||||
|
||||
public ModelRenderData RenderData(uint limb)
|
||||
{
|
||||
return limbData[limb].RenderData;
|
||||
}
|
||||
|
||||
public float[] Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return limbData.Select(a => a.Size.Select(b => a.Scale * b).ToArray())
|
||||
.Aggregate((a, b) =>
|
||||
[
|
||||
Math.Max(a[0], b[0]),
|
||||
Math.Max(a[1], b[1]),
|
||||
Math.Max(a[2], b[2])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public float[] Bounds(uint frame)
|
||||
{
|
||||
var ret = new[]
|
||||
{
|
||||
float.MaxValue, float.MaxValue, float.MaxValue,
|
||||
float.MinValue, float.MinValue, float.MinValue
|
||||
};
|
||||
|
||||
for (uint j = 0; j < limbs; j++)
|
||||
{
|
||||
var l = limbData[j];
|
||||
var b = new[]
|
||||
{
|
||||
0, 0, 0,
|
||||
l.Bounds[3] - l.Bounds[0],
|
||||
l.Bounds[4] - l.Bounds[1],
|
||||
l.Bounds[5] - l.Bounds[2]
|
||||
};
|
||||
|
||||
// Calculate limb bounding box
|
||||
var bb = Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b);
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
ret[i] = Math.Min(ret[i], bb[i]);
|
||||
ret[i + 3] = Math.Max(ret[i + 3], bb[i + 3]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Rectangle AggregateBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
// 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 };
|
||||
|
||||
// Calculate the smallest sphere that covers the model limbs
|
||||
var rSquared = 0f;
|
||||
for (var f = 0U; f < frames; f++)
|
||||
{
|
||||
var bounds = Bounds(f);
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var x = bounds[ix[i]];
|
||||
var y = bounds[iy[i]];
|
||||
var z = bounds[iz[i]];
|
||||
rSquared = Math.Max(rSquared, x * x + y * y + z * z);
|
||||
}
|
||||
}
|
||||
|
||||
var r = (int)Math.Sqrt(rSquared) + 1;
|
||||
return Rectangle.FromLTRB(-r, -r, r, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user