Compare commits
No commits in common. "7dc1912390dccaa5adb0789d14d507c9f4ae0426" and "440d0b91b456814cd74b66dc55039da08705df37" have entirely different histories.
7dc1912390
...
440d0b91b4
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace KeepersCompound.LGS.Database.Chunks;
|
||||
|
||||
|
@ -45,15 +46,6 @@ public class BrList : IChunk
|
|||
x = reader.ReadUInt16();
|
||||
y = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(id);
|
||||
writer.Write(rot);
|
||||
writer.Write(scale);
|
||||
writer.Write(x);
|
||||
writer.Write(y);
|
||||
}
|
||||
};
|
||||
|
||||
public short id;
|
||||
|
@ -112,34 +104,6 @@ public class BrList : IChunk
|
|||
txs = Array.Empty<TexInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(id);
|
||||
writer.Write(time);
|
||||
writer.Write(brushInfo);
|
||||
writer.Write(textureId);
|
||||
writer.Write((byte)media);
|
||||
writer.Write(flags);
|
||||
writer.WriteVec3(position);
|
||||
writer.WriteVec3(size);
|
||||
writer.WriteRotation(angle);
|
||||
writer.Write(currentFaceIndex);
|
||||
writer.Write(gridLineSpacing);
|
||||
writer.WriteVec3(gridPhaseShift);
|
||||
writer.WriteRotation(gridOrientation);
|
||||
writer.Write(gridEnabled);
|
||||
writer.Write(numFaces);
|
||||
writer.Write(edgeSelected);
|
||||
writer.Write(pointSelected);
|
||||
writer.Write(useFlag);
|
||||
writer.Write(groupId);
|
||||
writer.Write(new byte[4]);
|
||||
foreach (var info in txs)
|
||||
{
|
||||
info.Write(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
|
@ -156,9 +120,6 @@ public class BrList : IChunk
|
|||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
foreach (var brush in Brushes)
|
||||
{
|
||||
brush.Write(writer);
|
||||
}
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace KeepersCompound.LGS.Database.Chunks;
|
||||
|
||||
|
@ -14,6 +16,6 @@ public class GamFile : IChunk
|
|||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
writer.WriteNullString(fileName, 256);
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
@ -31,11 +32,6 @@ public record LinkId
|
|||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(_data);
|
||||
}
|
||||
}
|
||||
|
||||
public class LinkChunk : IChunk, IMergable
|
||||
|
@ -54,14 +50,6 @@ public class LinkChunk : IChunk, IMergable
|
|||
destination = reader.ReadInt32();
|
||||
relation = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
linkId.Write(writer);
|
||||
writer.Write(source);
|
||||
writer.Write(destination);
|
||||
writer.Write(relation);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
|
@ -78,10 +66,7 @@ public class LinkChunk : IChunk, IMergable
|
|||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
foreach (var link in links)
|
||||
{
|
||||
link.Write(writer);
|
||||
}
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Merge(IMergable other)
|
||||
|
@ -103,12 +88,6 @@ public class LinkDataMetaProp : IChunk, IMergable
|
|||
linkId = new LinkId(reader.ReadUInt32());
|
||||
priority = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
linkId.Write(writer);
|
||||
writer.Write(priority);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
|
@ -127,11 +106,7 @@ public class LinkDataMetaProp : IChunk, IMergable
|
|||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(DataSize);
|
||||
foreach (var data in linkData)
|
||||
{
|
||||
data.Write(writer);
|
||||
}
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Merge(IMergable other)
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
namespace KeepersCompound.LGS.Database.Chunks;
|
||||
|
||||
public enum SoftnessMode
|
||||
{
|
||||
Standard,
|
||||
HighFourPoint,
|
||||
HighFivePoint,
|
||||
HighNinePoint,
|
||||
MediumFourPoint,
|
||||
MediumFivePoint,
|
||||
MediumNinePoint,
|
||||
LowFourPoint,
|
||||
}
|
||||
|
||||
public class LmParams : IChunk
|
||||
{
|
||||
public enum LightingMode
|
||||
{
|
||||
Quick,
|
||||
Raycast,
|
||||
Objcast,
|
||||
}
|
||||
|
||||
public enum DepthMode
|
||||
{
|
||||
Lm16,
|
||||
Lm32,
|
||||
Lm32x,
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
public float Attenuation { get; set; }
|
||||
public float Saturation { get; set; }
|
||||
public LightingMode ShadowType { get; set; }
|
||||
public SoftnessMode ShadowSoftness { get; set; }
|
||||
public float CenterWeight { get; set; }
|
||||
public DepthMode ShadowDepth { get; set; }
|
||||
public bool LightmappedWater { get; set; }
|
||||
public int LightmapScale { get; set; }
|
||||
|
||||
private int _dataSize;
|
||||
private uint _unknown;
|
||||
|
||||
public void ReadData(BinaryReader reader, DbFile.TableOfContents.Entry entry)
|
||||
{
|
||||
_dataSize = reader.ReadInt32();
|
||||
Attenuation = reader.ReadSingle();
|
||||
Saturation = reader.ReadSingle();
|
||||
ShadowType = (LightingMode)reader.ReadUInt32();
|
||||
ShadowSoftness = (SoftnessMode)reader.ReadUInt32();
|
||||
CenterWeight = reader.ReadSingle();
|
||||
ShadowDepth = (DepthMode)reader.ReadUInt32();
|
||||
LightmappedWater = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
LightmapScale = reader.ReadInt32();
|
||||
_unknown = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(_dataSize);
|
||||
writer.Write(Attenuation);
|
||||
writer.Write(Saturation);
|
||||
writer.Write((uint)ShadowType);
|
||||
writer.Write((uint)ShadowSoftness);
|
||||
writer.Write(CenterWeight);
|
||||
writer.Write((uint)ShadowDepth);
|
||||
writer.Write(LightmappedWater);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(LightmapScale);
|
||||
writer.Write(_unknown);
|
||||
}
|
||||
}
|
|
@ -14,12 +14,6 @@ public class Property
|
|||
objectId = reader.ReadInt32();
|
||||
length = (int)reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public virtual void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(objectId);
|
||||
writer.Write((uint)length);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropertyChunk<T> : IChunk, IMergable where T : Property, new()
|
||||
|
@ -40,10 +34,7 @@ public class PropertyChunk<T> : IChunk, IMergable where T : Property, new()
|
|||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
prop.Write(writer);
|
||||
}
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Merge(IMergable other)
|
||||
|
@ -61,12 +52,6 @@ public class PropGeneric : Property
|
|||
base.Read(reader);
|
||||
data = reader.ReadBytes(length);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropBool : Property
|
||||
|
@ -78,12 +63,6 @@ public class PropBool : Property
|
|||
base.Read(reader);
|
||||
value = reader.ReadInt32() != 0;
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropInt : Property
|
||||
|
@ -95,12 +74,6 @@ public class PropInt : Property
|
|||
base.Read(reader);
|
||||
value = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(value);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropLabel : Property
|
||||
|
@ -112,12 +85,6 @@ public class PropLabel : Property
|
|||
base.Read(reader);
|
||||
value = reader.ReadNullString(length);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.WriteNullString(value, length);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropString : Property
|
||||
|
@ -131,13 +98,6 @@ public class PropString : Property
|
|||
stringLength = reader.ReadInt32();
|
||||
value = reader.ReadNullString(stringLength);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(stringLength);
|
||||
writer.WriteNullString(value, stringLength);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropFloat : Property
|
||||
|
@ -149,12 +109,6 @@ public class PropFloat : Property
|
|||
base.Read(reader);
|
||||
value = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(value);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropVector : Property
|
||||
|
@ -166,12 +120,6 @@ public class PropVector : Property
|
|||
base.Read(reader);
|
||||
value = reader.ReadVec3();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.WriteVec3(value);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropRenderType : Property
|
||||
|
@ -192,12 +140,6 @@ public class PropRenderType : Property
|
|||
base.Read(reader);
|
||||
mode = (Mode)reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write((uint)mode);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropSlayResult : Property
|
||||
|
@ -214,12 +156,6 @@ public class PropSlayResult : Property
|
|||
base.Read(reader);
|
||||
effect = (Effect)reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write((uint)effect);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropInventoryType : Property
|
||||
|
@ -236,12 +172,6 @@ public class PropInventoryType : Property
|
|||
base.Read(reader);
|
||||
type = (Slot)reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write((uint)type);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropCollisionType : Property
|
||||
|
@ -264,19 +194,6 @@ public class PropCollisionType : Property
|
|||
NoResult = (flags & (0x1 << 4)) != 0;
|
||||
FullCollisionSound = (flags & (0x1 << 5)) != 0;
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
var flags = 0u;
|
||||
if (Bounce) flags += 1;
|
||||
if (DestroyOnImpact) flags += 2;
|
||||
if (SlayOnImpact) flags += 4;
|
||||
if (NoCollisionSound) flags += 8;
|
||||
if (NoResult) flags += 16;
|
||||
if (FullCollisionSound) flags += 32;
|
||||
writer.Write(flags);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropPosition : Property
|
||||
|
@ -291,14 +208,6 @@ public class PropPosition : Property
|
|||
reader.ReadBytes(4); // Runtime Cell/Hint in editor
|
||||
Rotation = reader.ReadRotation();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.WriteVec3(Location);
|
||||
writer.Write(new byte[4]);
|
||||
writer.WriteRotation(Rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropLight : Property
|
||||
|
@ -319,123 +228,6 @@ public class PropLight : Property
|
|||
reader.ReadBytes(3);
|
||||
InnerRadius = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(Brightness);
|
||||
writer.WriteVec3(Offset);
|
||||
writer.Write(Radius);
|
||||
writer.Write(QuadLit);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(InnerRadius);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropAnimLight : Property
|
||||
{
|
||||
public enum AnimMode
|
||||
{
|
||||
FlipMinMax,
|
||||
SlideSmoothly,
|
||||
Random,
|
||||
MinBrightness,
|
||||
MaxBrightness,
|
||||
ZeroBrightness,
|
||||
SmoothlyBrighten,
|
||||
SmoothlyDim,
|
||||
RandomButCoherent,
|
||||
FlickerMinMax,
|
||||
}
|
||||
|
||||
// Standard light props
|
||||
public float Brightness;
|
||||
public Vector3 Offset;
|
||||
public float Radius;
|
||||
public float InnerRadius;
|
||||
public bool QuadLit;
|
||||
public bool Dynamic;
|
||||
|
||||
// Animation
|
||||
public AnimMode Mode;
|
||||
public int MsToBrighten;
|
||||
public int MsToDim;
|
||||
public float MinBrightness;
|
||||
public float MaxBrightness;
|
||||
|
||||
// Start state
|
||||
public float CurrentBrightness;
|
||||
public bool Rising;
|
||||
public int Timer;
|
||||
public bool Inactive;
|
||||
|
||||
// World rep info
|
||||
public bool Refresh; // Not relevant to us. It's used to tell dromed it needs to relight
|
||||
public ushort LightTableMapIndex;
|
||||
public ushort LightTableLightIndex;
|
||||
public ushort CellsReached;
|
||||
|
||||
private int _unknown;
|
||||
|
||||
public override void Read(BinaryReader reader)
|
||||
{
|
||||
base.Read(reader);
|
||||
Brightness = reader.ReadSingle();
|
||||
Offset = reader.ReadVec3();
|
||||
Refresh = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
LightTableMapIndex = reader.ReadUInt16();
|
||||
CellsReached = reader.ReadUInt16();
|
||||
LightTableLightIndex = reader.ReadUInt16();
|
||||
Mode = (AnimMode)reader.ReadUInt16();
|
||||
MsToBrighten = reader.ReadInt32();
|
||||
MsToDim = reader.ReadInt32();
|
||||
MinBrightness = reader.ReadSingle();
|
||||
MaxBrightness = reader.ReadSingle();
|
||||
CurrentBrightness = reader.ReadSingle();
|
||||
Rising = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
Timer = reader.ReadInt32();
|
||||
Inactive = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
Radius = reader.ReadSingle();
|
||||
_unknown = reader.ReadInt32();
|
||||
QuadLit = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
InnerRadius = reader.ReadSingle();
|
||||
Dynamic = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(Brightness);
|
||||
writer.WriteVec3(Offset);
|
||||
writer.Write(Refresh);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(LightTableMapIndex);
|
||||
writer.Write(CellsReached);
|
||||
writer.Write(LightTableLightIndex);
|
||||
writer.Write((ushort)Mode);
|
||||
writer.Write(MsToBrighten);
|
||||
writer.Write(MsToDim);
|
||||
writer.Write(MinBrightness);
|
||||
writer.Write(MaxBrightness);
|
||||
writer.Write(CurrentBrightness);
|
||||
writer.Write(Rising);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(Timer);
|
||||
writer.Write(Inactive);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(Radius);
|
||||
writer.Write(_unknown);
|
||||
writer.Write(QuadLit);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(InnerRadius);
|
||||
writer.Write(Dynamic);
|
||||
writer.Write(new byte[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropLightColor : Property
|
||||
|
@ -449,13 +241,6 @@ public class PropLightColor : Property
|
|||
Hue = reader.ReadSingle();
|
||||
Saturation = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(Hue);
|
||||
writer.Write(Saturation);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropSpotlight : Property
|
||||
|
@ -470,14 +255,6 @@ public class PropSpotlight : Property
|
|||
OuterAngle = reader.ReadSingle();
|
||||
reader.ReadBytes(4); // Z is unused
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(InnerAngle);
|
||||
writer.Write(OuterAngle);
|
||||
writer.Write(new byte[4]);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropSpotlightAndAmbient : Property
|
||||
|
@ -493,12 +270,21 @@ public class PropSpotlightAndAmbient : Property
|
|||
OuterAngle = reader.ReadSingle();
|
||||
SpotBrightness = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
// TODO: Work out what this property actually does
|
||||
public class PropLightBasedAlpha : Property
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(InnerAngle);
|
||||
writer.Write(OuterAngle);
|
||||
writer.Write(SpotBrightness);
|
||||
public bool Enabled;
|
||||
public Vector2 AlphaRange;
|
||||
public Vector2 LightRange;
|
||||
|
||||
public override void Read(BinaryReader reader)
|
||||
{
|
||||
base.Read(reader);
|
||||
Enabled = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
AlphaRange = reader.ReadVec2();
|
||||
LightRange = new Vector2(reader.ReadInt32(), reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
||||
namespace KeepersCompound.LGS.Database.Chunks;
|
||||
|
||||
public class RendParams : IChunk
|
||||
{
|
||||
public enum SunlightMode
|
||||
{
|
||||
SingleUnshadowed,
|
||||
QuadObjcastShadows,
|
||||
QuadUnshadowed,
|
||||
SingleObjcastShadows,
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
|
||||
public string palette;
|
||||
public Vector3 ambientLight;
|
||||
public int useSunlight;
|
||||
public SunlightMode sunlightMode;
|
||||
public Vector3 sunlightDirection;
|
||||
public float sunlightHue;
|
||||
public float sunlightSaturation;
|
||||
public float sunlightBrightness;
|
||||
public float viewDistance;
|
||||
public Vector3[] ambientLightZones;
|
||||
public float globalAiVisBias;
|
||||
public float[] ambientZoneAiVisBiases;
|
||||
|
||||
public void ReadData(BinaryReader reader, DbFile.TableOfContents.Entry entry)
|
||||
{
|
||||
palette = reader.ReadNullString(16);
|
||||
ambientLight = reader.ReadVec3();
|
||||
useSunlight = reader.ReadInt32();
|
||||
sunlightMode = (SunlightMode)reader.ReadUInt32();
|
||||
sunlightDirection = reader.ReadVec3();
|
||||
sunlightHue = reader.ReadSingle();
|
||||
sunlightSaturation = reader.ReadSingle();
|
||||
sunlightBrightness = reader.ReadSingle();
|
||||
reader.ReadBytes(24);
|
||||
viewDistance = reader.ReadSingle();
|
||||
reader.ReadBytes(12);
|
||||
ambientLightZones = new Vector3[8];
|
||||
for (var i = 0; i < ambientLightZones.Length; i++)
|
||||
{
|
||||
ambientLightZones[i] = reader.ReadVec3();
|
||||
}
|
||||
globalAiVisBias = reader.ReadSingle();
|
||||
ambientZoneAiVisBiases = new float[8];
|
||||
for (var i = 0; i < ambientZoneAiVisBiases.Length; i++)
|
||||
{
|
||||
ambientZoneAiVisBiases[i] = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
writer.WriteNullString(palette, 16);
|
||||
writer.WriteVec3(ambientLight);
|
||||
writer.Write(useSunlight);
|
||||
writer.Write((uint)sunlightMode);
|
||||
writer.WriteVec3(sunlightDirection);
|
||||
writer.Write(sunlightHue);
|
||||
writer.Write(sunlightSaturation);
|
||||
writer.Write(sunlightBrightness);
|
||||
writer.Write(new byte[24]);
|
||||
writer.Write(viewDistance);
|
||||
writer.Write(new byte[12]);
|
||||
foreach (var lightZone in ambientLightZones)
|
||||
{
|
||||
writer.WriteVec3(lightZone);
|
||||
}
|
||||
writer.Write(globalAiVisBias);
|
||||
foreach (var visBias in ambientZoneAiVisBiases)
|
||||
{
|
||||
writer.Write(visBias);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace KeepersCompound.LGS.Database.Chunks;
|
||||
|
||||
|
@ -14,12 +16,6 @@ public class TxList : IChunk
|
|||
Tokens = reader.ReadBytes(4);
|
||||
Name = reader.ReadNullString(16);
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Tokens);
|
||||
writer.WriteNullString(Name, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,6 +27,7 @@ public class TxList : IChunk
|
|||
public string[] Tokens { get; set; }
|
||||
public Item[] Items { get; set; }
|
||||
|
||||
|
||||
public void ReadData(BinaryReader reader, DbFile.TableOfContents.Entry entry)
|
||||
{
|
||||
BlockSize = reader.ReadInt32();
|
||||
|
@ -50,16 +47,6 @@ public class TxList : IChunk
|
|||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(BlockSize);
|
||||
writer.Write(ItemCount);
|
||||
writer.Write(TokenCount);
|
||||
foreach (var token in Tokens)
|
||||
{
|
||||
writer.WriteNullString(token, 16);
|
||||
}
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.Write(writer);
|
||||
}
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
||||
|
@ -40,20 +39,9 @@ public class WorldRep : IChunk
|
|||
_ => 1.0f,
|
||||
};
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Size);
|
||||
writer.Write(Version);
|
||||
writer.Write(Flags);
|
||||
writer.Write(LightmapFormat);
|
||||
writer.Write(LightmapScale);
|
||||
writer.Write(DataSize);
|
||||
writer.Write(CellCount);
|
||||
}
|
||||
}
|
||||
|
||||
public class Cell
|
||||
public struct Cell
|
||||
{
|
||||
public struct Poly
|
||||
{
|
||||
|
@ -74,17 +62,6 @@ public class WorldRep : IChunk
|
|||
MotionIndex = reader.ReadByte();
|
||||
reader.ReadByte();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Flags);
|
||||
writer.Write(VertexCount);
|
||||
writer.Write(PlaneId);
|
||||
writer.Write(ClutId);
|
||||
writer.Write(Destination);
|
||||
writer.Write(MotionIndex);
|
||||
writer.Write((byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
public struct RenderPoly
|
||||
|
@ -105,21 +82,9 @@ public class WorldRep : IChunk
|
|||
TextureMagnitude = reader.ReadSingle();
|
||||
Center = reader.ReadVec3();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.WriteVec3(TextureVectors.Item1);
|
||||
writer.WriteVec3(TextureVectors.Item2);
|
||||
writer.Write(TextureBases.Item1);
|
||||
writer.Write(TextureBases.Item2);
|
||||
writer.Write(TextureId);
|
||||
writer.Write(CachedSurface);
|
||||
writer.Write(TextureMagnitude);
|
||||
writer.WriteVec3(Center);
|
||||
}
|
||||
}
|
||||
|
||||
public class LightmapInfo
|
||||
public struct LightmapInfo
|
||||
{
|
||||
public (short, short) Bases { get; set; }
|
||||
public short PaddedWidth { get; set; }
|
||||
|
@ -139,24 +104,11 @@ public class WorldRep : IChunk
|
|||
DynamicLightPtr = reader.ReadUInt32();
|
||||
AnimLightBitmask = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Bases.Item1);
|
||||
writer.Write(Bases.Item2);
|
||||
writer.Write(PaddedWidth);
|
||||
writer.Write(Height);
|
||||
writer.Write(Width);
|
||||
writer.Write(DataPtr);
|
||||
writer.Write(DynamicLightPtr);
|
||||
writer.Write(AnimLightBitmask);
|
||||
}
|
||||
}
|
||||
|
||||
public class Lightmap
|
||||
public struct Lightmap
|
||||
{
|
||||
private readonly bool[] _litLayers;
|
||||
public List<byte[]> Pixels { get; set; }
|
||||
public byte[] Pixels { get; set; }
|
||||
|
||||
public int Layers;
|
||||
public int Width;
|
||||
|
@ -165,52 +117,44 @@ public class WorldRep : IChunk
|
|||
|
||||
public Lightmap(BinaryReader reader, byte width, byte height, uint bitmask, int bytesPerPixel)
|
||||
{
|
||||
var layers = 1 + BitOperations.PopCount(bitmask);
|
||||
var length = bytesPerPixel * width * height;
|
||||
_litLayers = new bool[33];
|
||||
Pixels = new List<byte[]>();
|
||||
for (var i = 0; i < layers; i++)
|
||||
{
|
||||
Pixels.Add(reader.ReadBytes(length));
|
||||
_litLayers[i] = true;
|
||||
}
|
||||
Layers = layers;
|
||||
var count = 1 + BitOperations.PopCount(bitmask);
|
||||
var length = bytesPerPixel * width * height * count;
|
||||
Pixels = reader.ReadBytes(length);
|
||||
Layers = count;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Bpp = bytesPerPixel;
|
||||
}
|
||||
|
||||
public Vector4 GetPixel(uint layer, uint x, uint y)
|
||||
public readonly Vector4 GetPixel(uint layer, uint x, uint y)
|
||||
{
|
||||
if (layer >= Layers || x >= Width || y >= Height)
|
||||
{
|
||||
return Vector4.Zero;
|
||||
}
|
||||
|
||||
var pLayer = Pixels[(int)layer];
|
||||
var idx = x * Bpp + y * Bpp * Width;
|
||||
var idx = 0 + x * Bpp + y * Bpp * Width + layer * Bpp * Width * Height;
|
||||
switch (Bpp)
|
||||
{
|
||||
case 1:
|
||||
var raw1 = pLayer[idx];
|
||||
var raw1 = Pixels[idx];
|
||||
return new Vector4(raw1, raw1, raw1, 255) / 255.0f;
|
||||
case 2:
|
||||
var raw2 = pLayer[idx] + (pLayer[idx + 1] << 8);
|
||||
var raw2 = Pixels[idx] + (Pixels[idx + 1] << 8);
|
||||
return new Vector4(raw2 & 31, (raw2 >> 5) & 31, (raw2 >> 10) & 31, 31) / 31.0f;
|
||||
case 4:
|
||||
return new Vector4(pLayer[idx + 2], pLayer[idx + 1], pLayer[idx], pLayer[idx + 3]) / 255.0f;
|
||||
return new Vector4(Pixels[idx + 2], Pixels[idx + 1], Pixels[idx], Pixels[idx + 3]) / 255.0f;
|
||||
default:
|
||||
return Vector4.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] AsBytesRgba(int layer)
|
||||
public readonly byte[] AsBytesRgba(int layer)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(layer, 0, nameof(layer));
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan(layer, Layers, nameof(layer));
|
||||
|
||||
var pLayer = Pixels[layer];
|
||||
var pIdx = 0;
|
||||
var pIdx = layer * Bpp * Width * Height;
|
||||
var length = 4 * Width * Height;
|
||||
var bytes = new byte[length];
|
||||
for (var i = 0; i < length; i += 4, pIdx += Bpp)
|
||||
|
@ -218,99 +162,30 @@ public class WorldRep : IChunk
|
|||
switch (Bpp)
|
||||
{
|
||||
case 1:
|
||||
var raw1 = pLayer[pIdx];
|
||||
var raw1 = Pixels[pIdx];
|
||||
bytes[i] = raw1;
|
||||
bytes[i + 1] = raw1;
|
||||
bytes[i + 2] = raw1;
|
||||
bytes[i + 3] = 255;
|
||||
break;
|
||||
case 2:
|
||||
var raw2 = pLayer[pIdx] + (pLayer[pIdx + 1] << 8);
|
||||
var raw2 = Pixels[pIdx] + (Pixels[pIdx + 1] << 8);
|
||||
bytes[i] = (byte)(255 * (raw2 & 31) / 31.0f);
|
||||
bytes[i + 1] = (byte)(255 * ((raw2 >> 5) & 31) / 31.0f);
|
||||
bytes[i + 2] = (byte)(255 * ((raw2 >> 10) & 31) / 31.0f);
|
||||
bytes[i + 3] = 255;
|
||||
break;
|
||||
case 4:
|
||||
bytes[i] = pLayer[pIdx + 2];
|
||||
bytes[i + 1] = pLayer[pIdx + 1];
|
||||
bytes[i + 2] = pLayer[pIdx];
|
||||
bytes[i + 3] = pLayer[pIdx + 3];
|
||||
bytes[i] = Pixels[pIdx + 2];
|
||||
bytes[i + 1] = Pixels[pIdx + 1];
|
||||
bytes[i + 2] = Pixels[pIdx];
|
||||
bytes[i + 3] = Pixels[pIdx + 3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var idx = (x + y * Width) * Bpp;
|
||||
var pLayer = Pixels[layer];
|
||||
pLayer[idx] = (byte)Math.Clamp(pLayer[idx] + r, 0, 255);
|
||||
pLayer[idx + 1] = (byte)Math.Clamp(pLayer[idx + 1] + g, 0, 255);
|
||||
pLayer[idx + 2] = (byte)Math.Clamp(pLayer[idx + 2] + b, 0, 255);
|
||||
pLayer[idx + 3] = 255;
|
||||
|
||||
_litLayers[layer] = true;
|
||||
}
|
||||
|
||||
public void AddLight(int layer, int x, int y, Vector3 color, float strength, bool hdr)
|
||||
{
|
||||
if (hdr)
|
||||
{
|
||||
strength /= 2.0f;
|
||||
}
|
||||
|
||||
// We need to make sure we don't go over (255, 255, 255).
|
||||
// If we just do Max(color, (255, 255, 255)) then we change
|
||||
// the hue/saturation of coloured lights. Got to make sure we
|
||||
// maintain the colour ratios.
|
||||
var c = color * strength;
|
||||
var ratio = Math.Max(Math.Max(Math.Max(0.0f, c.X), c.Y), c.Z) / 255.0f;
|
||||
if (ratio > 1.0f)
|
||||
{
|
||||
c /= ratio;
|
||||
}
|
||||
|
||||
AddLight(layer, x, y, c.Z, c.Y, c.X);
|
||||
}
|
||||
|
||||
public void Reset(Vector3 ambientLight, bool hdr)
|
||||
{
|
||||
Layers = 33;
|
||||
Pixels.Clear();
|
||||
var bytesPerLayer = Width * Height * Bpp;
|
||||
for (var i = 0; i < Layers; i++)
|
||||
{
|
||||
Pixels.Add(new byte[bytesPerLayer]);
|
||||
for (var j = 0; j < bytesPerLayer; j++)
|
||||
{
|
||||
Pixels[i][j] = 0;
|
||||
}
|
||||
_litLayers[i] = false;
|
||||
}
|
||||
|
||||
for (var y = 0; y < Height; y++)
|
||||
{
|
||||
for (var x = 0; x < Width; x++)
|
||||
{
|
||||
AddLight(0, x, y, ambientLight, 1.0f, hdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
for (var i = 0; i < Layers; i++)
|
||||
{
|
||||
if (_litLayers[i])
|
||||
{
|
||||
writer.Write(Pixels[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte VertexCount { get; set; }
|
||||
|
@ -332,11 +207,11 @@ public class WorldRep : IChunk
|
|||
public uint IndexCount { get; set; }
|
||||
public byte[] Indices { get; set; }
|
||||
public Plane[] Planes { get; set; }
|
||||
public List<ushort> AnimLights { get; set; }
|
||||
public ushort[] AnimLights { get; set; }
|
||||
public LightmapInfo[] LightList { get; set; }
|
||||
public Lightmap[] Lightmaps { get; set; }
|
||||
public int LightIndexCount { get; set; }
|
||||
public List<ushort> LightIndices { get; set; }
|
||||
public ushort[] LightIndices { get; set; }
|
||||
|
||||
public Cell(BinaryReader reader, int bpp)
|
||||
{
|
||||
|
@ -379,10 +254,10 @@ public class WorldRep : IChunk
|
|||
{
|
||||
Planes[i] = new Plane(reader.ReadVec3(), reader.ReadSingle());
|
||||
}
|
||||
AnimLights = new List<ushort>(AnimLightCount);
|
||||
AnimLights = new ushort[AnimLightCount];
|
||||
for (var i = 0; i < AnimLightCount; i++)
|
||||
{
|
||||
AnimLights.Add(reader.ReadUInt16());
|
||||
AnimLights[i] = reader.ReadUInt16();
|
||||
}
|
||||
LightList = new LightmapInfo[RenderPolyCount];
|
||||
for (var i = 0; i < RenderPolyCount; i++)
|
||||
|
@ -396,269 +271,17 @@ public class WorldRep : IChunk
|
|||
Lightmaps[i] = new Lightmap(reader, info.Width, info.Height, info.AnimLightBitmask, bpp);
|
||||
}
|
||||
LightIndexCount = reader.ReadInt32();
|
||||
LightIndices = new List<ushort>(LightIndexCount);
|
||||
LightIndices = new ushort[LightIndexCount];
|
||||
for (var i = 0; i < LightIndexCount; i++)
|
||||
{
|
||||
LightIndices.Add(reader.ReadUInt16());
|
||||
LightIndices[i] = reader.ReadUInt16();
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(VertexCount);
|
||||
writer.Write(PolyCount);
|
||||
writer.Write(RenderPolyCount);
|
||||
writer.Write(PortalPolyCount);
|
||||
writer.Write(PlaneCount);
|
||||
writer.Write(Medium);
|
||||
writer.Write(Flags);
|
||||
writer.Write(PortalVertices);
|
||||
writer.Write(NumVList);
|
||||
writer.Write(AnimLightCount);
|
||||
writer.Write(MotionIndex);
|
||||
writer.WriteVec3(SphereCenter);
|
||||
writer.Write(SphereRadius);
|
||||
foreach (var vertex in Vertices)
|
||||
{
|
||||
writer.WriteVec3(vertex);
|
||||
}
|
||||
foreach (var poly in Polys)
|
||||
{
|
||||
poly.Write(writer);
|
||||
}
|
||||
foreach (var renderPoly in RenderPolys)
|
||||
{
|
||||
renderPoly.Write(writer);
|
||||
}
|
||||
writer.Write(IndexCount);
|
||||
writer.Write(Indices);
|
||||
foreach (var plane in Planes)
|
||||
{
|
||||
writer.WriteVec3(plane.Normal);
|
||||
writer.Write(plane.D);
|
||||
}
|
||||
foreach (var animLight in AnimLights)
|
||||
{
|
||||
writer.Write(animLight);
|
||||
}
|
||||
foreach (var lightmapInfo in LightList)
|
||||
{
|
||||
lightmapInfo.Write(writer);
|
||||
}
|
||||
foreach (var lightmap in Lightmaps)
|
||||
{
|
||||
lightmap.Write(writer);
|
||||
}
|
||||
writer.Write(LightIndexCount);
|
||||
foreach (var lightIndex in LightIndices)
|
||||
{
|
||||
writer.Write(lightIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct BspTree
|
||||
{
|
||||
public struct Node
|
||||
{
|
||||
int parentIndex; // TODO: Split the flags out of this
|
||||
int cellId;
|
||||
int planeId;
|
||||
uint insideIndex;
|
||||
uint outsideIndex;
|
||||
|
||||
public Node(BinaryReader reader)
|
||||
{
|
||||
parentIndex = reader.ReadInt32();
|
||||
cellId = reader.ReadInt32();
|
||||
planeId = reader.ReadInt32();
|
||||
insideIndex = reader.ReadUInt32();
|
||||
outsideIndex = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(parentIndex);
|
||||
writer.Write(cellId);
|
||||
writer.Write(planeId);
|
||||
writer.Write(insideIndex);
|
||||
writer.Write(outsideIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public uint PlaneCount;
|
||||
public uint NodeCount;
|
||||
public Plane[] Planes;
|
||||
public Node[] Nodes;
|
||||
|
||||
public BspTree(BinaryReader reader)
|
||||
{
|
||||
PlaneCount = reader.ReadUInt32();
|
||||
Planes = new Plane[PlaneCount];
|
||||
for (var i = 0; i < PlaneCount; i++)
|
||||
{
|
||||
Planes[i] = new Plane(reader.ReadVec3(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
NodeCount = reader.ReadUInt32();
|
||||
Nodes = new Node[NodeCount];
|
||||
for (var i = 0; i < NodeCount; i++)
|
||||
{
|
||||
Nodes[i] = new Node(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(PlaneCount);
|
||||
foreach (var plane in Planes)
|
||||
{
|
||||
writer.WriteVec3(plane.Normal);
|
||||
writer.Write(plane.D);
|
||||
}
|
||||
writer.Write(NodeCount);
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
node.Write(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LightTable
|
||||
{
|
||||
public struct LightData
|
||||
{
|
||||
public Vector3 Location;
|
||||
public Vector3 Direction;
|
||||
public Vector3 Color;
|
||||
public float InnerAngle; // I'm pretty sure these are the spotlight angles
|
||||
public float OuterAngle;
|
||||
public float Radius;
|
||||
|
||||
public LightData(BinaryReader reader)
|
||||
{
|
||||
Location = reader.ReadVec3();
|
||||
Direction = reader.ReadVec3();
|
||||
Color = reader.ReadVec3();
|
||||
InnerAngle = reader.ReadSingle();
|
||||
OuterAngle = reader.ReadSingle();
|
||||
Radius = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.WriteVec3(Location);
|
||||
writer.WriteVec3(Direction);
|
||||
writer.WriteVec3(Color);
|
||||
writer.Write(InnerAngle);
|
||||
writer.Write(OuterAngle);
|
||||
writer.Write(Radius);
|
||||
}
|
||||
}
|
||||
|
||||
public struct AnimCellMap
|
||||
{
|
||||
public ushort CellIndex;
|
||||
public ushort LightIndex;
|
||||
|
||||
public AnimCellMap(BinaryReader reader)
|
||||
{
|
||||
CellIndex = reader.ReadUInt16();
|
||||
LightIndex = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(CellIndex);
|
||||
writer.Write(LightIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public int LightCount;
|
||||
public int DynamicLightCount;
|
||||
public int AnimMapCount;
|
||||
public List<LightData> Lights;
|
||||
public LightData[] ScratchpadLights;
|
||||
public List<AnimCellMap> AnimCellMaps;
|
||||
|
||||
// TODO: Support olddark
|
||||
public LightTable(BinaryReader reader)
|
||||
{
|
||||
LightCount = reader.ReadInt32();
|
||||
DynamicLightCount = reader.ReadInt32();
|
||||
var totalLightCount = LightCount + DynamicLightCount;
|
||||
Lights = new List<LightData>(totalLightCount);
|
||||
for (var i = 0; i < totalLightCount; i++)
|
||||
{
|
||||
Lights.Add(new LightData(reader));
|
||||
}
|
||||
ScratchpadLights = new LightData[32];
|
||||
for (var i = 0; i < 32; i++)
|
||||
{
|
||||
ScratchpadLights[i] = new LightData(reader);
|
||||
}
|
||||
AnimMapCount = reader.ReadInt32();
|
||||
AnimCellMaps = new List<AnimCellMap>(AnimMapCount);
|
||||
for (var i = 0; i < AnimMapCount; i++)
|
||||
{
|
||||
AnimCellMaps.Add(new AnimCellMap(reader));
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(LightCount);
|
||||
writer.Write(DynamicLightCount);
|
||||
foreach (var light in Lights)
|
||||
{
|
||||
light.Write(writer);
|
||||
}
|
||||
foreach (var light in ScratchpadLights)
|
||||
{
|
||||
light.Write(writer);
|
||||
}
|
||||
writer.Write(AnimMapCount);
|
||||
foreach (var map in AnimCellMaps)
|
||||
{
|
||||
map.Write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
// Seems light we store something for sunlight at index 0 even if sunlight isn't being used
|
||||
// TODO: Work out what to actually *put* here
|
||||
LightCount = 1;
|
||||
Lights.Clear();
|
||||
Lights.Add(new LightData());
|
||||
|
||||
DynamicLightCount = 0;
|
||||
AnimMapCount = 0;
|
||||
AnimCellMaps.Clear();
|
||||
}
|
||||
|
||||
public void AddLight(LightData data, bool dynamicLight = false)
|
||||
{
|
||||
if (dynamicLight)
|
||||
{
|
||||
DynamicLightCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LightCount++;
|
||||
}
|
||||
|
||||
Lights.Add(data);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
public WrHeader DataHeader { get; set; }
|
||||
public Cell[] Cells { get; set; }
|
||||
public BspTree Bsp { get; set; }
|
||||
public LightTable LightingTable { get; set; }
|
||||
private byte[] _unknown;
|
||||
private byte[] _unreadData;
|
||||
|
||||
public void ReadData(BinaryReader reader, DbFile.TableOfContents.Entry entry)
|
||||
{
|
||||
|
@ -671,27 +294,11 @@ public class WorldRep : IChunk
|
|||
Cells[i] = new Cell(reader, bpp);
|
||||
}
|
||||
|
||||
Bsp = new BspTree(reader);
|
||||
|
||||
// TODO: Work out what this is
|
||||
_unknown = reader.ReadBytes(Cells.Length);
|
||||
LightingTable = new LightTable(reader);
|
||||
|
||||
// TODO: All the other info lol
|
||||
var length = entry.Offset + entry.Size + 24 - reader.BaseStream.Position;
|
||||
_unreadData = reader.ReadBytes((int)length);
|
||||
}
|
||||
|
||||
public void WriteData(BinaryWriter writer)
|
||||
{
|
||||
DataHeader.Write(writer);
|
||||
foreach (var cell in Cells)
|
||||
{
|
||||
cell.Write(writer);
|
||||
}
|
||||
Bsp.Write(writer);
|
||||
writer.Write(_unknown);
|
||||
LightingTable.Write(writer);
|
||||
writer.Write(_unreadData);
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -31,13 +32,13 @@ public class DbFile
|
|||
}
|
||||
}
|
||||
|
||||
public struct TableOfContents
|
||||
public readonly struct TableOfContents
|
||||
{
|
||||
public struct Entry
|
||||
public readonly struct Entry
|
||||
{
|
||||
public string Name;
|
||||
public uint Offset;
|
||||
public uint Size;
|
||||
public string Name { get; }
|
||||
public uint Offset { get; }
|
||||
public uint Size { get; }
|
||||
|
||||
public Entry(BinaryReader reader)
|
||||
{
|
||||
|
@ -46,16 +47,10 @@ public class DbFile
|
|||
Size = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public override readonly string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Name: {Name}, Offset: {Offset}, Size: {Size}";
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.WriteNullString(Name, 12);
|
||||
writer.Write(Offset);
|
||||
writer.Write(Size);
|
||||
// return $"Name: {Name}, Offset: {O}"
|
||||
return base.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,15 +65,6 @@ public class DbFile
|
|||
Items.Add(new Entry(reader));
|
||||
Items.Sort((a, b) => a.Offset.CompareTo(b.Offset));
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(ItemCount);
|
||||
foreach (var entry in Items)
|
||||
{
|
||||
entry.Write(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FHeader Header { get; private set; }
|
||||
|
@ -87,7 +73,6 @@ public class DbFile
|
|||
|
||||
public DbFile(string filename)
|
||||
{
|
||||
// TODO: Throw rather than return
|
||||
if (!File.Exists(filename)) return;
|
||||
|
||||
using MemoryStream stream = new(File.ReadAllBytes(filename));
|
||||
|
@ -106,43 +91,6 @@ public class DbFile
|
|||
}
|
||||
}
|
||||
|
||||
public void Save(string filename)
|
||||
{
|
||||
using var stream = File.Open(filename, FileMode.Create);
|
||||
using var writer = new BinaryWriter(stream, Encoding.UTF8, false);
|
||||
|
||||
Header.Write(writer);
|
||||
for (var i = 0; i < Toc.ItemCount; i++)
|
||||
{
|
||||
var item = Toc.Items[i];
|
||||
var pos = stream.Position;
|
||||
|
||||
var chunk = Chunks[item.Name];
|
||||
chunk.Write(writer);
|
||||
var size = stream.Position - pos - 24;
|
||||
|
||||
item.Offset = (uint)pos;
|
||||
item.Size = (uint)size;
|
||||
Toc.Items[i] = item;
|
||||
}
|
||||
var tocOffset = (uint)stream.Position;
|
||||
Toc.Write(writer);
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
writer.Write(tocOffset);
|
||||
}
|
||||
|
||||
public bool TryGetChunk<T>(string name, out T chunk)
|
||||
{
|
||||
if (Chunks.TryGetValue(name, out var rawChunk))
|
||||
{
|
||||
chunk = (T)rawChunk;
|
||||
return true;
|
||||
}
|
||||
chunk = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IChunk NewChunk(string entryName)
|
||||
{
|
||||
return entryName switch
|
||||
|
@ -153,8 +101,6 @@ public class DbFile
|
|||
"TXLIST" => new TxList(),
|
||||
"WREXT" => new WorldRep(),
|
||||
"BRLIST" => new BrList(),
|
||||
"LM_PARAM" => new LmParams(),
|
||||
"RENDPARAMS" => new RendParams(),
|
||||
"P$ModelName" => new PropertyChunk<PropLabel>(),
|
||||
"P$Scale" => new PropertyChunk<PropVector>(),
|
||||
"P$RenderTyp" => new PropertyChunk<PropRenderType>(),
|
||||
|
@ -162,10 +108,6 @@ public class DbFile
|
|||
"P$OTxtRepr1" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr2" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr3" => new PropertyChunk<PropString>(),
|
||||
"P$Light" => new PropertyChunk<PropLight>(),
|
||||
"P$AnimLight" => new PropertyChunk<PropAnimLight>(),
|
||||
"P$LightColo" => new PropertyChunk<PropLightColor>(),
|
||||
"P$Spotlight" => new PropertyChunk<PropSpotlight>(),
|
||||
"P$RenderAlp" => new PropertyChunk<PropFloat>(),
|
||||
"LD$MetaProp" => new LinkDataMetaProp(),
|
||||
_ when entryName.StartsWith("L$") => new LinkChunk(),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using KeepersCompound.LGS.Database.Chunks;
|
||||
|
@ -6,7 +7,7 @@ namespace KeepersCompound.LGS.Database;
|
|||
|
||||
public class ObjectHierarchy
|
||||
{
|
||||
private class DarkObject
|
||||
public class DarkObject
|
||||
{
|
||||
public int objectId;
|
||||
public int parentId;
|
||||
|
@ -19,7 +20,7 @@ public class ObjectHierarchy
|
|||
properties = new Dictionary<string, Property>();
|
||||
}
|
||||
|
||||
public T? GetProperty<T>(string propName) where T : Property
|
||||
public T GetProperty<T>(string propName) where T : Property
|
||||
{
|
||||
if (properties.TryGetValue(propName, out var prop))
|
||||
{
|
||||
|
@ -37,19 +38,20 @@ public class ObjectHierarchy
|
|||
|
||||
T GetMergedChunk<T>(string name) where T : IMergable
|
||||
{
|
||||
if (!db.TryGetChunk<T>(name, out var chunk))
|
||||
if (db.Chunks.TryGetValue(name, out var rawChunk))
|
||||
{
|
||||
throw new ArgumentException($"No chunk with name ({name}) found", nameof(name));
|
||||
}
|
||||
|
||||
if (gam != null && gam.TryGetChunk<T>(name, out var gamChunk))
|
||||
var chunk = (T)rawChunk;
|
||||
if (gam != null && gam.Chunks.TryGetValue(name, out var rawGamChunk))
|
||||
{
|
||||
gamChunk.Merge(chunk);
|
||||
return gamChunk;
|
||||
var gamChunk = (T)rawGamChunk;
|
||||
chunk.Merge(gamChunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"No chunk with name ({name}) found", nameof(name));
|
||||
}
|
||||
|
||||
// Add parentages
|
||||
var metaPropLinks = GetMergedChunk<LinkChunk>("L$MetaProp");
|
||||
var metaPropLinkData = GetMergedChunk<LinkDataMetaProp>("LD$MetaProp");
|
||||
|
@ -81,12 +83,11 @@ public class ObjectHierarchy
|
|||
foreach (var prop in chunk.properties)
|
||||
{
|
||||
var id = prop.objectId;
|
||||
if (!_objects.TryGetValue(id, out var value))
|
||||
if (!_objects.ContainsKey(id))
|
||||
{
|
||||
value = new DarkObject(id);
|
||||
_objects.Add(id, value);
|
||||
_objects.Add(id, new DarkObject(id));
|
||||
}
|
||||
value.properties.TryAdd(name, prop);
|
||||
_objects[id].properties.TryAdd(name, prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,14 +99,9 @@ public class ObjectHierarchy
|
|||
AddProp<PropString>("P$OTxtRepr2");
|
||||
AddProp<PropString>("P$OTxtRepr3");
|
||||
AddProp<PropFloat>("P$RenderAlp");
|
||||
AddProp<PropLight>("P$Light");
|
||||
AddProp<PropAnimLight>("P$AnimLight");
|
||||
AddProp<PropLightColor>("P$LightColo");
|
||||
AddProp<PropSpotlight>("P$Spotlight");
|
||||
}
|
||||
|
||||
// TODO: Work out if there's some nice way to automatically decide if we inherit
|
||||
public T? GetProperty<T>(int objectId, string propName, bool inherit = true) where T : Property
|
||||
public T GetProperty<T>(int objectId, string propName) where T : Property
|
||||
{
|
||||
if (!_objects.ContainsKey(objectId))
|
||||
{
|
||||
|
@ -121,7 +117,7 @@ public class ObjectHierarchy
|
|||
}
|
||||
|
||||
var prop = obj.GetProperty<T>(propName);
|
||||
if (prop != null || !inherit)
|
||||
if (prop != null)
|
||||
{
|
||||
return prop;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
@ -13,37 +12,16 @@ public static class Extensions
|
|||
return raw * 360 / (ushort.MaxValue + 1);
|
||||
}
|
||||
|
||||
public static void WriteRotation(this BinaryWriter writer, Vector3 rotation)
|
||||
{
|
||||
var raw = rotation * (ushort.MaxValue + 1) / 360;
|
||||
writer.Write((ushort)raw.X);
|
||||
writer.Write((ushort)raw.Y);
|
||||
writer.Write((ushort)raw.Z);
|
||||
}
|
||||
|
||||
public static Vector3 ReadVec3(this BinaryReader reader)
|
||||
{
|
||||
return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static void WriteVec3(this BinaryWriter writer, Vector3 vec)
|
||||
{
|
||||
writer.Write(vec.X);
|
||||
writer.Write(vec.Y);
|
||||
writer.Write(vec.Z);
|
||||
}
|
||||
|
||||
public static Vector2 ReadVec2(this BinaryReader reader)
|
||||
{
|
||||
return new Vector2(reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static void WriteVec2(this BinaryWriter writer, Vector2 vec)
|
||||
{
|
||||
writer.Write(vec.X);
|
||||
writer.Write(vec.Y);
|
||||
}
|
||||
|
||||
public static string ReadNullString(this BinaryReader reader, int length)
|
||||
{
|
||||
var tmpName = Encoding.UTF8.GetString(reader.ReadBytes(length));
|
||||
|
@ -51,12 +29,4 @@ public static class Extensions
|
|||
if (idx >= 0) tmpName = tmpName[..idx];
|
||||
return tmpName;
|
||||
}
|
||||
|
||||
public static void WriteNullString(this BinaryWriter writer, string nullString, int length)
|
||||
{
|
||||
var writeBytes = new byte[length];
|
||||
var stringBytes = Encoding.UTF8.GetBytes(nullString);
|
||||
stringBytes[..Math.Min(length, stringBytes.Length)].CopyTo(writeBytes, 0);
|
||||
writer.Write(writeBytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
@ -93,54 +94,6 @@ public class ModelFile
|
|||
}
|
||||
}
|
||||
|
||||
public struct SubObject
|
||||
{
|
||||
public string Name;
|
||||
public byte Type;
|
||||
public int Joint;
|
||||
public float MinJointValue;
|
||||
public float MaxJointValue;
|
||||
public Matrix4x4 Transform;
|
||||
public short Child;
|
||||
public short Next;
|
||||
public ushort VhotIdx;
|
||||
public ushort VhotCount;
|
||||
public ushort PointIdx;
|
||||
public ushort PointCount;
|
||||
public ushort LightIdx;
|
||||
public ushort LightCount;
|
||||
public ushort NormalIdx;
|
||||
public ushort NormalCount;
|
||||
public ushort NodeIdx;
|
||||
public ushort NodeCount;
|
||||
|
||||
public SubObject(BinaryReader reader)
|
||||
{
|
||||
Name = reader.ReadNullString(8);
|
||||
Type = reader.ReadByte();
|
||||
Joint = reader.ReadInt32();
|
||||
MinJointValue = reader.ReadSingle();
|
||||
MaxJointValue = reader.ReadSingle();
|
||||
var v1 = reader.ReadVec3();
|
||||
var v2 = reader.ReadVec3();
|
||||
var v3 = reader.ReadVec3();
|
||||
var v4 = reader.ReadVec3();
|
||||
Transform = new Matrix4x4(v1.X, v1.Y, v1.Z, 0, v2.X, v2.Y, v2.Z, 0, v3.X, v3.Y, v3.Z, 0, v4.X, v4.Y, v4.Z, 1);
|
||||
Child = reader.ReadInt16();
|
||||
Next = reader.ReadInt16();
|
||||
VhotIdx = reader.ReadUInt16();
|
||||
VhotCount = reader.ReadUInt16();
|
||||
PointIdx = reader.ReadUInt16();
|
||||
PointCount = reader.ReadUInt16();
|
||||
LightIdx = reader.ReadUInt16();
|
||||
LightCount = reader.ReadUInt16();
|
||||
NormalIdx = reader.ReadUInt16();
|
||||
NormalCount = reader.ReadUInt16();
|
||||
NodeIdx = reader.ReadUInt16();
|
||||
NodeCount = reader.ReadUInt16();
|
||||
}
|
||||
}
|
||||
|
||||
public struct Polygon
|
||||
{
|
||||
public ushort Index;
|
||||
|
@ -200,30 +153,6 @@ public class ModelFile
|
|||
}
|
||||
}
|
||||
|
||||
public enum VhotId
|
||||
{
|
||||
LightPosition = 1,
|
||||
LightDirection = 8,
|
||||
Anchor = 2,
|
||||
Particle1 = 3,
|
||||
Particle2 = 4,
|
||||
Particle3 = 5,
|
||||
Particle4 = 6,
|
||||
Particle5 = 7,
|
||||
}
|
||||
|
||||
public struct VHot
|
||||
{
|
||||
public int Id;
|
||||
public Vector3 Position;
|
||||
|
||||
public VHot(BinaryReader reader)
|
||||
{
|
||||
Id = reader.ReadInt32();
|
||||
Position = reader.ReadVec3();
|
||||
}
|
||||
}
|
||||
|
||||
public BHeader BinHeader { get; set; }
|
||||
public MHeader Header { get; set; }
|
||||
public Vector3[] Vertices { get; }
|
||||
|
@ -231,8 +160,6 @@ public class ModelFile
|
|||
public Vector3[] Normals { get; }
|
||||
public Polygon[] Polygons { get; }
|
||||
public Material[] Materials { get; }
|
||||
public VHot[] VHots { get; }
|
||||
public SubObject[] Objects { get; }
|
||||
|
||||
public ModelFile(string filename)
|
||||
{
|
||||
|
@ -275,31 +202,5 @@ public class ModelFile
|
|||
{
|
||||
Materials[i] = new Material(reader);
|
||||
}
|
||||
stream.Seek(Header.VHotOffset, SeekOrigin.Begin);
|
||||
VHots = new VHot[Header.VHotCount];
|
||||
for (var i = 0; i < VHots.Length; i++)
|
||||
{
|
||||
VHots[i] = new VHot(reader);
|
||||
}
|
||||
stream.Seek(Header.ObjectOffset, SeekOrigin.Begin);
|
||||
Objects = new SubObject[Header.ObjectCount];
|
||||
for (var i = 0; i < Objects.Length; i++)
|
||||
{
|
||||
Objects[i] = new SubObject(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetVhot(VhotId id, out VHot vhot)
|
||||
{
|
||||
foreach (var v in VHots)
|
||||
{
|
||||
if (v.Id == (int)id)
|
||||
{
|
||||
vhot = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
vhot = new VHot();
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -261,17 +261,16 @@ public partial class Mission : Node3D
|
|||
var pos = brush.position.ToGodotVec3();
|
||||
var rot = brush.angle.ToGodotVec3(false);
|
||||
var scale = scaleProp == null ? Vector3.One : scaleProp.value.ToGodotVec3(false);
|
||||
var meshDetails = Timing.TimeStage("Get Models", () => Context.Instance.ModelLoader.Load(modelName));
|
||||
if (meshDetails.Length != 0)
|
||||
var model = Timing.TimeStage("Get Models", () =>
|
||||
{
|
||||
return Context.Instance.ModelLoader.Load(modelName);
|
||||
});
|
||||
if (model != null)
|
||||
{
|
||||
var model = new Node3D();
|
||||
model.Position = pos;
|
||||
model.RotationDegrees = rot;
|
||||
model.Scale = scale;
|
||||
|
||||
// TODO: Apply real joints
|
||||
var meshes = ModelLoader.TransformMeshes([45, 180, 0, 0, 0, 0], meshDetails);
|
||||
|
||||
bool GetTextReplPath(PropString prop, out string path)
|
||||
{
|
||||
path = "";
|
||||
|
@ -300,8 +299,6 @@ public partial class Mission : Node3D
|
|||
}
|
||||
|
||||
var repls = new PropString[] { txtRepl0, txtRepl1, txtRepl2, txtRepl3 };
|
||||
foreach (var meshInstance in meshes)
|
||||
{
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
if (GetTextReplPath(repls[i], out var path))
|
||||
|
@ -312,13 +309,13 @@ public partial class Mission : Node3D
|
|||
Transparency = BaseMaterial3D.TransparencyEnum.AlphaDepthPrePass,
|
||||
};
|
||||
|
||||
var surfaceCount = meshInstance.Mesh.GetSurfaceCount();
|
||||
var surfaceCount = model.Mesh.GetSurfaceCount();
|
||||
for (var idx = 0; idx < surfaceCount; idx++)
|
||||
{
|
||||
var surfaceMat = meshInstance.Mesh.SurfaceGetMaterial(idx);
|
||||
var surfaceMat = model.Mesh.SurfaceGetMaterial(idx);
|
||||
if (surfaceMat.HasMeta($"TxtRepl{i}"))
|
||||
{
|
||||
meshInstance.SetSurfaceOverrideMaterial(idx, overrideMat);
|
||||
model.SetSurfaceOverrideMaterial(idx, overrideMat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,10 +323,7 @@ public partial class Mission : Node3D
|
|||
|
||||
if (renderAlpha != null)
|
||||
{
|
||||
meshInstance.Transparency = 1.0f - renderAlpha.value;
|
||||
}
|
||||
|
||||
model.AddChild(meshInstance);
|
||||
model.Transparency = 1.0f - renderAlpha.value;
|
||||
}
|
||||
|
||||
model.AddToGroup(OBJECT_MODELS_GROUP);
|
||||
|
|
|
@ -19,13 +19,7 @@ public partial class Model : Node3D
|
|||
}
|
||||
|
||||
Context.Instance.SetCampaign(campaignName);
|
||||
var model = new Node3D();
|
||||
var meshDetails = Context.Instance.ModelLoader.Load(modelPath);
|
||||
var meshes = ModelLoader.TransformMeshes([0, 0, 0, 0, 0, 0], meshDetails);
|
||||
foreach (var meshInstance in meshes)
|
||||
{
|
||||
model.AddChild(meshInstance);
|
||||
}
|
||||
var model = Context.Instance.ModelLoader.Load(modelPath);
|
||||
AddChild(model);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,16 +8,9 @@ namespace KeepersCompound.TMV;
|
|||
// TODO: Work out a way to share base game models again in the cache
|
||||
public class ModelLoader
|
||||
{
|
||||
public struct MeshDetails(int jointIdx, Transform3D transform, MeshInstance3D mesh)
|
||||
{
|
||||
public readonly int JointIdx = jointIdx;
|
||||
public readonly Transform3D Transform = transform;
|
||||
public readonly MeshInstance3D Mesh = mesh;
|
||||
}
|
||||
private readonly Dictionary<(string, string), MeshInstance3D> _cache = new();
|
||||
|
||||
private readonly Dictionary<(string, string), MeshDetails[]> _cache = new();
|
||||
|
||||
public MeshDetails[] Load(string modelName, bool forceLoad = false)
|
||||
public MeshInstance3D Load(string modelName, bool forceLoad = false)
|
||||
{
|
||||
var campaignResources = Context.Instance.CampaignResources;
|
||||
var campaignName = campaignResources.name;
|
||||
|
@ -25,60 +18,36 @@ public class ModelLoader
|
|||
|
||||
if (!forceLoad)
|
||||
{
|
||||
if (_cache.TryGetValue((campaignName, modelName), out var fmDetails))
|
||||
if (_cache.TryGetValue((campaignName, modelName), out var fmModel))
|
||||
{
|
||||
return fmDetails;
|
||||
return fmModel?.Duplicate() as MeshInstance3D;
|
||||
}
|
||||
if (_cache.TryGetValue(("", modelName), out var omDetails))
|
||||
else if (_cache.TryGetValue(("", modelName), out var omModel))
|
||||
{
|
||||
return omDetails;
|
||||
return omModel?.Duplicate() as MeshInstance3D;
|
||||
}
|
||||
}
|
||||
|
||||
var details = Timing.TimeStage("Load Models", () => LoadModel(modelName));
|
||||
_cache[(campaignName, modelName)] = details;
|
||||
return details;
|
||||
// We don't care if this is null actually, we'll still cache that it's null lol
|
||||
var model = Timing.TimeStage("Load Models", () => { return LoadModel(modelName); });
|
||||
_cache[(campaignName, modelName)] = model;
|
||||
return model?.Duplicate() as MeshInstance3D;
|
||||
}
|
||||
|
||||
public static MeshInstance3D[] TransformMeshes(float[] joints, MeshDetails[] meshDetails)
|
||||
{
|
||||
var meshes = new List<MeshInstance3D>();
|
||||
foreach (var details in meshDetails)
|
||||
{
|
||||
var mesh = details.Mesh.Duplicate() as MeshInstance3D;
|
||||
if (details.JointIdx != -1)
|
||||
{
|
||||
var ang = float.DegreesToRadians(joints[details.JointIdx]);
|
||||
var r1 = new Quaternion(new Vector3(0, 0, 1), ang);
|
||||
var r2 = details.Transform.Basis.GetRotationQuaternion();
|
||||
var basis = new Basis(r2 * r1);
|
||||
mesh.SetTransform(new Transform3D(basis, details.Transform.Origin));
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh.SetTransform(details.Transform);
|
||||
}
|
||||
|
||||
meshes.Add(mesh);
|
||||
}
|
||||
|
||||
return [..meshes];
|
||||
}
|
||||
|
||||
public static MeshDetails[] LoadModel(string modelName)
|
||||
public static MeshInstance3D LoadModel(string modelName)
|
||||
{
|
||||
var campaignResources = Context.Instance.CampaignResources;
|
||||
var modelPath = campaignResources.GetResourcePath(ResourceType.Object, modelName);
|
||||
if (modelPath == null)
|
||||
{
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
|
||||
var modelFile = new ModelFile(modelPath);
|
||||
if (modelFile == null)
|
||||
{
|
||||
GD.Print($"Failed to load model file: {modelPath}");
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
|
||||
var materials = new List<StandardMaterial3D>();
|
||||
|
@ -125,32 +94,19 @@ public class ModelLoader
|
|||
}
|
||||
}
|
||||
|
||||
var objCount = modelFile.Objects.Length;
|
||||
var meshDetails = new MeshDetails[objCount];
|
||||
for (var i = 0; i < objCount; i++)
|
||||
{
|
||||
var subObj = modelFile.Objects[i];
|
||||
var jointIdx = subObj.Joint;
|
||||
var transform = subObj.Type == 0 ? Transform3D.Identity : subObj.Transform.ToGodotTransform3D();
|
||||
var surfaceDataMap = new Dictionary<int, MeshSurfaceData>();
|
||||
foreach (var poly in modelFile.Polygons)
|
||||
{
|
||||
var v0 = poly.VertexIndices[0];
|
||||
if (v0 < subObj.PointIdx || v0 >= subObj.PointIdx + subObj.PointCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var vertices = new List<Vector3>();
|
||||
var normal = modelFile.Normals[poly.Normal].ToGodotVec3();
|
||||
var uvs = new List<Vector2>();
|
||||
for (var j = 0; j < poly.VertexCount; j++)
|
||||
for (var i = 0; i < poly.VertexCount; i++)
|
||||
{
|
||||
var vertex = modelFile.Vertices[poly.VertexIndices[j]];
|
||||
var vertex = modelFile.Vertices[poly.VertexIndices[i]];
|
||||
vertices.Add(vertex.ToGodotVec3());
|
||||
if (j < poly.UvIndices.Length)
|
||||
if (i < poly.UvIndices.Length)
|
||||
{
|
||||
var uv = modelFile.Uvs[poly.UvIndices[j]];
|
||||
var uv = modelFile.Uvs[poly.UvIndices[i]];
|
||||
uvs.Add(new Vector2(uv.X, uv.Y));
|
||||
}
|
||||
else
|
||||
|
@ -173,12 +129,12 @@ public class ModelLoader
|
|||
var array = surfaceData.BuildSurfaceArray();
|
||||
var surfaceIdx = mesh.GetSurfaceCount();
|
||||
mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, array);
|
||||
for (var j = 0; j < materials.Count; j++)
|
||||
for (var i = 0; i < materials.Count; i++)
|
||||
{
|
||||
var m = modelFile.Materials[j];
|
||||
var m = modelFile.Materials[i];
|
||||
if (m.Slot == materialId)
|
||||
{
|
||||
mesh.SurfaceSetMaterial(surfaceIdx, materials[j]);
|
||||
mesh.SurfaceSetMaterial(surfaceIdx, materials[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -186,9 +142,6 @@ public class ModelLoader
|
|||
|
||||
var pos = -modelFile.Header.Center.ToGodotVec3();
|
||||
var meshInstance = new MeshInstance3D { Mesh = mesh, Position = pos };
|
||||
meshDetails[i] = new MeshDetails(jointIdx, transform, meshInstance);
|
||||
}
|
||||
|
||||
return meshDetails;
|
||||
return meshInstance;
|
||||
}
|
||||
}
|
|
@ -9,10 +9,4 @@ public static class Utils
|
|||
{
|
||||
return new Godot.Vector3(vec.Y, vec.Z, vec.X) / (scale ? InverseScale : 1.0f);
|
||||
}
|
||||
|
||||
public static Godot.Transform3D ToGodotTransform3D(this Matrix4x4 mat, bool scale = true)
|
||||
{
|
||||
var t = mat.Translation / (scale ? InverseScale : 1.0f);
|
||||
return new Godot.Transform3D(mat.M22, mat.M21, mat.M23, mat.M31, mat.M33, mat.M32, mat.M12, mat.M13, mat.M11, t.Y, t.Z, t.X);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
[ext_resource type="Texture2D" uid="uid://bfswg75r148mr" path="res://project/assets/icons/ActionCopy.svg" id="7_2pq2g"]
|
||||
|
||||
[node name="AssetBrowser" type="Control"]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
@ -21,10 +22,9 @@ size_flags_vertical = 3
|
|||
script = ExtResource("1_5rr8c")
|
||||
|
||||
[node name="TabContainer" type="TabContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
layout_mode = 2
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 648.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
current_tab = 0
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://boxi211q3kx6c"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://boxi211q3kx6c"]
|
||||
|
||||
[ext_resource type="Script" path="res://project/code/TMV/Mission.cs" id="1_3gnqe"]
|
||||
[ext_resource type="Script" path="res://project/code/camera.gd" id="2_w5otl"]
|
||||
[ext_resource type="PackedScene" uid="uid://bfxdpxkcgwlkx" path="res://project/scenes/ui/resource_selector.tscn" id="3_kdn7u"]
|
||||
[ext_resource type="PackedScene" uid="uid://byknmqac1a5vn" path="res://project/scenes/asset_browser/asset_browser.tscn" id="3_noiti"]
|
||||
[ext_resource type="PackedScene" uid="uid://0h2w7w84vbea" path="res://project/scenes/ui/lightmap_layer_toggler.tscn" id="4_naip8"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment_cckyk"]
|
||||
|
@ -28,5 +29,7 @@ unique_name_in_owner = true
|
|||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="AssetBrowser" parent="UI" instance=ExtResource("3_noiti")]
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_cckyk")
|
||||
|
|
Loading…
Reference in New Issue