Skip to content

Commit

Permalink
Grass is now rendered
Browse files Browse the repository at this point in the history
  • Loading branch information
Foxxyyy committed Jul 17, 2024
1 parent 4f6b1ce commit 5cf5509
Show file tree
Hide file tree
Showing 14 changed files with 53 additions and 211 deletions.
4 changes: 3 additions & 1 deletion RDR1Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ public override Setting[] GetMapSettings()
RDR1Map.LoadBoundsSetting,
RDR1Map.EnabledSetting,
RDR1Map.EnableTreesSetting,
RDR1Map.EnableInstancedGrass,
RDR1Map.EnablePropsSetting,
RDR1Map.EnableLightsSetting,
RDR1Map.TreesDistanceSetting
RDR1Map.TreesDistanceSetting,
RDR1Map.GrassDistanceSetting
};
}

Expand Down
166 changes: 23 additions & 143 deletions RDR1Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class RDR1Map : StreamingLevel<RDR1Game, RDR1MapFileCache, Rpf6FileManage
public List<Rpf6StoreItem> WbdBoundsStore; //Basic data of bounds dictionary to render
public List<Rpf6StoreItem> WtbBoundsStore; //Basic data of tiles collisions to render
public List<TreeItem> Trees; //Basic data of trees, debris, rocks & placed grass
public HashSet<Entity> GrassBatchs; //The grass batches //TODO:

public Dictionary<JenkHash, RDR1MapNode> MapNodeDict;
public StreamingSet<RDR1MapNode> StreamNodes;
Expand All @@ -31,8 +30,11 @@ public class RDR1Map : StreamingLevel<RDR1Game, RDR1MapFileCache, Rpf6FileManage
public static readonly Setting EnabledSetting = Settings.Register("RDR1Map.Enabled", SettingType.Bool, true, true);
public static readonly Setting EnableTreesSetting = Settings.Register("RDR1Map.EnableTrees", SettingType.Bool, true);
public static readonly Setting EnablePropsSetting = Settings.Register("RDR1Map.EnableProps", SettingType.Bool, true);
public static readonly Setting EnableInstancedGrass = Settings.Register("RDR1Map.EnableInstancedGrass", SettingType.Bool, true);
public static readonly Setting EnableLightsSetting = Settings.Register("RDR1Map.EnableLights", SettingType.Bool, false);

public static readonly Setting TreesDistanceSetting = Settings.Register("RDR1Map.TreesDistance", SettingType.Float, 100.0f, false);
public static readonly Setting GrassDistanceSetting = Settings.Register("RDR1Map.GrassDistance", SettingType.Float, 50.0f, false);

public Statistic NodeCountStat = Statistics.Register("RDR1Map.NodeCount", StatisticType.Counter);
public Statistic EntityCountStat = Statistics.Register("RDR1Map.EntityCount", StatisticType.Counter);
Expand Down Expand Up @@ -183,7 +185,7 @@ protected override bool StreamingUpdate()
this.StreamBVH.BeginIteration();
this.StreamBVH.AddStreamPosition(spos);


foreach (var node in this.StreamBVH.StreamItems.Cast<RDR1MapNode>())
{
var n = node;
Expand All @@ -196,42 +198,20 @@ protected override bool StreamingUpdate()
}
}

/*if (this.GrassBatchs != null) //Grass batches
{
foreach (var batch in this.GrassBatchs)
{
RecurseAddStreamEntity((WsiEntity)batch, ref spos, ents);
}
}
foreach (var wsg in this.FileManager.DataFileMgr.WsgFiles)
if (EnableInstancedGrass.GetBool())
{
foreach (var item in wsg.Value.GrassField.GrassItems.Items)
foreach (var wsg in this.FileManager.DataFileMgr.WsgFiles)
{
if (Vector3.Distance(item.GetFieldCenter().XYZ(), StreamPosition) > 50.0f) continue;
if (item.VertexBuffer.Item == null) continue;
item.GrassEntities = new List<RDR1GrassEntity>();
var data = item.VertexBuffer.Item.VertexData.Items;
var aabbScale = item.AABBScale.XYZ();
var aabbOffset = item.AABBOffset.XYZ();
var itemName = item.Name.ToString();
using var br = new BinaryReader(new MemoryStream(data));
int length = data.Length;
for (int i = 0; i < length; i += 4)
foreach (var item in wsg.Value.GrassField.GrassItems.Items)
{
var value = br.ReadUInt32();
var color = new Colour(value);
color = new Colour(color.B, color.R, color.G, color.A);
var scaledPos = Vector3.Multiply(aabbScale, color.ToVector4().XYZ());
var loc = aabbOffset + scaledPos;
var ent = new RDR1GrassEntity(itemName, loc);
ents.Add(ent);
if (Vector3.Distance(item.GetAABB().Center, StreamPosition) > 50.0f) continue;
foreach (var grassPos in item.GrassPositions)
{
ents.Add(new RDR1GrassEntity(item.Name.ToString(), GrassDistanceSetting.GetFloat(), grassPos));
}
}
}
}
*/

