Compare commits
7 Commits
db01667fb2
...
65dda0194d
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 65dda0194d | |
Jarrod Doyle | 010757eb6f | |
Jarrod Doyle | bf47578133 | |
Jarrod Doyle | 0f9467b8c4 | |
Jarrod Doyle | a8bdf37097 | |
Jarrod Doyle | 9c71529d8e | |
Jarrod Doyle | e3aac88c17 |
|
@ -240,9 +240,11 @@ public class WorldRep : IChunk
|
|||
return bytes;
|
||||
}
|
||||
|
||||
// TODO: This ONLY works for rgba (bpp = 4)!!!
|
||||
public void AddLight(int layer, int x, int y, float r, float g, float b)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(layer, 0, nameof(layer));
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan(layer, Layers, nameof(layer));
|
||||
|
||||
var idx = (x + y * Width) * Bpp;
|
||||
var pLayer = Pixels[layer];
|
||||
switch (Bpp)
|
||||
|
|
|
@ -166,6 +166,7 @@ public class DbFile
|
|||
"P$AnimLight" => new PropertyChunk<PropAnimLight>(),
|
||||
"P$LightColo" => new PropertyChunk<PropLightColor>(),
|
||||
"P$Spotlight" => new PropertyChunk<PropSpotlight>(),
|
||||
"P$SpotAmb" => new PropertyChunk<PropSpotlightAndAmbient>(),
|
||||
"P$RenderAlp" => new PropertyChunk<PropFloat>(),
|
||||
"LD$MetaProp" => new LinkDataMetaProp(),
|
||||
_ when entryName.StartsWith("L$") => new LinkChunk(),
|
||||
|
|
|
@ -103,6 +103,7 @@ public class ObjectHierarchy
|
|||
AddProp<PropAnimLight>("P$AnimLight");
|
||||
AddProp<PropLightColor>("P$LightColo");
|
||||
AddProp<PropSpotlight>("P$Spotlight");
|
||||
AddProp<PropSpotlightAndAmbient>("P$SpotAmb");
|
||||
}
|
||||
|
||||
// TODO: Work out if there's some nice way to automatically decide if we inherit
|
||||
|
|
|
@ -288,6 +288,73 @@ public class ModelFile
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Apply transforms to normals and stuff
|
||||
public void ApplyJoints(float[] joints)
|
||||
{
|
||||
// Build map of objects to their parent id
|
||||
var objCount = Objects.Length;
|
||||
var parentIds = new int[objCount];
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
parentIds[i] = -1;
|
||||
}
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = Objects[i];
|
||||
var childIdx = subObj.Child;
|
||||
while (childIdx != -1)
|
||||
{
|
||||
parentIds[childIdx] = i;
|
||||
childIdx = Objects[childIdx].Next;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate base transforms for every subobj (including joint)
|
||||
var subObjTransforms = new Matrix4x4[objCount];
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = Objects[i];
|
||||
var objTrans = Matrix4x4.Identity;
|
||||
if (subObj.Joint != -1)
|
||||
{
|
||||
var ang = float.DegreesToRadians(joints[subObj.Joint]);
|
||||
// TODO: Is this correct? Should I use a manual rotation matrix?
|
||||
var jointRot = Matrix4x4.CreateFromYawPitchRoll(0, ang, 0);
|
||||
objTrans = jointRot * subObj.Transform;
|
||||
}
|
||||
|
||||
subObjTransforms[i] = objTrans;
|
||||
}
|
||||
|
||||
// Apply sub object transforms
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = Objects[i];
|
||||
var transform = subObjTransforms[i];
|
||||
|
||||
// Build compound transformation
|
||||
var parentId = parentIds[i];
|
||||
while (parentId != -1)
|
||||
{
|
||||
transform *= subObjTransforms[parentId];
|
||||
parentId = parentIds[parentId];
|
||||
}
|
||||
|
||||
for (var j = 0; j < subObj.VhotCount; j++)
|
||||
{
|
||||
var v = VHots[subObj.VhotIdx + j];
|
||||
v.Position = Vector3.Transform(v.Position, transform);
|
||||
VHots[subObj.VhotIdx + j] = v;
|
||||
}
|
||||
|
||||
for (var j = 0; j < subObj.PointCount; j++)
|
||||
{
|
||||
var v = Vertices[subObj.PointIdx + j];
|
||||
Vertices[subObj.PointIdx + j] = Vector3.Transform(v, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetVhot(VhotId id, out VHot vhot)
|
||||
{
|
||||
foreach (var v in VHots)
|
||||
|
|
|
@ -35,6 +35,30 @@ public class Light
|
|||
};
|
||||
}
|
||||
|
||||
public void FixRadius()
|
||||
{
|
||||
if (Radius == 0)
|
||||
{
|
||||
Radius = float.MaxValue;
|
||||
R2 = float.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyTransforms(
|
||||
Vector3 vhotLightPos,
|
||||
Vector3 vhotLightDir,
|
||||
Matrix4x4 translate,
|
||||
Matrix4x4 rotate,
|
||||
Matrix4x4 scale)
|
||||
{
|
||||
var transform = scale * rotate * translate;
|
||||
vhotLightPos = Vector3.Transform(vhotLightPos, transform);
|
||||
vhotLightDir = Vector3.Transform(vhotLightDir, transform);
|
||||
|
||||
Position = Vector3.Transform(Position, rotate) + vhotLightPos;
|
||||
SpotlightDir = Vector3.Normalize(vhotLightDir - vhotLightPos);
|
||||
}
|
||||
|
||||
public float StrengthAtPoint(Vector3 point, Plane plane)
|
||||
{
|
||||
// Calculate light strength at a given point. As far as I can tell
|
||||
|
|
|
@ -202,10 +202,12 @@ public class LightMapper
|
|||
return;
|
||||
}
|
||||
|
||||
var brightness = Math.Min(sz.X, 255.0f);
|
||||
var light = new Light
|
||||
{
|
||||
Position = brush.position,
|
||||
Color = Utils.HsbToRgb(sz.Y, sz.Z, Math.Min(sz.X, 255.0f)),
|
||||
Color = Utils.HsbToRgb(sz.Y, sz.Z, brightness),
|
||||
Brightness = brightness,
|
||||
Radius = float.MaxValue,
|
||||
R2 = float.MaxValue,
|
||||
LightTableIndex = lightTable.LightCount,
|
||||
|
@ -219,79 +221,46 @@ public class LightMapper
|
|||
{
|
||||
// TODO: Handle PropSpotlightAndAmbient
|
||||
var id = (int)brush.brushInfo;
|
||||
var propScale = _hierarchy.GetProperty<PropVector>(id, "P$Scale");
|
||||
var propAnimLight = _hierarchy.GetProperty<PropAnimLight>(id, "P$AnimLight", false);
|
||||
var propLight = _hierarchy.GetProperty<PropLight>(id, "P$Light", false);
|
||||
var propLightColor = _hierarchy.GetProperty<PropLightColor>(id, "P$LightColo");
|
||||
var propSpotlight = _hierarchy.GetProperty<PropSpotlight>(id, "P$Spotlight");
|
||||
var propSpotAmb = _hierarchy.GetProperty<PropSpotlightAndAmbient>(id, "P$SpotAmb");
|
||||
var propModelName = _hierarchy.GetProperty<PropLabel>(id, "P$ModelName");
|
||||
var propJointPos = _hierarchy.GetProperty<PropJointPos>(id, "P$JointPos");
|
||||
|
||||
propLightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
|
||||
var joints = propJointPos?.Positions ?? [0, 0, 0, 0, 0, 0];
|
||||
|
||||
// TODO: Also apply scale?
|
||||
var rot = Matrix4x4.Identity;
|
||||
rot *= Matrix4x4.CreateRotationX(float.DegreesToRadians(brush.angle.X));
|
||||
rot *= Matrix4x4.CreateRotationY(float.DegreesToRadians(brush.angle.Y));
|
||||
rot *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(brush.angle.Z));
|
||||
|
||||
var baseLight = new Light
|
||||
{
|
||||
Position = brush.position,
|
||||
SpotlightDir = Vector3.Transform(-Vector3.UnitZ, rot),
|
||||
SpotlightInnerAngle = -1.0f,
|
||||
};
|
||||
// Transform data
|
||||
var translate = Matrix4x4.CreateTranslation(brush.position);
|
||||
var rotate = Matrix4x4.Identity;
|
||||
rotate *= Matrix4x4.CreateRotationX(float.DegreesToRadians(brush.angle.X));
|
||||
rotate *= Matrix4x4.CreateRotationY(float.DegreesToRadians(brush.angle.Y));
|
||||
rotate *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(brush.angle.Z));
|
||||
var scale = Matrix4x4.CreateScale(propScale?.value ?? Vector3.One);
|
||||
|
||||
var vhotLightPos = Vector3.Zero;
|
||||
var vhotLightDir = -Vector3.UnitZ;
|
||||
if (propModelName != null)
|
||||
{
|
||||
var resName = $"{propModelName.value.ToLower()}.bin";
|
||||
var modelPath = _campaign.GetResourcePath(ResourceType.Object, resName);
|
||||
if (modelPath != null)
|
||||
{
|
||||
// TODO: Handle failing to find model more gracefully
|
||||
var model = new ModelFile(modelPath);
|
||||
model.ApplyJoints(joints);
|
||||
|
||||
if (model.TryGetVhot(ModelFile.VhotId.LightPosition, out var vhot))
|
||||
{
|
||||
baseLight.Position += Vector3.Transform(vhot.Position - model.Header.Center, rot);
|
||||
|
||||
vhotLightPos = vhot.Position - model.Header.Center;
|
||||
}
|
||||
if (model.TryGetVhot(ModelFile.VhotId.LightDirection, out vhot))
|
||||
{
|
||||
baseLight.SpotlightDir = Vector3.Transform(vhot.Position - model.Header.Center, rot);
|
||||
vhotLightDir = vhot.Position - model.Header.Center;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (propSpotlight != null)
|
||||
{
|
||||
baseLight.Spotlight = true;
|
||||
baseLight.SpotlightInnerAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.InnerAngle));
|
||||
baseLight.SpotlightOuterAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.OuterAngle));
|
||||
}
|
||||
|
||||
if (propLight != null && propLight.Brightness != 0f)
|
||||
{
|
||||
var light = new Light
|
||||
{
|
||||
Position = baseLight.Position + Vector3.Transform(propLight.Offset, rot),
|
||||
Color = Utils.HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness),
|
||||
InnerRadius = propLight.InnerRadius,
|
||||
Radius = propLight.Radius,
|
||||
R2 = propLight.Radius * propLight.Radius,
|
||||
QuadLit = propLight.QuadLit,
|
||||
Spotlight = baseLight.Spotlight,
|
||||
SpotlightDir = baseLight.SpotlightDir,
|
||||
SpotlightInnerAngle = baseLight.SpotlightInnerAngle,
|
||||
SpotlightOuterAngle = baseLight.SpotlightOuterAngle,
|
||||
LightTableIndex = lightTable.LightCount,
|
||||
};
|
||||
if (propLight.Radius == 0)
|
||||
{
|
||||
light.Radius = float.MaxValue;
|
||||
light.R2 = float.MaxValue;
|
||||
}
|
||||
|
||||
_lights.Add(light);
|
||||
lightTable.AddLight(light.ToLightData(32.0f));
|
||||
}
|
||||
|
||||
if (propAnimLight != null)
|
||||
|
@ -301,26 +270,82 @@ public class LightMapper
|
|||
|
||||
var light = new Light
|
||||
{
|
||||
Position = baseLight.Position + Vector3.Transform(propAnimLight.Offset, rot),
|
||||
Position = propAnimLight.Offset,
|
||||
Color = Utils.HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propAnimLight.MaxBrightness),
|
||||
Brightness = propAnimLight.Brightness,
|
||||
InnerRadius = propAnimLight.InnerRadius,
|
||||
Radius = propAnimLight.Radius,
|
||||
R2 = propAnimLight.Radius * propAnimLight.Radius,
|
||||
QuadLit = propAnimLight.QuadLit,
|
||||
Spotlight = baseLight.Spotlight,
|
||||
SpotlightDir = baseLight.SpotlightDir,
|
||||
SpotlightInnerAngle = baseLight.SpotlightInnerAngle,
|
||||
SpotlightOuterAngle = baseLight.SpotlightOuterAngle,
|
||||
Anim = true,
|
||||
ObjId = id,
|
||||
LightTableIndex = propAnimLight.LightTableLightIndex,
|
||||
Anim = true
|
||||
};
|
||||
if (propAnimLight.Radius == 0)
|
||||
|
||||
if (propSpotlight != null)
|
||||
{
|
||||
light.Radius = float.MaxValue;
|
||||
light.R2 = float.MaxValue;
|
||||
light.Spotlight = true;
|
||||
light.SpotlightInnerAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.InnerAngle));
|
||||
light.SpotlightOuterAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.OuterAngle));
|
||||
}
|
||||
|
||||
light.FixRadius();
|
||||
light.ApplyTransforms(vhotLightPos, vhotLightDir, translate, rotate, scale);
|
||||
|
||||
_lights.Add(light);
|
||||
lightTable.AddLight(light.ToLightData(32.0f));
|
||||
}
|
||||
|
||||
if (propLight != null)
|
||||
{
|
||||
var light = new Light
|
||||
{
|
||||
Position = propLight.Offset,
|
||||
Color = Utils.HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness),
|
||||
Brightness = propLight.Brightness,
|
||||
InnerRadius = propLight.InnerRadius,
|
||||
Radius = propLight.Radius,
|
||||
R2 = propLight.Radius * propLight.Radius,
|
||||
QuadLit = propLight.QuadLit,
|
||||
ObjId = id,
|
||||
LightTableIndex = lightTable.LightCount,
|
||||
};
|
||||
|
||||
if (propSpotAmb != null)
|
||||
{
|
||||
var spot = new Light
|
||||
{
|
||||
Position = light.Position,
|
||||
Color = Utils.HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propSpotAmb.SpotBrightness),
|
||||
InnerRadius = light.InnerRadius,
|
||||
Radius = light.Radius,
|
||||
R2 = light.R2,
|
||||
QuadLit = light.QuadLit,
|
||||
Spotlight = true,
|
||||
SpotlightInnerAngle = (float)Math.Cos(float.DegreesToRadians(propSpotAmb.InnerAngle)),
|
||||
SpotlightOuterAngle = (float)Math.Cos(float.DegreesToRadians(propSpotAmb.OuterAngle)),
|
||||
ObjId = light.ObjId,
|
||||
LightTableIndex = light.LightTableIndex,
|
||||
};
|
||||
|
||||
light.LightTableIndex++; // Because we're inserting the spotlight part first
|
||||
|
||||
spot.FixRadius();
|
||||
spot.ApplyTransforms(vhotLightPos, vhotLightDir, translate, rotate, scale);
|
||||
|
||||
_lights.Add(spot);
|
||||
lightTable.AddLight(spot.ToLightData(32.0f));
|
||||
}
|
||||
else if (propSpotlight != null)
|
||||
{
|
||||
light.Spotlight = true;
|
||||
light.SpotlightInnerAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.InnerAngle));
|
||||
light.SpotlightOuterAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.OuterAngle));
|
||||
}
|
||||
|
||||
light.FixRadius();
|
||||
light.ApplyTransforms(vhotLightPos, vhotLightDir, translate, rotate, scale);
|
||||
|
||||
_lights.Add(light);
|
||||
lightTable.AddLight(light.ToLightData(32.0f));
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ public class MeshBuilder
|
|||
}
|
||||
|
||||
// Let's try and place an object :)
|
||||
// TODO: Handle failing to find model more gracefully
|
||||
var modelName = modelNameProp.value.ToLower() + ".bin";
|
||||
var modelPath = campaignResources.GetResourcePath(ResourceType.Object, modelName);
|
||||
if (modelPath == null)
|
||||
|
@ -120,80 +121,15 @@ public class MeshBuilder
|
|||
continue;
|
||||
}
|
||||
|
||||
// TODO: Handle failing to find model more gracefully
|
||||
var pos = brush.position;
|
||||
var rot = brush.angle;
|
||||
var scale = scaleProp?.value ?? Vector3.One;
|
||||
var model = new ModelFile(modelPath);
|
||||
pos -= model.Header.Center;
|
||||
model.ApplyJoints(joints);
|
||||
|
||||
// Calculate base model transform
|
||||
var scalePart = Matrix4x4.CreateScale(scale);
|
||||
var rotPart = Matrix4x4.Identity;
|
||||
rotPart *= Matrix4x4.CreateRotationX(float.DegreesToRadians(rot.X));
|
||||
rotPart *= Matrix4x4.CreateRotationY(float.DegreesToRadians(rot.Y));
|
||||
rotPart *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(rot.Z));
|
||||
var transPart = Matrix4x4.CreateTranslation(pos);
|
||||
var modelTrans = scalePart * rotPart * transPart;
|
||||
|
||||
// Calculate base transforms for every subobj (including joint)
|
||||
var objCount = model.Objects.Length;
|
||||
var subObjTransforms = new Matrix4x4[objCount];
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = model.Objects[i];
|
||||
var objTrans = Matrix4x4.Identity;
|
||||
if (subObj.Joint != -1)
|
||||
{
|
||||
var ang = float.DegreesToRadians(joints[subObj.Joint]);
|
||||
// TODO: Is this correct? Should I use a manual rotation matrix?
|
||||
var jointRot = Matrix4x4.CreateFromYawPitchRoll(0, ang, 0);
|
||||
objTrans = jointRot * subObj.Transform;
|
||||
}
|
||||
|
||||
subObjTransforms[i] = objTrans;
|
||||
}
|
||||
|
||||
// Build map of objects to their parent id
|
||||
var parentIds = new int[objCount];
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
parentIds[i] = -1;
|
||||
}
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = model.Objects[i];
|
||||
var childIdx = subObj.Child;
|
||||
while (childIdx != -1)
|
||||
{
|
||||
parentIds[childIdx] = i;
|
||||
childIdx = model.Objects[childIdx].Next;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply sub object transforms + the base object transform to each vertex
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = model.Objects[i];
|
||||
var transform = subObjTransforms[i];
|
||||
|
||||
var parentId = parentIds[i];
|
||||
while (parentId != -1)
|
||||
{
|
||||
transform *= subObjTransforms[parentId];
|
||||
parentId = parentIds[parentId];
|
||||
}
|
||||
|
||||
transform *= modelTrans;
|
||||
|
||||
var start = subObj.PointIdx;
|
||||
var end = start + subObj.PointCount;
|
||||
for (var j = start; j < end; j++)
|
||||
{
|
||||
var v = model.Vertices[j];
|
||||
model.Vertices[j] = Vector3.Transform(v, transform);
|
||||
}
|
||||
}
|
||||
var transform = Matrix4x4.CreateScale(scaleProp?.value ?? Vector3.One);
|
||||
transform *= Matrix4x4.CreateRotationX(float.DegreesToRadians(brush.angle.X));
|
||||
transform *= Matrix4x4.CreateRotationY(float.DegreesToRadians(brush.angle.Y));
|
||||
transform *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(brush.angle.Z));
|
||||
transform *= Matrix4x4.CreateTranslation(brush.position - model.Header.Center);
|
||||
|
||||
// for each polygon slam its vertices and indices :)
|
||||
foreach (var poly in model.Polygons)
|
||||
|
@ -202,7 +138,9 @@ public class MeshBuilder
|
|||
polyVertices.EnsureCapacity(poly.VertexCount);
|
||||
foreach (var idx in poly.VertexIndices)
|
||||
{
|
||||
polyVertices.Add(model.Vertices[idx]);
|
||||
var vertex = model.Vertices[idx];
|
||||
vertex = Vector3.Transform(vertex, transform);
|
||||
polyVertices.Add(vertex);
|
||||
}
|
||||
|
||||
AddPolygon(polyVertices, SurfaceType.Solid);
|
||||
|
|
Loading…
Reference in New Issue