using CodeWalker.Core.Utils; using CodeWalker.GameFiles; using SharpDX; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace CodeWalker.World { public class Water { public volatile bool Inited = false; public GameFileCache GameFileCache; public List WaterQuads = new List(); public List CalmingQuads = new List(); public List WaveQuads = new List(); public void Init(GameFileCache gameFileCache, Action updateStatus) { using var _ = new DisposableTimer("Water Init"); GameFileCache = gameFileCache; var rpfman = gameFileCache.RpfMan; string filename = "common.rpf\\data\\levels\\gta5\\water.xml"; XmlDocument waterxml = rpfman.GetFileXml(filename); XmlElement? waterdata = waterxml.DocumentElement; XmlNodeList? waterquads = waterdata.SelectNodes("WaterQuads/Item"); WaterQuads.Clear(); WaterQuads.EnsureCapacity(waterquads.Count); for (int i = 0; i < waterquads.Count; i++) { var waterquad = new WaterQuad(); waterquad.Init(waterquads[i], i); WaterQuads.Add(waterquad); } XmlNodeList? calmingquads = waterdata.SelectNodes("CalmingQuads/Item"); CalmingQuads.Clear(); CalmingQuads.EnsureCapacity(calmingquads.Count); for (int i = 0; i < calmingquads.Count; i++) { var calmingquad = new WaterCalmingQuad(); calmingquad.Init(calmingquads[i], i); CalmingQuads.Add(calmingquad); } XmlNodeList? wavequads = waterdata.SelectNodes("WaveQuads/Item"); WaveQuads.Clear(); WaveQuads.EnsureCapacity(wavequads.Count); for (int i = 0; i < wavequads.Count; i++) { var wavequad = new WaterWaveQuad(); wavequad.Init(wavequads[i], i); WaveQuads.Add(wavequad); } Inited = true; } public List GetVisibleQuads(Camera camera, IEnumerable allQuads) where T : BaseWaterQuad { List quads = new List(); if (!Inited) return quads; var vf = camera.ViewFrustum; foreach (var quad in allQuads) { Vector3 camrel = quad.BSCenter - camera.Position; if (vf.ContainsSphereNoClipNoOpt(ref camrel, quad.BSRadius)) { quads.Add(quad); } } return quads; } } public abstract class BaseWaterQuad { public int xmlNodeIndex { get; set; } public float minX { get; set; } public float maxX { get; set; } public float minY { get; set; } public float maxY { get; set; } public float? z { get; set; } = null; public abstract void Init(XmlNode node, int index); public void CalcBS() { BSCenter = new Vector3((minX + maxX) * 0.5f, (minY + maxY) * 0.5f, z ?? 0); BSRadius = new Vector2(maxX - minX, maxY - minY).Length() * 0.5f; } public Vector3 BSCenter { get; private set; } public float BSRadius { get; private set; } public override string ToString() { return $"[{xmlNodeIndex}] X=({minX} : {maxX}), Y=({minY} : {maxY})"; } } public class WaterQuad : BaseWaterQuad { public int Type { get; set; } public bool IsInvisible { get; set; } public bool HasLimitedDepth { get; set; } public float a1 { get; set; } public float a2 { get; set; } public float a3 { get; set; } public float a4 { get; set; } public bool NoStencil { get; set; } public override void Init(XmlNode node, int index) { xmlNodeIndex = index; minX = Xml.GetChildFloatAttribute(node, "minX", "value"); maxX = Xml.GetChildFloatAttribute(node, "maxX", "value"); minY = Xml.GetChildFloatAttribute(node, "minY", "value"); maxY = Xml.GetChildFloatAttribute(node, "maxY", "value"); Type = Xml.GetChildIntAttribute(node, "Type", "value"); IsInvisible = Xml.GetChildBoolAttribute(node, "IsInvisible", "value"); HasLimitedDepth = Xml.GetChildBoolAttribute(node, "HasLimitedDepth", "value"); z = Xml.GetChildFloatAttribute(node, "z", "value"); a1 = Xml.GetChildFloatAttribute(node, "a1", "value"); a2 = Xml.GetChildFloatAttribute(node, "a2", "value"); a3 = Xml.GetChildFloatAttribute(node, "a3", "value"); a4 = Xml.GetChildFloatAttribute(node, "a4", "value"); NoStencil = Xml.GetChildBoolAttribute(node, "NoStencil", "value"); /* */ CalcBS(); } } public class WaterCalmingQuad : BaseWaterQuad { public float fDampening { get; set; } public override void Init(XmlNode node, int index) { xmlNodeIndex = index; minX = Xml.GetChildFloatAttribute(node, "minX", "value"); maxX = Xml.GetChildFloatAttribute(node, "maxX", "value"); minY = Xml.GetChildFloatAttribute(node, "minY", "value"); maxY = Xml.GetChildFloatAttribute(node, "maxY", "value"); fDampening = Xml.GetChildFloatAttribute(node, "fDampening", "value"); /* */ CalcBS(); } } public class WaterWaveQuad : BaseWaterQuad { public float Amplitude { get; set; } public float XDirection { get; set; } public float YDirection { get; set; } public Quaternion _WaveOrientation; public ref Quaternion WaveOrientation => ref _WaveOrientation; public override void Init(XmlNode node, int index) { xmlNodeIndex = index; minX = Xml.GetChildFloatAttribute(node, "minX", "value"); maxX = Xml.GetChildFloatAttribute(node, "maxX", "value"); minY = Xml.GetChildFloatAttribute(node, "minY", "value"); maxY = Xml.GetChildFloatAttribute(node, "maxY", "value"); Amplitude = Xml.GetChildFloatAttribute(node, "Amplitude", "value"); XDirection = Xml.GetChildFloatAttribute(node, "XDirection", "value"); YDirection = Xml.GetChildFloatAttribute(node, "YDirection", "value"); float angl = (float)Math.Atan2(YDirection, XDirection); Quaternion.RotationYawPitchRoll(0.0f, 0.0f, angl, out WaveOrientation); /* */ CalcBS(); } } }