foreach (var node in nodes) //Find current entities for max lod level
{
Expand Down Expand Up @@ -387,23 +367,6 @@ protected override bool StreamingUpdate()

private static void RecurseAddStreamEntity(Entity e, ref Vector3 spos, HashSet<Entity> ents)
{
if (e.Batch != null)
{
var d = (e.Position - spos).Length();
if (d > e.LodDistMax) return;
e.StreamingDistance = (e.Batch.Lods == null) ? 1000.0f : d;

if (e.Batch.Lods == null)
{
if (e.BoundingBox.Contains(ref spos) == ContainmentType.Contains)
{
e.StreamingDistance = 0.0f;
}
}
ents.Add(e);
return;
}

e.StreamingDistance = (e.Position - spos).Length();
if (e.BoundingBox.Contains(ref spos) == ContainmentType.Contains)
{
Expand Down Expand Up @@ -547,93 +510,6 @@ public override void GetAssets(uint typeHash, List<Asset> assets)
}
}

public class RDR1GrassBatch : WsiEntity
{
public float CellSize;
public sbyte GridSizeX;
public sbyte GridSizeY;
public string GrassFieldName;

public RDR1GrassBatch(Rsc6GrassField field, Level level)
{
if (field == null) return;
SetFieldBatch(field);

Level = level;
GrassFieldName = field.Name.Value;

var b = new EntityBatch(this)
{
InstanceCount = field.Batchs.Count,
InstanceLayout = 3,
InstanceScaleParams = field.AABBScale,
InstanceBatchMin = field.AABBMin,
InstanceBatchSize = field.GetAABBSize(),
Data = field.BatchData
};

var bbs = field.GetAABBSize();
var csx = bbs.X / 32;
var csy = bbs.Y / 32;

var x = (sbyte)(bbs.X > 127 ? 127 : Math.Abs((sbyte)bbs.X));
var y = (sbyte)(bbs.Y > 127 ? 127 : Math.Abs((sbyte)bbs.Y));

if (csx >= csy)
{
CellSize = csx;
GridSizeX = x;
GridSizeY = y;
}
else
{
CellSize = csy;
GridSizeY = x;
GridSizeX = y;
}

b.InitGrid(GridSizeX, GridSizeY, CellSize);
SetBatch(b);
}

protected Entity CreateBatchLodEntity(EntityBatchLod lod, Piece p, int pieceLod)
{
var e = new Entity
{
Level = Level,
Piece = p,
Name = GrassFieldName,
PieceLodOverride = pieceLod,
CurrentDistance = lod.LodDist,
BoundingBox = BoundingBox,
BoundingSphere = BoundingSphere,
Position = BoundingBox.Center,
Orientation = Quaternion.Identity,
Scale = Vector3.One,
ParentIndex = -1
};
e.SetBatchLod(lod);
e.UpdateWorldTransform();
return e;
}

public override void SetPiece(Piece p)
{
var changed = p != Piece;
base.SetPiece(p);

if (changed)
{
if ((Batch?.Grid != null) && (p is Rsc6Drawable d))
{
var hdist = d.LodDistHigh;
Batch.InitLods(hdist);
Batch.Lods[0].RenderEntity = CreateBatchLodEntity(Batch.Lods[0], p, 0);
}
}
}
}

public class RDR1MapNode : StreamingBVHItem
{
public BoundingBox StreamingBox { get; set; }
Expand Down Expand Up @@ -790,26 +666,30 @@ public RDR1MapData(WsiFile wsi, bool swTerrain = false)
var drawableInstances = sector.DrawableInstances.Items;
if (drawableInstances != null && drawableInstances.Length > 0)
{
var ident = Matrix4x4.Identity;
ident.M44 = 0.0f;

foreach (var instance in drawableInstances)
{
if (instance.Name.ToString().ToLower() == name)
{
continue;
}

var ident = Matrix4x4.Identity;
ident.M44 = 0.0f;
var global = instance.Matrix.Equals(ident);
var bb = new BoundingBox(instance.BoundingBoxMin.XYZ(), instance.BoundingBoxMax.XYZ());

var e = new WsiEntity(instance)
{
Index = Entities.Count,
ParentName = name,
Level = this,
ResetPos = global,
Position = global ? bb.Center : new Vector3()
};

var isIdent = instance.Matrix.Equals(ident);
if (isIdent)
{
var bb = new BoundingBox(instance.BoundingBoxMin.XYZ(), instance.BoundingBoxMax.XYZ());
e.Position = bb.Center;
e.ResetPos = true;
}
this.Add(e);
}
}
Expand Down
4 changes: 0 additions & 4 deletions RPF6/Rpf6FileManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,9 @@ public override void InitArchivesComplete()
private void InitGameFiles()
{
Core.Engine.Console.Write("RDR1.InitGameFiles", "Initialising RDR1...");

Rsc6BoundsMaterialTypes.Init(this);
Rsc6GrassManager.Init(this);

DataFileMgr ??= new Rpf6DataFileMgr(this);
DataFileMgr.Init();

Core.Engine.Console.Write("RDR1.InitGameFiles", "RDR1 Initialised.");
}

Expand Down
81 changes: 22 additions & 59 deletions RSC6/Rsc6SectorGrass.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Numerics;
using System.Collections.Generic;
using CodeX.Core.Engine;
using CodeX.Core.Numerics;
using CodeX.Core.Utilities;
using CodeX.Games.RDR1.RPF6;
using System.IO;

namespace CodeX.Games.RDR1.RSC6
{
Expand Down Expand Up @@ -59,7 +57,7 @@ public class Rsc6GrassField : Rsc6BlockBase, MetaNode //rage::grassField
public Vector4 AABBMax { get; set; } //m_aabbMax
public Vector4 AABBMin { get; set; } //m_aabbMin
public Vector4 AABBScale { get; set; } //m_aabbScale
public Vector4 AABBOffset { get; set; } //m_aabbOffset, same as m_aabbMin but with W as number of patches per field
public Vector4 AABBOffset { get; set; } //m_aabbOffset, same as m_aabbMin but with W as 'offset fade'
public Rsc6Ptr<Rsc6TexPlacementValues> TexPlacement { get; set; } //m_tp, texPlacementValues, always NULL
public Rsc6Ptr<Rsc6VertexDeclaration> Layout { get; set; } //m_VertexDeclaration, always NULL
public Rsc6Ptr<Rsc6VertexBuffer> VertexBuffer { get; set; } //m_VertexBuffer
Expand All @@ -71,10 +69,7 @@ public class Rsc6GrassField : Rsc6BlockBase, MetaNode //rage::grassField
public ushort NameLength2 { get; set; } //Name length + 1 (null terminator)
public JenkHash NameHash { get; set; } //m_TypeHash
public uint Unknown_6Ch { get; set; } = 0xCDCDCDCD; //m_Pad1

public List<EntityBatchInstance3> Batchs { get; set; }
public byte[] BatchData { get; set; }
public List<RDR1GrassEntity> GrassEntities { get; set; }
public List<Vector3> GrassPositions { get; set; }

public override void Read(Rsc6DataReader reader)
{
Expand All @@ -94,6 +89,24 @@ public override void Read(Rsc6DataReader reader)
NameLength2 = reader.ReadUInt16();
NameHash = reader.ReadUInt32();
Unknown_6Ch = reader.ReadUInt32();

if (VertexBuffer.Item != null)
{
GrassPositions = new List<Vector3>();
var data = VertexBuffer.Item.VertexData.Items;
var br = new BinaryReader(new MemoryStream(data));

for (int i = 0; i < data.Length; i += 4)
{
var value = br.ReadUInt32();
var color = new Colour(value);
color = new Colour(color.R, color.B, color.G, color.A);

var scaledPos = Vector3.Multiply(AABBScale.XYZ(), color.ToVector4().XYZ());
var loc = AABBMin.XYZ() + scaledPos;
GrassPositions.Add(loc);
}
}
}

public override void Write(Rsc6DataWriter writer)
Expand Down Expand Up @@ -186,30 +199,11 @@ public void Write(MetaNodeWriter writer)
}
}

public Vector4 GetFieldCenter()
{
var center = AABBMin + AABBMax;
return center * 0.5f;
}

public BoundingBox GetAABB()
{
return new BoundingBox(AABBMin.XYZ(), AABBMax.XYZ());
}

public Vector4 GetAABBSize()
{
return new Vector4(GetAABB().Size, 0.0f);
}

public void SetBounds(Vector4 min, Vector4 max)
{
AABBMin = min;
AABBMax = max;
AABBScale = new Vector4(AABBMax.XYZ() - AABBMin.XYZ(), 0.0f);
AABBOffset = new Vector4(AABBMin.XYZ(), 16000.0f);
}

public override string ToString()
{
return Name.Value;
Expand Down Expand Up @@ -254,35 +248,4 @@ public void Write(MetaNodeWriter writer)
writer.WriteUInt32Array("Colors", Colors.Items);
}
}

public static class Rsc6GrassManager
{
public static List<Rsc6Texture> Textures;

public static void Init(Rpf6FileManager fman)
{
if (fman.AllArchives.Count == 0)
{
return;
}

Core.Engine.Console.Write("Rsc6GrassManager", "Initialising grass manager...");
var textures = new List<Rsc6Texture>();
var rpf = fman.AllArchives.FirstOrDefault(e => e.Name == "grassres.rpf");
var entries = rpf.AllEntries.Where(e => e.Name.EndsWith(".wtd")).ToList();

if (entries != null)
{
foreach (var entry in entries.Cast<Rpf6FileEntry>())
{
var pack = fman.LoadTexturePack(entry);
foreach (var texture in pack.Textures)
{
textures.Add((Rsc6Texture)texture.Value);
}
}
}
Textures = textures;
}
}
}
Loading

0 comments on commit 5cf5509

Please sign in to comment.