Initial commit
This commit is contained in:
306
C#/CodeWalker.Core/World/AudioZones.cs
Normal file
306
C#/CodeWalker.Core/World/AudioZones.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class AudioZones
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
public GameFileCache GameFileCache;
|
||||
|
||||
public List<AudioPlacement> Zones = new List<AudioPlacement>();
|
||||
public List<AudioPlacement> Emitters = new List<AudioPlacement>();
|
||||
public List<AudioPlacement> AllItems = new List<AudioPlacement>();
|
||||
|
||||
public Dictionary<RelFile, AudioPlacement[]> PlacementsDict = new Dictionary<RelFile, AudioPlacement[]>();
|
||||
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
Inited = false;
|
||||
|
||||
GameFileCache = gameFileCache;
|
||||
|
||||
Zones.Clear();
|
||||
Emitters.Clear();
|
||||
AllItems.Clear();
|
||||
|
||||
|
||||
List<AudioPlacement> placements = new List<AudioPlacement>();
|
||||
|
||||
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
||||
{
|
||||
if (relfile == null) continue;
|
||||
|
||||
placements.Clear();
|
||||
|
||||
CreatePlacements(relfile, placements, true);
|
||||
|
||||
PlacementsDict[relfile] = placements.ToArray();
|
||||
}
|
||||
|
||||
AllItems.AddRange(Zones);
|
||||
AllItems.AddRange(Emitters);
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
|
||||
private void CreatePlacements(RelFile relfile, List<AudioPlacement> placements, bool addtoLists = false)
|
||||
{
|
||||
foreach (var reldata in relfile.RelDatas)
|
||||
{
|
||||
AudioPlacement placement = null;
|
||||
if (reldata is Dat151AmbientZone)
|
||||
{
|
||||
placement = new AudioPlacement(relfile, reldata as Dat151AmbientZone);
|
||||
if (addtoLists) Zones.Add(placement);
|
||||
}
|
||||
else if (reldata is Dat151AmbientRule)
|
||||
{
|
||||
placement = new AudioPlacement(relfile, reldata as Dat151AmbientRule);
|
||||
if (addtoLists) Emitters.Add(placement);
|
||||
}
|
||||
if (placement != null)
|
||||
{
|
||||
placements.Add(placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void GetPlacements(List<RelFile> relfiles, List<AudioPlacement> placements)
|
||||
{
|
||||
|
||||
foreach (var relfile in relfiles)
|
||||
{
|
||||
AudioPlacement[] fileplacements = null;
|
||||
if (!PlacementsDict.TryGetValue(relfile, out fileplacements))
|
||||
{
|
||||
List<AudioPlacement> newplacements = new List<AudioPlacement>();
|
||||
CreatePlacements(relfile, newplacements);
|
||||
fileplacements = newplacements.ToArray();
|
||||
PlacementsDict[relfile] = fileplacements;
|
||||
}
|
||||
if (fileplacements != null)
|
||||
{
|
||||
placements.AddRange(fileplacements);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class AudioPlacement
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public MetaHash NameHash { get; set; }
|
||||
public RelFile RelFile { get; set; }
|
||||
public Dat151AmbientZone AudioZone { get; set; }
|
||||
public Dat151AmbientRule AudioEmitter { get; set; }
|
||||
public Dat151ZoneShape Shape { get; set; }
|
||||
public string ShortTypeName { get; set; }
|
||||
public string FullTypeName { get; set; }
|
||||
public Vector3 InnerPos { get; set; }
|
||||
public Vector3 InnerMin { get; set; }
|
||||
public Vector3 InnerMax { get; set; }
|
||||
public float InnerRad { get; set; }
|
||||
public Quaternion InnerOri { get; set; }
|
||||
public Vector3 OuterPos { get; set; }
|
||||
public Vector3 OuterMin { get; set; }
|
||||
public Vector3 OuterMax { get; set; }
|
||||
public float OuterRad { get; set; }
|
||||
public Quaternion OuterOri { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 HitboxMin { get; set; }
|
||||
public Vector3 HitboxMax { get; set; }
|
||||
public Quaternion Orientation { get; set; }
|
||||
public Quaternion OrientationInv { get; set; }
|
||||
public float HitSphereRad { get; set; }
|
||||
|
||||
|
||||
public AudioPlacement(RelFile rel, Dat151AmbientZone zone)
|
||||
{
|
||||
RelFile = rel;
|
||||
AudioZone = zone;
|
||||
ShortTypeName = "AudioZone";
|
||||
FullTypeName = "Audio Zone";
|
||||
|
||||
UpdateFromZone();
|
||||
}
|
||||
public AudioPlacement(RelFile rel, Dat151AmbientRule emitter)
|
||||
{
|
||||
RelFile = rel;
|
||||
AudioEmitter = emitter;
|
||||
ShortTypeName = "AudioEmitter";
|
||||
FullTypeName = "Audio Emitter";
|
||||
|
||||
UpdateFromEmitter();
|
||||
}
|
||||
|
||||
|
||||
public void UpdateFromZone()
|
||||
{
|
||||
if (AudioZone == null) return;
|
||||
var zone = AudioZone;
|
||||
|
||||
Name = zone.Name;
|
||||
NameHash = zone.NameHash;
|
||||
Shape = zone.Shape;
|
||||
|
||||
float deg2rad = (float)(Math.PI / 180.0);
|
||||
|
||||
switch (zone.Shape)
|
||||
{
|
||||
case Dat151ZoneShape.Box:
|
||||
InnerPos = zone.PlaybackZonePosition;
|
||||
InnerMax = zone.PlaybackZoneSize * 0.5f;
|
||||
InnerMin = -InnerMax;
|
||||
InnerOri = Quaternion.RotationAxis(Vector3.UnitZ, zone.PlaybackZoneAngle * deg2rad);
|
||||
break;
|
||||
case Dat151ZoneShape.Sphere:
|
||||
InnerPos = zone.PlaybackZonePosition;
|
||||
InnerOri = Quaternion.Identity;
|
||||
InnerRad = zone.PlaybackZoneSize.X;
|
||||
OuterRad = zone.ActivationZoneSize.X;
|
||||
break;
|
||||
case Dat151ZoneShape.Line:
|
||||
InnerPos = zone.PlaybackZonePosition;
|
||||
InnerMin = new Vector3(-1.0f, -1.0f, 0.0f);
|
||||
InnerMax = new Vector3(1.0f, 1.0f, (zone.PlaybackZoneSize - zone.PlaybackZonePosition).Length());
|
||||
InnerOri = Quaternion.Invert(Quaternion.LookAtLH(zone.PlaybackZonePosition, zone.PlaybackZoneSize, Vector3.UnitZ));
|
||||
break;
|
||||
}
|
||||
|
||||
OuterPos = zone.ActivationZonePosition;
|
||||
OuterMax = zone.ActivationZoneSize * 0.5f;
|
||||
OuterMin = -OuterMax;
|
||||
OuterOri = Quaternion.RotationAxis(Vector3.UnitZ, zone.ActivationZoneAngle * deg2rad);
|
||||
|
||||
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
|
||||
if (useouter && (zone.Shape != Dat151ZoneShape.Sphere))
|
||||
{ } //not sure what these are yet!
|
||||
Position = useouter ? OuterPos : InnerPos;
|
||||
HitboxMax = useouter ? OuterMax : InnerMax;
|
||||
HitboxMin = useouter ? OuterMin : InnerMin;
|
||||
Orientation = useouter ? OuterOri : InnerOri;
|
||||
OrientationInv = Quaternion.Invert(Orientation);
|
||||
HitSphereRad = InnerRad;
|
||||
if (zone.Shape == Dat151ZoneShape.Sphere)
|
||||
{
|
||||
Position = InnerPos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void UpdateFromEmitter()
|
||||
{
|
||||
if (AudioEmitter == null) return;
|
||||
var emitter = AudioEmitter;
|
||||
|
||||
Name = emitter.Name;
|
||||
NameHash = emitter.NameHash;
|
||||
Shape = Dat151ZoneShape.Sphere;
|
||||
|
||||
Orientation = Quaternion.Identity;
|
||||
OrientationInv = Quaternion.Identity;
|
||||
InnerPos = emitter.Position;
|
||||
OuterPos = InnerPos;
|
||||
InnerRad = emitter.InnerRad;
|
||||
OuterRad = emitter.OuterRad;
|
||||
|
||||
bool useouter = (InnerRad == 0);
|
||||
if (useouter)
|
||||
{
|
||||
InnerRad = 1;
|
||||
}
|
||||
Position = InnerPos;
|
||||
HitSphereRad = InnerRad;// useouter ? OuterRad : InnerRad;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void SetPosition(Vector3 pos)
|
||||
{
|
||||
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
|
||||
Vector3 delta = pos - InnerPos;
|
||||
InnerPos = pos;
|
||||
OuterPos += delta;
|
||||
Position = useouter ? OuterPos : InnerPos;
|
||||
|
||||
if (AudioZone != null)
|
||||
{
|
||||
AudioZone.PlaybackZonePosition = InnerPos;
|
||||
AudioZone.ActivationZonePosition = OuterPos;
|
||||
}
|
||||
if (AudioEmitter != null)
|
||||
{
|
||||
AudioEmitter.Position = InnerPos;
|
||||
}
|
||||
}
|
||||
public void SetOrientation(Quaternion ori)
|
||||
{
|
||||
Orientation = ori;
|
||||
OrientationInv = Quaternion.Invert(ori);
|
||||
|
||||
Vector3 t = ori.Multiply(Vector3.UnitX);
|
||||
float angl = (float)Math.Atan2(t.Y, t.X);
|
||||
while (angl < 0) angl += ((float)Math.PI * 2.0f);
|
||||
float rad2deg = (float)(180.0 / Math.PI);
|
||||
float dangl = angl * rad2deg;
|
||||
uint uangl = (uint)dangl;
|
||||
|
||||
|
||||
if (InnerOri == OuterOri)
|
||||
{
|
||||
InnerOri = Orientation;
|
||||
OuterOri = Orientation;
|
||||
if (AudioZone != null)
|
||||
{
|
||||
AudioZone.PlaybackZoneAngle = uangl;
|
||||
AudioZone.ActivationZoneAngle = uangl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//not sure yet how to allow independent rotation of inner & outer boxes...
|
||||
//maybe only in project window?
|
||||
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
|
||||
if (useouter)
|
||||
{
|
||||
OuterOri = Orientation;
|
||||
if (AudioZone != null)
|
||||
{
|
||||
AudioZone.ActivationZoneAngle = uangl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InnerOri = Orientation;
|
||||
if (AudioZone != null)
|
||||
{
|
||||
AudioZone.PlaybackZoneAngle = uangl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string GetNameString()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Name)) return Name;
|
||||
return NameHash.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
381
C#/CodeWalker.Core/World/Camera.cs
Normal file
381
C#/CodeWalker.Core/World/Camera.cs
Normal file
@@ -0,0 +1,381 @@
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class Camera
|
||||
{
|
||||
public Vector3 TargetRotation = Vector3.Zero;
|
||||
public Vector3 CurrentRotation = Vector3.Zero;
|
||||
public float Smoothness;// 10.0f;//0.15f;
|
||||
public float Sensitivity;// 0.005f;
|
||||
public float TargetDistance = 1.0f;
|
||||
public float CurrentDistance = 1.0f;
|
||||
public float ZoomCurrentTime = 0.0f;
|
||||
public float ZoomTargetTime = 2.0f;
|
||||
public float ZoomVelocity = 0.0f;
|
||||
public float ZoomSpeed = 0.1f;
|
||||
public float Width = 1920.0f;
|
||||
public float Height = 1080.0f;
|
||||
public float FieldOfView;// 1.0f;
|
||||
public float FieldOfViewFactor = 0.5f / (float)Math.Tan(/*FieldOfView*/ 1.0f * 0.5f);
|
||||
public float AspectRatio = 1920.0f / 1080.0f;
|
||||
public float ZNear = 0.01f;
|
||||
public float ZFar = 100000.0f;
|
||||
public Entity FollowEntity = null;
|
||||
public Vector3 LocalLookAt = Vector3.ForwardLH;
|
||||
public float VOffset = 0.0f;
|
||||
public bool UpdateProj = true;
|
||||
public bool IsMapView = false;
|
||||
public bool IsOrthographic = false;
|
||||
public float OrthographicSize = 20.0f;
|
||||
public float OrthographicTargetSize = 20.0f;
|
||||
public Matrix ProjMatrix = Matrix.Identity;
|
||||
public Vector3 Position = Vector3.Zero;
|
||||
public Vector3 UpDirection = Vector3.Up;
|
||||
public Vector3 ViewDirection = Vector3.ForwardLH;
|
||||
public Quaternion ViewQuaternion = Quaternion.Identity;
|
||||
public Quaternion ViewInvQuaternion = Quaternion.Identity;
|
||||
public Matrix ViewMatrix = Matrix.Identity;
|
||||
public Matrix ViewInvMatrix = Matrix.Identity;
|
||||
public Matrix ViewProjMatrix = Matrix.Identity;
|
||||
public Matrix ViewProjInvMatrix = Matrix.Identity;
|
||||
public Frustum ViewFrustum = new Frustum();
|
||||
public Vector3 MouseRayNear = Vector3.Zero;
|
||||
public Vector3 MouseRayFar = Vector3.Zero;
|
||||
public Ray MouseRay;
|
||||
private float MouseX = 0;
|
||||
private float MouseY = 0;
|
||||
private object syncRoot = new object();
|
||||
|
||||
|
||||
public Camera(float smoothness, float sensitivity, float fov)
|
||||
{
|
||||
Smoothness = smoothness;
|
||||
Sensitivity = sensitivity;
|
||||
FieldOfView = fov;
|
||||
FieldOfViewFactor = 0.5f / (float)Math.Tan(FieldOfView * 0.5f);
|
||||
}
|
||||
|
||||
|
||||
public void SetMousePosition(int x, int y)
|
||||
{
|
||||
MouseX = (x / Width) * 2.0f - 1.0f;
|
||||
MouseY = (y / Height) * -2.0f + 1.0f;
|
||||
}
|
||||
|
||||
public void SetFollowEntity(Entity e)
|
||||
{
|
||||
FollowEntity = e;
|
||||
}
|
||||
|
||||
public void Update(float elapsed)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
UpdateFollow(elapsed);
|
||||
if (UpdateProj) UpdateProjMatrix();
|
||||
|
||||
//float mx = (LastMouseX / Width) * 2.0f;
|
||||
//float my = (LastMouseY / Height) * -2.0f;
|
||||
|
||||
////MousedItem = nullptr;
|
||||
////MousedThing = nullptr;
|
||||
////MousedItemSpace = nullptr;
|
||||
|
||||
UpdateProjection();//, mx, my);
|
||||
}
|
||||
}
|
||||
private void UpdateFollow(float elapsed)
|
||||
{
|
||||
const float ythresh = 1.55f;
|
||||
const float nythresh = -1.55f;
|
||||
Vector3 up = Vector3.Up;// new Vector3(0.0f, 1.0f, 0.0f);
|
||||
if (TargetRotation.Y > ythresh) TargetRotation.Y = ythresh;
|
||||
if (TargetRotation.Y < nythresh) TargetRotation.Y = nythresh;
|
||||
float sv = Math.Min(Smoothness * elapsed, 1.0f);
|
||||
CurrentRotation = CurrentRotation + ((TargetRotation - CurrentRotation) * sv);
|
||||
|
||||
if (TargetDistance > 11000.0f) TargetDistance = 11000.0f; //11km max zoom dist
|
||||
if (TargetDistance < 0.0001f) TargetDistance = 0.0001f; //0.1mm min zoom dist...
|
||||
ZoomCurrentTime += elapsed;
|
||||
if (ZoomCurrentTime > ZoomTargetTime) ZoomCurrentTime = ZoomTargetTime;
|
||||
float currentTime = ZoomCurrentTime / ZoomTargetTime;
|
||||
float deltaDist = TargetDistance - CurrentDistance;
|
||||
if (currentTime < 1.0f && deltaDist > 0.0f)
|
||||
{
|
||||
//TODO: when to properly reset ZoomCurrentTime?
|
||||
float y = currentTime*currentTime*currentTime; //powf(currentTime, 3.0f);
|
||||
deltaDist *= y;
|
||||
}
|
||||
CurrentDistance = CurrentDistance + deltaDist * ZoomSpeed;
|
||||
|
||||
if (IsOrthographic || IsMapView)
|
||||
{
|
||||
if (OrthographicTargetSize > 20000.0f) OrthographicTargetSize = 20000.0f;
|
||||
if (OrthographicTargetSize < 1.0f) OrthographicTargetSize = 1.0f;
|
||||
OrthographicSize = OrthographicSize + ((OrthographicTargetSize - OrthographicSize) * sv);
|
||||
UpdateProj = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (IsMapView)
|
||||
{
|
||||
//in map view, need a constant view matrix aligned to XY.
|
||||
|
||||
Vector3 cpos = new Vector3();
|
||||
if (FollowEntity != null)
|
||||
{
|
||||
cpos = FollowEntity.Position;
|
||||
}
|
||||
LocalLookAt = Vector3.Zero;
|
||||
Position = cpos;
|
||||
//Position.Z = 1000.0f;
|
||||
ViewDirection = -Vector3.UnitZ;
|
||||
UpDirection = Vector3.UnitY;
|
||||
}
|
||||
else
|
||||
{
|
||||
//normal view mode
|
||||
|
||||
Vector3 rdir = new Vector3();
|
||||
float cryd = (float)Math.Cos(CurrentRotation.Y);
|
||||
rdir.X = -(float)Math.Sin(-CurrentRotation.X) * cryd;
|
||||
rdir.Z = -(float)Math.Cos(-CurrentRotation.X) * cryd;
|
||||
rdir.Y = (float)Math.Sin(CurrentRotation.Y);
|
||||
Vector3 lookat = new Vector3(0.0f, VOffset, 0.0f);
|
||||
Vector3 cpos = new Vector3();
|
||||
if (FollowEntity != null)
|
||||
{
|
||||
up = FollowEntity.Orientation.Multiply(up);
|
||||
lookat = FollowEntity.Orientation.Multiply(lookat);
|
||||
rdir = FollowEntity.Orientation.Multiply(rdir);
|
||||
cpos = FollowEntity.Position;
|
||||
}
|
||||
LocalLookAt = (rdir * CurrentDistance) + lookat;
|
||||
Position = cpos + LocalLookAt;
|
||||
ViewDirection = Vector3.Normalize(-rdir);
|
||||
UpDirection = up;
|
||||
}
|
||||
|
||||
|
||||
//M16FLookAt(LocalProjection.ViewMatrix, V3F(0.0f, 0.0f, 0.0f), LocalProjection.ViewDirection, LocalProjection.UpDirection);
|
||||
ViewQuaternion = Quaternion.LookAtRH(Vector3.Zero, ViewDirection, UpDirection);
|
||||
ViewInvQuaternion = Quaternion.Invert(ViewQuaternion);
|
||||
ViewMatrix = ViewQuaternion.ToMatrix();
|
||||
ViewInvMatrix = Matrix.Invert(ViewMatrix);
|
||||
|
||||
}
|
||||
private void UpdateProjMatrix()
|
||||
{
|
||||
if (IsMapView)
|
||||
{
|
||||
ProjMatrix = Matrix.OrthoRH(AspectRatio * OrthographicSize, OrthographicSize, 3000.0f, 1.0f);
|
||||
}
|
||||
else if (IsOrthographic)
|
||||
{
|
||||
ProjMatrix = Matrix.OrthoRH(AspectRatio * OrthographicSize, OrthographicSize, ZFar, ZNear);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjMatrix = Matrix.PerspectiveFovRH(FieldOfView, AspectRatio, ZFar, ZNear);
|
||||
}
|
||||
//ProjMatrix._33/=ZFar;
|
||||
//ProjMatrix._43/=ZFar;
|
||||
UpdateProj = false;
|
||||
}
|
||||
private void UpdateProjection() //CameraSpaceProjection& p, float mx, float my)
|
||||
{
|
||||
float mx = MouseX;
|
||||
float my = MouseY;
|
||||
ViewProjMatrix = Matrix.Multiply(ViewMatrix, ProjMatrix);
|
||||
ViewProjInvMatrix = Matrix.Invert(ViewProjMatrix);
|
||||
MouseRayNear = ViewProjInvMatrix.MultiplyW(new Vector3(mx, my, 1.0f));
|
||||
MouseRayFar = ViewProjInvMatrix.MultiplyW(new Vector3(mx, my, 0.0f));
|
||||
MouseRay.Position = Vector3.Zero;
|
||||
MouseRay.Direction = Vector3.Normalize(MouseRayFar - MouseRayNear);
|
||||
if (IsMapView || IsOrthographic)
|
||||
{
|
||||
MouseRay.Position = MouseRayNear;
|
||||
}
|
||||
ViewFrustum.Update(ref ViewProjMatrix);
|
||||
ViewFrustum.Position = Position;
|
||||
}
|
||||
private void UpdateMousedItem()
|
||||
{
|
||||
//////MousedItem = nullptr;
|
||||
//////MousedThing = nullptr;
|
||||
//////MousedItemSpace = nullptr;
|
||||
////int i = 0;
|
||||
//////var cp = &SpaceProjections[i++];
|
||||
//////auto item = cp->MousedItem;
|
||||
//////auto thing = cp->MousedThing;
|
||||
////auto count = cp->MouseTestedItems;
|
||||
//////while((item==nullptr) && (thing==nullptr) && (i<SpaceProjections.size()))
|
||||
////Moused.Clear();
|
||||
////if (cp->Moused.HasValue) Moused.Set(cp->Moused);
|
||||
////while (!Moused.HasValue && (i < SpaceProjections.size()))
|
||||
////{
|
||||
//// cp = &SpaceProjections[i++];
|
||||
//// //item = cp->MousedItem;
|
||||
//// //thing = cp->MousedThing;
|
||||
//// if (cp->Moused.HasValue)
|
||||
//// {
|
||||
//// Moused.Set(cp->Moused);
|
||||
//// }
|
||||
//// count += cp->MouseTestedItems;
|
||||
////}
|
||||
//////if((item!=nullptr) || (thing!=nullptr))
|
||||
//////{
|
||||
////// MousedItem = item;
|
||||
////// MousedThing = thing;
|
||||
////// MousedItemSpace = cp->MousedItemSpace;
|
||||
//////}
|
||||
}
|
||||
public void OnWindowResize(int w, int h)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
Width = (float)w;
|
||||
Height = (float)h;
|
||||
AspectRatio = Width / Height;
|
||||
UpdateProj = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ControllerRotate(float x, float y, float elapsed)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
TargetRotation.X += x*elapsed;
|
||||
TargetRotation.Y += y*elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public void ControllerZoom(float z)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
float v = (z < 0) ? (1.0f - z) : (z > 0) ? (1.0f / (1.0f + z)) : 1.0f;
|
||||
TargetDistance *= v;
|
||||
OrthographicTargetSize *= v;
|
||||
}
|
||||
}
|
||||
|
||||
public void MouseRotate(int x, int y)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
TargetRotation.X += x * Sensitivity;
|
||||
TargetRotation.Y += y * Sensitivity;
|
||||
}
|
||||
}
|
||||
|
||||
public void MouseZoom(int z)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
float v = (z < 0) ? 1.1f : (z > 0) ? 1.0f / 1.1f : 1.0f;
|
||||
TargetDistance *= v;
|
||||
OrthographicTargetSize *= v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Frustum
|
||||
{
|
||||
public Plane[] Planes = new Plane[6];
|
||||
public Vector3 Position;
|
||||
|
||||
public void Update(ref Matrix vp)
|
||||
{
|
||||
//left, right, top, bottom, near, far
|
||||
Planes[0] = Plane.Normalize(new Plane((vp.M14 + vp.M11), (vp.M24 + vp.M21), (vp.M34 + vp.M31), (vp.M44 + vp.M41)));
|
||||
Planes[1] = Plane.Normalize(new Plane((vp.M14 - vp.M11), (vp.M24 - vp.M21), (vp.M34 - vp.M31), (vp.M44 - vp.M41)));
|
||||
Planes[2] = Plane.Normalize(new Plane((vp.M14 - vp.M12), (vp.M24 - vp.M22), (vp.M34 - vp.M32), (vp.M44 - vp.M42)));
|
||||
Planes[3] = Plane.Normalize(new Plane((vp.M14 + vp.M12), (vp.M24 + vp.M22), (vp.M34 + vp.M32), (vp.M44 + vp.M42)));
|
||||
Planes[4] = Plane.Normalize(new Plane((vp.M14 - vp.M13), (vp.M24 - vp.M23), (vp.M34 - vp.M33), (vp.M44 - vp.M43)));
|
||||
Planes[5] = Plane.Normalize(new Plane((vp.M13), (vp.M23), (vp.M33), 0.0f));//(vp.M43));
|
||||
}
|
||||
|
||||
//public bool ContainsSphere(ref Vector3 c, float cls, float r)
|
||||
//{
|
||||
// //cls = c length squared, for optimization
|
||||
// if (cls < (r * r))
|
||||
// {
|
||||
// return true; //frustrum center is in the sphere
|
||||
// }
|
||||
// float nr = -r;
|
||||
// for (int i = 0; i < 6; i++)
|
||||
// {
|
||||
// if (Plane.DotCoordinate(Planes[i], c) < nr)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
//}
|
||||
public bool ContainsSphereNoClipNoOpt(ref Vector3 c, float r)
|
||||
{
|
||||
float nr = -r;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (Plane.DotCoordinate(Planes[i], c) < nr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool ContainsAABBNoClip(ref Vector3 cen, ref Vector3 e)
|
||||
{
|
||||
var c = cen - Position;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var pn = Planes[i].Normal;
|
||||
var d = (c.X * pn.X) + (c.Y * pn.Y) + (c.Z * pn.Z); //Vector3.Dot(c, pn);//
|
||||
var r = (e.X * (pn.X > 0 ? pn.X : -pn.X)) + (e.Y * (pn.Y > 0 ? pn.Y : -pn.Y)) + (e.Z * (pn.Z > 0 ? pn.Z : -pn.Z)); //Vector3.Dot(e, pn.Abs()); //
|
||||
if ((d + r) < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool ContainsAABBNoClipNoOpt(ref Vector3 bmin, ref Vector3 bmax)
|
||||
{
|
||||
var c = (bmax + bmin) * 0.5f - Position;
|
||||
var e = (bmax - bmin) * 0.5f;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var pd = Planes[i].D;
|
||||
var pn = Planes[i].Normal;
|
||||
var d = (c.X * pn.X) + (c.Y * pn.Y) + (c.Z * pn.Z);
|
||||
var r = (e.X * (pn.X > 0 ? pn.X : -pn.X)) + (e.Y * (pn.Y > 0 ? pn.Y : -pn.Y)) + (e.Z * (pn.Z > 0 ? pn.Z : -pn.Z));
|
||||
if ((d + r) < -pd) return false;
|
||||
//if ((d - r) < -pd) ; //intersecting
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool ContainsAABBNoFrontClipNoOpt(ref Vector3 bmin, ref Vector3 bmax)
|
||||
{
|
||||
var c = (bmax + bmin) * 0.5f - Position;
|
||||
var e = (bmax - bmin) * 0.5f;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var pd = Planes[i].D;
|
||||
var pn = Planes[i].Normal;
|
||||
var d = (c.X * pn.X) + (c.Y * pn.Y) + (c.Z * pn.Z);
|
||||
var r = (e.X * (pn.X > 0 ? pn.X : -pn.X)) + (e.Y * (pn.Y > 0 ? pn.Y : -pn.Y)) + (e.Z * (pn.Z > 0 ? pn.Z : -pn.Z));
|
||||
if ((d + r) < -pd) return false;
|
||||
//if ((d - r) < -pd) ; //intersecting
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
459
C#/CodeWalker.Core/World/Clouds.cs
Normal file
459
C#/CodeWalker.Core/World/Clouds.cs
Normal file
@@ -0,0 +1,459 @@
|
||||
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 Clouds
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
|
||||
public Weather Weather;
|
||||
public Timecycle Timecycle;
|
||||
public Dictionary<string, CloudAnimSetting> AnimSettings { get; set; }
|
||||
public CloudAnimOverrides AnimOverrides = new CloudAnimOverrides();
|
||||
|
||||
public CloudHatManager HatManager;
|
||||
public CloudSettingsMap SettingsMap;
|
||||
|
||||
|
||||
public Clouds()
|
||||
{
|
||||
AnimSettings = new Dictionary<string, CloudAnimSetting>();
|
||||
AddAnimSetting(new CloudAnimSetting("UVOffset1.X", "UV Offset 1 X", -1.0f, 1.0f, 0.0f));
|
||||
AddAnimSetting(new CloudAnimSetting("UVOffset1.Y", "UV Offset 1 Y", -1.0f, 1.0f, 0.0f));
|
||||
AddAnimSetting(new CloudAnimSetting("UVOffset2.X", "UV Offset 2 X", -1.0f, 1.0f, 0.0f));
|
||||
AddAnimSetting(new CloudAnimSetting("UVOffset2.Y", "UV Offset 2 Y", -1.0f, 1.0f, 0.0f));
|
||||
AddAnimSetting(new CloudAnimSetting("UVOffset3.X", "UV Offset 3 X", -1.0f, 1.0f, 0.0f));
|
||||
AddAnimSetting(new CloudAnimSetting("UVOffset3.Y", "UV Offset 3 Y", -1.0f, 1.0f, 0.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("RescaleUV1.X", "Rescale UV 1 X", 0.0f, 50.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("RescaleUV1.Y", "Rescale UV 1 Y", 0.0f, 50.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("RescaleUV2.X", "Rescale UV 2 X", 0.0f, 50.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("RescaleUV2.Y", "Rescale UV 2 Y", 0.0f, 50.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("RescaleUV3.X", "Rescale UV 3 X", 0.0f, 50.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("RescaleUV3.Y", "Rescale UV 3 Y", 0.0f, 50.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale1.X", "Anim Scale 1 X", 0.0f, 8.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale1.Y", "Anim Scale 1 Y", 0.0f, 8.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale2.X", "Anim Scale 2 X", 0.0f, 8.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale2.Y", "Anim Scale 2 Y", 0.0f, 8.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale3.X", "Anim Scale 3 X", 0.0f, 8.0f, 1.0f));
|
||||
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale3.Y", "Anim Scale 3 Y", 0.0f, 8.0f, 1.0f));
|
||||
}
|
||||
private void AddAnimSetting(CloudAnimSetting setting)
|
||||
{
|
||||
AnimSettings[setting.Name] = setting;
|
||||
}
|
||||
private void UpdateAnimOverrides()
|
||||
{
|
||||
AnimOverrides.UVOffset1.X = AnimSettings["UVOffset1.X"].CurrentValue;
|
||||
AnimOverrides.UVOffset1.Y = AnimSettings["UVOffset1.Y"].CurrentValue;
|
||||
AnimOverrides.UVOffset2.X = AnimSettings["UVOffset2.X"].CurrentValue;
|
||||
AnimOverrides.UVOffset2.Y = AnimSettings["UVOffset2.Y"].CurrentValue;
|
||||
AnimOverrides.UVOffset3.X = AnimSettings["UVOffset3.X"].CurrentValue;
|
||||
AnimOverrides.UVOffset3.Y = AnimSettings["UVOffset3.Y"].CurrentValue;
|
||||
//AnimOverrides.RescaleUV1.X = AnimSettings["RescaleUV1.X"].CurrentValue;
|
||||
//AnimOverrides.RescaleUV1.Y = AnimSettings["RescaleUV1.Y"].CurrentValue;
|
||||
//AnimOverrides.RescaleUV2.X = AnimSettings["RescaleUV2.X"].CurrentValue;
|
||||
//AnimOverrides.RescaleUV2.Y = AnimSettings["RescaleUV2.Y"].CurrentValue;
|
||||
//AnimOverrides.RescaleUV3.X = AnimSettings["RescaleUV3.X"].CurrentValue;
|
||||
//AnimOverrides.RescaleUV3.Y = AnimSettings["RescaleUV3.Y"].CurrentValue;
|
||||
//AnimOverrides.cloudLayerAnimScale1.X = AnimSettings["cloudLayerAnimScale1.X"].CurrentValue;
|
||||
//AnimOverrides.cloudLayerAnimScale1.Y = AnimSettings["cloudLayerAnimScale1.Y"].CurrentValue;
|
||||
//AnimOverrides.cloudLayerAnimScale2.X = AnimSettings["cloudLayerAnimScale2.X"].CurrentValue;
|
||||
//AnimOverrides.cloudLayerAnimScale2.Y = AnimSettings["cloudLayerAnimScale2.Y"].CurrentValue;
|
||||
//AnimOverrides.cloudLayerAnimScale3.X = AnimSettings["cloudLayerAnimScale3.X"].CurrentValue;
|
||||
//AnimOverrides.cloudLayerAnimScale3.Y = AnimSettings["cloudLayerAnimScale3.Y"].CurrentValue;
|
||||
}
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus, Weather weather)
|
||||
{
|
||||
Weather = weather;
|
||||
Timecycle = weather.Timecycle;
|
||||
var rpfman = gameFileCache.RpfMan;
|
||||
|
||||
string filename = "common.rpf\\data\\clouds.xml";
|
||||
|
||||
//TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it!
|
||||
string kffilename = "common.rpf\\data\\cloudkeyframes.xml";
|
||||
if (gameFileCache.EnableDlc)
|
||||
{
|
||||
kffilename = "update\\update.rpf\\common\\data\\cloudkeyframes.xml";
|
||||
}
|
||||
|
||||
XmlDocument cloudsxml = rpfman.GetFileXml(filename);
|
||||
XmlDocument cloudskfxml = rpfman.GetFileXml(kffilename);
|
||||
|
||||
HatManager = new CloudHatManager();
|
||||
HatManager.Init(cloudsxml.DocumentElement); //CloudHatManager
|
||||
|
||||
SettingsMap = new CloudSettingsMap();
|
||||
SettingsMap.Init(cloudskfxml.DocumentElement); //CloudSettingsMap
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
|
||||
public void Update(float elapsed)
|
||||
{
|
||||
UpdateAnimOverrides();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class CloudHatManager
|
||||
{
|
||||
public CloudHatFrag[] CloudHatFrags { get; set; }
|
||||
public float DesiredTransitionTimeSec { get; set; }
|
||||
public Vector3 CamPositionScaler { get; set; }
|
||||
public float AltitudeScrollScaler { get; set; }
|
||||
|
||||
public void Init(XmlElement xml)
|
||||
{
|
||||
List<CloudHatFrag> fraglist = new List<CloudHatFrag>();
|
||||
XmlNodeList frags = xml.SelectNodes("mCloudHatFrags/Item");
|
||||
foreach (XmlNode node in frags)
|
||||
{
|
||||
XmlElement fragel = node as XmlElement;
|
||||
if (fragel != null)
|
||||
{
|
||||
CloudHatFrag frag = new CloudHatFrag();
|
||||
frag.Init(fragel);
|
||||
fraglist.Add(frag);
|
||||
}
|
||||
}
|
||||
CloudHatFrags = fraglist.ToArray();
|
||||
|
||||
DesiredTransitionTimeSec = Xml.GetChildFloatAttribute(xml, "mDesiredTransitionTimeSec", "value");
|
||||
CamPositionScaler = Xml.GetChildVector3Attributes(xml, "mCamPositionScaler");
|
||||
AltitudeScrollScaler = Xml.GetChildFloatAttribute(xml, "mAltitudeScrollScaler", "value");
|
||||
}
|
||||
|
||||
public CloudHatFrag FindFrag(string name)
|
||||
{
|
||||
for (int i = 0; i < CloudHatFrags.Length; i++)
|
||||
{
|
||||
CloudHatFrag f = CloudHatFrags[i];
|
||||
if (f.Name == name)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CloudHatFrag
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Rotation { get; set; }
|
||||
public Vector3 Scale { get; set; }
|
||||
public string Name { get; set; }
|
||||
public CloudHatFragLayer[] Layers { get; set; }
|
||||
public float TransitionAlphaRange { get; set; }
|
||||
public float TransitionMidPoint { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public Vector3 AngularVelocity { get; set; }
|
||||
public Vector3 AnimBlendWeights { get; set; }
|
||||
public Vector2[] UVVelocity { get; set; }
|
||||
public byte[] AnimMode { get; set; }
|
||||
public bool[] ShowLayer { get; set; }
|
||||
public bool EnableAnimations { get; set; }
|
||||
|
||||
public void Init(XmlElement xml)
|
||||
{
|
||||
Position = Xml.GetChildVector3Attributes(xml, "mPosition");
|
||||
Rotation = Xml.GetChildVector3Attributes(xml, "mRotation");
|
||||
Scale = Xml.GetChildVector3Attributes(xml, "mScale");
|
||||
Name = Xml.GetChildInnerText(xml, "mName");
|
||||
|
||||
List<CloudHatFragLayer> layerlist = new List<CloudHatFragLayer>();
|
||||
XmlNodeList layersxml = xml.SelectNodes("mLayers/Item");
|
||||
foreach (XmlNode node in layersxml)
|
||||
{
|
||||
XmlElement layerel = node as XmlElement;
|
||||
if (layerel != null)
|
||||
{
|
||||
CloudHatFragLayer layer = new CloudHatFragLayer();
|
||||
layer.Init(layerel);
|
||||
layerlist.Add(layer);
|
||||
}
|
||||
}
|
||||
Layers = layerlist.ToArray();
|
||||
|
||||
TransitionAlphaRange = Xml.GetChildFloatAttribute(xml, "mTransitionAlphaRange", "value");
|
||||
TransitionMidPoint = Xml.GetChildFloatAttribute(xml, "mTransitionMidPoint", "value");
|
||||
Enabled = Xml.GetChildBoolAttribute(xml, "mEnabled", "value");
|
||||
AngularVelocity = Xml.GetChildVector3Attributes(xml, "mAngularVelocity");
|
||||
AnimBlendWeights = Xml.GetChildVector3Attributes(xml, "mAnimBlendWeights");
|
||||
|
||||
string uvvelocitystr = Xml.GetChildInnerText(xml, "mUVVelocity").Trim();
|
||||
string[] uvvelocities = uvvelocitystr.Split('\n');
|
||||
UVVelocity = new Vector2[uvvelocities.Length];
|
||||
for (int i = 0; i < uvvelocities.Length; i++)
|
||||
{
|
||||
Vector2 vel = Vector2.Zero;
|
||||
string uvvel = uvvelocities[i].Trim();
|
||||
string[] uvvelc = uvvel.Split('\t');
|
||||
if (uvvelc.Length == 2)
|
||||
{
|
||||
FloatUtil.TryParse(uvvelc[0].Trim(), out vel.X);
|
||||
FloatUtil.TryParse(uvvelc[1].Trim(), out vel.Y);
|
||||
}
|
||||
UVVelocity[i] = vel;
|
||||
}
|
||||
|
||||
string animmodestr = Xml.GetChildInnerText(xml, "mAnimMode").Trim();
|
||||
string[] animmodes = animmodestr.Split('\n');
|
||||
AnimMode = new byte[animmodes.Length];
|
||||
for (int i = 0; i < animmodes.Length; i++)
|
||||
{
|
||||
byte.TryParse(animmodes[i].Trim(), out AnimMode[i]);
|
||||
}
|
||||
|
||||
|
||||
//string showlayerstr = Xml.GetChildInnerText(xml, "mShowLayer").Trim();
|
||||
XmlNodeList showlayersxml = xml.SelectNodes("mShowLayer/Item");
|
||||
ShowLayer = new bool[showlayersxml.Count];
|
||||
for (int i = 0; i < showlayersxml.Count; i++)
|
||||
{
|
||||
XmlNode slnode = showlayersxml[i];
|
||||
if (slnode is XmlElement)
|
||||
{
|
||||
ShowLayer[i] = Xml.GetBoolAttribute(slnode, "value");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EnableAnimations = Xml.GetChildBoolAttribute(xml, "mEnableAnimations", "value");
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public class CloudHatFragLayer
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
public float CostFactor { get; set; }
|
||||
public float RotationScale { get; set; }
|
||||
public float CamPositionScalerAdjust { get; set; }
|
||||
public float TransitionInTimePercent { get; set; }
|
||||
public float TransitionOutTimePercent { get; set; }
|
||||
public float TransitionInDelayPercent { get; set; }
|
||||
public float TransitionOutDelayPercent { get; set; }
|
||||
public float HeightTigger { get; set; }
|
||||
public float HeightFadeRange { get; set; }
|
||||
|
||||
public void Init(XmlElement xml)
|
||||
{
|
||||
Filename = Xml.GetChildInnerText(xml, "mFilename");
|
||||
CostFactor = Xml.GetChildFloatAttribute(xml, "mCostFactor", "value");
|
||||
RotationScale = Xml.GetChildFloatAttribute(xml, "mRotationScale", "value");
|
||||
CamPositionScalerAdjust = Xml.GetChildFloatAttribute(xml, "mCamPositionScalerAdjust", "value");
|
||||
TransitionInTimePercent = Xml.GetChildFloatAttribute(xml, "mTransitionInTimePercent", "value");
|
||||
TransitionOutTimePercent = Xml.GetChildFloatAttribute(xml, "mTransitionOutTimePercent", "value");
|
||||
TransitionInDelayPercent = Xml.GetChildFloatAttribute(xml, "mTransitionInDelayPercent", "value");
|
||||
TransitionOutDelayPercent = Xml.GetChildFloatAttribute(xml, "mTransitionOutDelayPercent", "value");
|
||||
HeightTigger = Xml.GetChildFloatAttribute(xml, "mHeightTigger", "value");
|
||||
HeightFadeRange = Xml.GetChildFloatAttribute(xml, "mHeightFadeRange", "value");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Filename;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class CloudSettingsMap
|
||||
{
|
||||
public float[] KeyframeTimes { get; set; }
|
||||
public Dictionary<string, CloudSettingsMapItem> SettingsMap { get; set; }
|
||||
|
||||
public void Init(XmlElement xml)
|
||||
{
|
||||
|
||||
string kftstr = Xml.GetChildInnerText(xml, "KeyframeTimes").Trim();
|
||||
string[] kftarr = kftstr.Split('\n');
|
||||
KeyframeTimes = new float[kftarr.Length];
|
||||
for (int i = 0; i < kftarr.Length; i++)
|
||||
{
|
||||
FloatUtil.TryParse(kftarr[i].Trim(), out KeyframeTimes[i]);
|
||||
}
|
||||
|
||||
|
||||
SettingsMap = new Dictionary<string, CloudSettingsMapItem>();
|
||||
XmlNodeList mapxml = xml.SelectNodes("SettingsMap/Item");
|
||||
foreach (XmlNode node in mapxml)
|
||||
{
|
||||
XmlElement itemel = node as XmlElement;
|
||||
if (itemel != null)
|
||||
{
|
||||
CloudSettingsMapItem item = new CloudSettingsMapItem();
|
||||
item.Init(itemel);
|
||||
SettingsMap[item.Name] = item;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class CloudSettingsMapItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public CloudSettingsMapCloudList CloudList { get; set; } = new CloudSettingsMapCloudList();
|
||||
public CloudSettingsMapKeyData CloudColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudLightColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudAmbientColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudSkyColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudBounceColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudEastColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudWestColor { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudScaleFillColors { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudDensityShift_Scale_ScatteringConst_Scale { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudPiercingLightPower_Strength_NormalStrength_Thickness { get; set; } = new CloudSettingsMapKeyData();
|
||||
public CloudSettingsMapKeyData CloudScaleDiffuseFillAmbient_WrapAmount { get; set; } = new CloudSettingsMapKeyData();
|
||||
|
||||
public void Init(XmlNode xml)
|
||||
{
|
||||
Name = Xml.GetChildInnerText(xml, "Name");
|
||||
var snode = xml.SelectSingleNode("Settings");
|
||||
CloudList.Init(snode.SelectSingleNode("CloudList"));
|
||||
CloudColor.Init(snode.SelectSingleNode("CloudColor"));
|
||||
CloudLightColor.Init(snode.SelectSingleNode("CloudLightColor"));
|
||||
CloudAmbientColor.Init(snode.SelectSingleNode("CloudAmbientColor"));
|
||||
CloudSkyColor.Init(snode.SelectSingleNode("CloudSkyColor"));
|
||||
CloudBounceColor.Init(snode.SelectSingleNode("CloudBounceColor"));
|
||||
CloudEastColor.Init(snode.SelectSingleNode("CloudEastColor"));
|
||||
CloudWestColor.Init(snode.SelectSingleNode("CloudWestColor"));
|
||||
CloudScaleFillColors.Init(snode.SelectSingleNode("CloudScaleFillColors"));
|
||||
CloudDensityShift_Scale_ScatteringConst_Scale.Init(snode.SelectSingleNode("CloudDensityShift_Scale_ScatteringConst_Scale"));
|
||||
CloudPiercingLightPower_Strength_NormalStrength_Thickness.Init(snode.SelectSingleNode("CloudPiercingLightPower_Strength_NormalStrength_Thickness"));
|
||||
CloudScaleDiffuseFillAmbient_WrapAmount.Init(snode.SelectSingleNode("CloudScaleDiffuseFillAmbient_WrapAmount"));
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public class CloudSettingsMapCloudList
|
||||
{
|
||||
public int[] Probability { get; set; }
|
||||
public int[] Bits { get; set; } //one bit for each cloud hat frag
|
||||
|
||||
public void Init(XmlNode xml)
|
||||
{
|
||||
string pstr = Xml.GetChildInnerText(xml, "mProbability").Trim();
|
||||
string bstr = Xml.GetChildInnerText(xml, "mBits").Trim();
|
||||
|
||||
string[] parr = pstr.Split('\n');
|
||||
string[] barr = bstr.Split('\n');
|
||||
|
||||
Probability = new int[parr.Length];
|
||||
Bits = new int[barr.Length];
|
||||
|
||||
for (int i = 0; i < parr.Length; i++)
|
||||
{
|
||||
int.TryParse(parr[i].Trim(), out Probability[i]);
|
||||
}
|
||||
for (int i = 0; i < barr.Length; i++)
|
||||
{
|
||||
Bits[i] = Convert.ToInt32(barr[i].Trim(), 16);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class CloudSettingsMapKeyData
|
||||
{
|
||||
public int numKeyEntries { get; set; }
|
||||
public Dictionary<float, Vector4> keyEntryData { get; set; }
|
||||
|
||||
public void Init(XmlNode xml)
|
||||
{
|
||||
var kdxml = xml.SelectSingleNode("keyData");
|
||||
|
||||
numKeyEntries = Xml.GetChildIntAttribute(kdxml, "numKeyEntries", "value");
|
||||
|
||||
string kestr = Xml.GetChildInnerText(kdxml, "keyEntryData").Trim();
|
||||
string[] kearr = kestr.Split('\n');
|
||||
keyEntryData = new Dictionary<float, Vector4>();
|
||||
for (int i = 0; i < kearr.Length; i++)
|
||||
{
|
||||
string kvstr = kearr[i].Trim();
|
||||
string[] kvarr = kvstr.Split('\t');
|
||||
float key = 0.0f;
|
||||
Vector4 val = Vector4.Zero;
|
||||
if (kvarr.Length >= 5)
|
||||
{
|
||||
FloatUtil.TryParse(kvarr[0].Trim(), out key);
|
||||
FloatUtil.TryParse(kvarr[1].Trim(), out val.X);
|
||||
FloatUtil.TryParse(kvarr[2].Trim(), out val.Y);
|
||||
FloatUtil.TryParse(kvarr[3].Trim(), out val.Z);
|
||||
FloatUtil.TryParse(kvarr[4].Trim(), out val.W);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
keyEntryData[key] = val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class CloudAnimSetting
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public float MinValue { get; set; }
|
||||
public float MaxValue { get; set; }
|
||||
public float DefaultValue { get; set; }
|
||||
public float CurrentValue { get; set; }
|
||||
|
||||
|
||||
public CloudAnimSetting(string name, string displayname, float minval, float maxval, float defaultval)
|
||||
{
|
||||
Name = name;
|
||||
DisplayName = displayname;
|
||||
MinValue = minval;
|
||||
MaxValue = maxval;
|
||||
DefaultValue = defaultval;
|
||||
CurrentValue = defaultval;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
public class CloudAnimOverrides
|
||||
{
|
||||
public Vector2 UVOffset1 = Vector2.Zero;
|
||||
public Vector2 UVOffset2 = Vector2.Zero;
|
||||
public Vector2 UVOffset3 = Vector2.Zero;
|
||||
public Vector2 RescaleUV1 = Vector2.One;
|
||||
public Vector2 RescaleUV2 = Vector2.One;
|
||||
public Vector2 RescaleUV3 = Vector2.One;
|
||||
public Vector2 cloudLayerAnimScale1 = Vector2.One;
|
||||
public Vector2 cloudLayerAnimScale2 = Vector2.One;
|
||||
public Vector2 cloudLayerAnimScale3 = Vector2.One;
|
||||
}
|
||||
|
||||
}
|
||||
198
C#/CodeWalker.Core/World/Entity.cs
Normal file
198
C#/CodeWalker.Core/World/Entity.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class Entity
|
||||
{
|
||||
public Space Space;
|
||||
public YmapEntityDef EntityDef;
|
||||
|
||||
public float Radius;
|
||||
public Vector3 Center;
|
||||
public Vector3 Position;
|
||||
public Quaternion Orientation = Quaternion.Identity;
|
||||
public Quaternion OrientationInv = Quaternion.Identity;
|
||||
|
||||
public float Mass;
|
||||
public Matrix MomentOfInertia;
|
||||
public Vector3 Momentum;
|
||||
public Vector3 Velocity;
|
||||
public Vector3 AngularMomentum;
|
||||
public Vector3 AngularVelocity;
|
||||
|
||||
public bool WasColliding;
|
||||
|
||||
public bool EnableCollisions;
|
||||
public bool Enabled;
|
||||
|
||||
public float Lifetime;
|
||||
public float Age;
|
||||
|
||||
//public CollisionShape ..
|
||||
|
||||
public virtual void PreUpdate(float elapsed)
|
||||
{ }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class PedEntity : Entity
|
||||
{
|
||||
|
||||
public Vector2 ControlMovement;
|
||||
public bool ControlJump;
|
||||
public bool ControlBoost;
|
||||
|
||||
public Vector3 ForwardVec;
|
||||
|
||||
public Quaternion CameraOrientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
|
||||
public Entity CameraEntity = new Entity();
|
||||
|
||||
public bool OnGround = false;
|
||||
|
||||
|
||||
public PedEntity()
|
||||
{
|
||||
Radius = 0.5f;
|
||||
Center = new Vector3(0.0f, 0.0f, -1.2f); //base collision point is 1.7m below center... for camera offset
|
||||
|
||||
Mass = 80.0f;
|
||||
|
||||
ForwardVec = Vector3.UnitY;
|
||||
CameraEntity.Orientation = CameraOrientation;
|
||||
CameraEntity.OrientationInv = Quaternion.Invert(Orientation);
|
||||
}
|
||||
|
||||
public override void PreUpdate(float elapsed)
|
||||
{
|
||||
|
||||
//float rotspd = 0.5f;
|
||||
float movspd = 10.0f;
|
||||
float velspd = 10.0f;
|
||||
float jmpvel = 3.0f;
|
||||
float boostmult = 10.0f;
|
||||
if (ControlBoost) movspd *= boostmult;
|
||||
|
||||
Quaternion rot = Quaternion.Identity;// .RotationAxis(Vector3.UnitZ, -ControlMovement.X * rotspd * elapsed);
|
||||
Quaternion ori = Quaternion.Multiply(Orientation, rot);
|
||||
SetOrientation(ori);
|
||||
|
||||
|
||||
float jmpamt = (ControlJump ? jmpvel : 0);
|
||||
Vector3 curvel = Velocity;
|
||||
Vector3 controlvel = new Vector3(ControlMovement * movspd, jmpamt);
|
||||
Vector3 targetvel = controlvel + new Vector3(0, 0, curvel.Z);
|
||||
Vector3 newvel = curvel + (targetvel - curvel) * velspd * elapsed;
|
||||
Velocity = newvel;
|
||||
var coll = Space.FindFirstCollision(this, elapsed);
|
||||
if (coll.Hit)
|
||||
{
|
||||
Vector3 collpos = coll.PrePos; //last known ok position
|
||||
Vector3 disp = Velocity * elapsed;
|
||||
Vector3 oldpos = Position;
|
||||
Vector3 targetpos = Position + disp;
|
||||
float displ = disp.Length();
|
||||
|
||||
//////BoundingSphere sph = new BoundingSphere(targetpos + Center, Radius);
|
||||
//////r.SphereHit = SphereIntersect(sph);
|
||||
|
||||
if ((disp.Z > -0.25f))/* && (displ < Radius * 2.0f)*/
|
||||
{
|
||||
Vector3 raydir = new Vector3(0.0f, 0.0f, -1.0f);
|
||||
Vector3 rayoff = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
Ray ray = new Ray(targetpos + Center + rayoff, raydir);
|
||||
var rayhit = Space.RayIntersect(ray, 1.0f);
|
||||
if (rayhit.Hit)
|
||||
{
|
||||
if (rayhit.HitDist > 0)
|
||||
{
|
||||
Position = rayhit.Position - Center + new Vector3(0, 0, Radius);
|
||||
//collpos = Position;//targetpos;//
|
||||
}
|
||||
else
|
||||
{
|
||||
//the start of the ray was a collision... can't move here
|
||||
Position = collpos;
|
||||
}
|
||||
}
|
||||
else //might happen when about to go off a big drop?
|
||||
{
|
||||
Position = targetpos;// collpos;
|
||||
//collpos = targetpos;
|
||||
}
|
||||
}
|
||||
else //moving fast...
|
||||
{
|
||||
Position = collpos; //last known ok position
|
||||
}
|
||||
//Position = collpos; //last known ok position
|
||||
|
||||
|
||||
|
||||
bool wasOnGround = OnGround;
|
||||
OnGround = (Vector3.Dot(coll.SphereHit.Normal, Vector3.UnitZ) > 0.8f);
|
||||
if (OnGround)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Vector3 findisp = Position - oldpos;
|
||||
float findispl = findisp.Length();
|
||||
float fdisp = Math.Min(displ, findispl);
|
||||
Vector3 dispdir = findisp / Math.Max(findispl, 0.0001f);
|
||||
float absvel = fdisp / Math.Max(elapsed, 0.0001f);
|
||||
Velocity = dispdir * absvel;
|
||||
|
||||
//Vector3 veldir = Vector3.Normalize(Position - oldpos);
|
||||
//float vellen = (collpos - oldpos).Length() / Math.Max(elapsed, 0.0001f);
|
||||
//Velocity = veldir * vellen;
|
||||
|
||||
//Velocity = (Position - oldpos) / Math.Max(elapsed, 0.0001f);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Position = coll.HitPos; //hitpos is the end pos if not hit
|
||||
OnGround = false;
|
||||
|
||||
var raydir = new Vector3(0.0f, 0.0f, -1.0f);
|
||||
var ray = new Ray(Position, raydir);
|
||||
var rayhit = Space.RayIntersect(ray, float.MaxValue);
|
||||
if (!rayhit.Hit && rayhit.TestComplete)
|
||||
{
|
||||
//must be under the map? try to find the ground...
|
||||
ray.Position = Position + new Vector3(0.0f, 0.0f, 1000.0f);
|
||||
rayhit = Space.RayIntersect(ray, float.MaxValue);
|
||||
if (rayhit.Hit)
|
||||
{
|
||||
Position = rayhit.Position + new Vector3(0.0f, 0.0f, Radius) - Center;
|
||||
OnGround = true;
|
||||
}
|
||||
else
|
||||
{ }//didn't find the ground, what to do now?
|
||||
}
|
||||
}
|
||||
|
||||
CameraEntity.Position = Position;
|
||||
}
|
||||
|
||||
|
||||
private void SetOrientation(Quaternion ori)
|
||||
{
|
||||
Orientation = ori;
|
||||
OrientationInv = Quaternion.Invert(Orientation);
|
||||
CameraEntity.Orientation = Quaternion.Multiply(Orientation, CameraOrientation);
|
||||
CameraEntity.OrientationInv = Quaternion.Invert(Orientation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
170
C#/CodeWalker.Core/World/Heightmaps.cs
Normal file
170
C#/CodeWalker.Core/World/Heightmaps.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class Heightmaps : BasePathData
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
public GameFileCache GameFileCache;
|
||||
|
||||
public List<HeightmapFile> HeightmapFiles = new List<HeightmapFile>();
|
||||
|
||||
|
||||
public Vector4[] GetNodePositions()
|
||||
{
|
||||
return NodePositions;
|
||||
}
|
||||
public EditorVertex[] GetPathVertices()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public EditorVertex[] GetTriangleVertices()
|
||||
{
|
||||
return TriangleVerts;
|
||||
}
|
||||
|
||||
public Vector4[] NodePositions;
|
||||
public EditorVertex[] TriangleVerts;
|
||||
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
Inited = false;
|
||||
|
||||
GameFileCache = gameFileCache;
|
||||
|
||||
|
||||
HeightmapFiles.Clear();
|
||||
|
||||
|
||||
if (gameFileCache.EnableDlc)
|
||||
{
|
||||
LoadHeightmap("update\\update.rpf\\common\\data\\levels\\gta5\\heightmap.dat");
|
||||
LoadHeightmap("update\\update.rpf\\common\\data\\levels\\gta5\\heightmapheistisland.dat");
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadHeightmap("common.rpf\\data\\levels\\gta5\\heightmap.dat");
|
||||
}
|
||||
|
||||
|
||||
BuildVertices();
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
private void LoadHeightmap(string filename)
|
||||
{
|
||||
var hmf = GameFileCache.RpfMan.GetFile<HeightmapFile>(filename);
|
||||
HeightmapFiles.Add(hmf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void BuildVertices()
|
||||
{
|
||||
|
||||
var vlist = new List<EditorVertex>();
|
||||
var nlist = new List<Vector4>();
|
||||
|
||||
foreach (var hmf in HeightmapFiles)
|
||||
{
|
||||
BuildHeightmapVertices(hmf, vlist, nlist);
|
||||
}
|
||||
|
||||
if (vlist.Count > 0)
|
||||
{
|
||||
TriangleVerts = vlist.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
TriangleVerts = null;
|
||||
}
|
||||
if (nlist.Count > 0)
|
||||
{
|
||||
NodePositions = nlist.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
NodePositions = null;
|
||||
}
|
||||
|
||||
}
|
||||
private void BuildHeightmapVertices(HeightmapFile hmf, List<EditorVertex> vl, List<Vector4> nl)
|
||||
{
|
||||
var v1 = new EditorVertex();
|
||||
var v2 = new EditorVertex();
|
||||
var v3 = new EditorVertex();
|
||||
var v4 = new EditorVertex();
|
||||
|
||||
uint cgrn = (uint)new Color(0, 128, 0, 60).ToRgba();
|
||||
uint cyel = (uint)new Color(128, 128, 0, 200).ToRgba();
|
||||
|
||||
var w = hmf.Width;
|
||||
var h = hmf.Height;
|
||||
var hmin = hmf.MinHeights;
|
||||
var hmax = hmf.MaxHeights;
|
||||
var min = hmf.BBMin;
|
||||
var max = hmf.BBMax;
|
||||
var siz = max - min;
|
||||
var step = siz / new Vector3(w - 1, h - 1, 255);
|
||||
|
||||
v1.Colour = v2.Colour = v3.Colour = v4.Colour = cyel;
|
||||
for (int yi = 1; yi < h; yi++)
|
||||
{
|
||||
var yo = yi - 1;
|
||||
for (int xi = 1; xi < w; xi++)
|
||||
{
|
||||
var xo = xi - 1;
|
||||
var o1 = yo * w + xo;
|
||||
var o2 = yo * w + xi;
|
||||
var o3 = yi * w + xo;
|
||||
var o4 = yi * w + xi;
|
||||
v1.Position = min + step * new Vector3(xo, yo, hmin[o1]);
|
||||
v2.Position = min + step * new Vector3(xi, yo, hmin[o2]);
|
||||
v3.Position = min + step * new Vector3(xo, yi, hmin[o3]);
|
||||
v4.Position = min + step * new Vector3(xi, yi, hmin[o4]);
|
||||
vl.Add(v1); vl.Add(v2); vl.Add(v3);
|
||||
vl.Add(v3); vl.Add(v2); vl.Add(v4);
|
||||
}
|
||||
}
|
||||
v1.Colour = v2.Colour = v3.Colour = v4.Colour = cgrn;
|
||||
for (int yi = 1; yi < h; yi++)
|
||||
{
|
||||
var yo = yi - 1;
|
||||
for (int xi = 1; xi < w; xi++)
|
||||
{
|
||||
var xo = xi - 1;
|
||||
var o1 = yo * w + xo;
|
||||
var o2 = yo * w + xi;
|
||||
var o3 = yi * w + xo;
|
||||
var o4 = yi * w + xi;
|
||||
v1.Position = min + step * new Vector3(xo, yo, hmax[o1]);
|
||||
v2.Position = min + step * new Vector3(xi, yo, hmax[o2]);
|
||||
v3.Position = min + step * new Vector3(xo, yi, hmax[o3]);
|
||||
v4.Position = min + step * new Vector3(xi, yi, hmax[o4]);
|
||||
vl.Add(v1); vl.Add(v2); vl.Add(v3);
|
||||
vl.Add(v3); vl.Add(v2); vl.Add(v4);
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
var o = y * w + x;
|
||||
nl.Add(new Vector4(min + step * new Vector3(x, y, hmin[o]), 10));
|
||||
nl.Add(new Vector4(min + step * new Vector3(x, y, hmax[o]), 10));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
306
C#/CodeWalker.Core/World/Ped.cs
Normal file
306
C#/CodeWalker.Core/World/Ped.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class Ped
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public MetaHash NameHash { get; set; } = 0;//ped name hash
|
||||
public CPedModelInfo__InitData InitData { get; set; } = null; //ped init data
|
||||
public YddFile Ydd { get; set; } = null; //ped drawables
|
||||
public YtdFile Ytd { get; set; } = null; //ped textures
|
||||
public YldFile Yld { get; set; } = null; //ped clothes
|
||||
public YcdFile Ycd { get; set; } = null; //ped animations
|
||||
public YedFile Yed { get; set; } = null; //ped expressions
|
||||
public YftFile Yft { get; set; } = null; //ped skeleton YFT
|
||||
public PedFile Ymt { get; set; } = null; //ped variation info
|
||||
public Dictionary<MetaHash, RpfFileEntry> DrawableFilesDict { get; set; } = null;
|
||||
public Dictionary<MetaHash, RpfFileEntry> TextureFilesDict { get; set; } = null;
|
||||
public Dictionary<MetaHash, RpfFileEntry> ClothFilesDict { get; set; } = null;
|
||||
public RpfFileEntry[] DrawableFiles { get; set; } = null;
|
||||
public RpfFileEntry[] TextureFiles { get; set; } = null;
|
||||
public RpfFileEntry[] ClothFiles { get; set; } = null;
|
||||
public ClipMapEntry AnimClip { get; set; } = null;
|
||||
public Expression Expression { get; set; } = null;
|
||||
public string[] DrawableNames { get; set; } = new string[12];
|
||||
public Drawable[] Drawables { get; set; } = new Drawable[12];
|
||||
public Texture[] Textures { get; set; } = new Texture[12];
|
||||
public Expression[] Expressions { get; set; } = new Expression[12];
|
||||
public ClothInstance[] Clothes { get; set; } = new ClothInstance[12];
|
||||
public bool EnableRootMotion { get; set; } = false; //used to toggle whether or not to include root motion when playing animations
|
||||
public Skeleton Skeleton { get; set; } = null;
|
||||
|
||||
public Vector3 Position { get; set; } = Vector3.Zero;
|
||||
public Quaternion Rotation { get; set; } = Quaternion.Identity;
|
||||
|
||||
public YmapEntityDef RenderEntity = new YmapEntityDef(); //placeholder entity object for rendering
|
||||
|
||||
|
||||
public void Init(string name, GameFileCache gfc)
|
||||
{
|
||||
var hash = JenkHash.GenHash(name.ToLowerInvariant());
|
||||
Init(hash, gfc);
|
||||
Name = name;
|
||||
}
|
||||
public void Init(MetaHash pedhash, GameFileCache gfc)
|
||||
{
|
||||
|
||||
Name = string.Empty;
|
||||
NameHash = 0;
|
||||
InitData = null;
|
||||
Ydd = null;
|
||||
Ytd = null;
|
||||
Yld = null;
|
||||
Ycd = null;
|
||||
Yed = null;
|
||||
Yft = null;
|
||||
Ymt = null;
|
||||
AnimClip = null;
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
Drawables[i] = null;
|
||||
Textures[i] = null;
|
||||
Expressions[i] = null;
|
||||
}
|
||||
|
||||
|
||||
CPedModelInfo__InitData initdata = null;
|
||||
if (!gfc.PedsInitDict.TryGetValue(pedhash, out initdata)) return;
|
||||
|
||||
var ycdhash = JenkHash.GenHash(initdata.ClipDictionaryName.ToLowerInvariant());
|
||||
var yedhash = JenkHash.GenHash(initdata.ExpressionDictionaryName.ToLowerInvariant());
|
||||
|
||||
//bool pedchange = NameHash != pedhash;
|
||||
//Name = pedname;
|
||||
NameHash = pedhash;
|
||||
InitData = initdata;
|
||||
Ydd = gfc.GetYdd(pedhash);
|
||||
Ytd = gfc.GetYtd(pedhash);
|
||||
Ycd = gfc.GetYcd(ycdhash);
|
||||
Yed = gfc.GetYed(yedhash);
|
||||
Yft = gfc.GetYft(pedhash);
|
||||
|
||||
PedFile pedFile = null;
|
||||
gfc.PedVariationsDict?.TryGetValue(pedhash, out pedFile);
|
||||
Ymt = pedFile;
|
||||
|
||||
Dictionary<MetaHash, RpfFileEntry> peddict = null;
|
||||
gfc.PedDrawableDicts.TryGetValue(NameHash, out peddict);
|
||||
DrawableFilesDict = peddict;
|
||||
DrawableFiles = DrawableFilesDict?.Values.ToArray();
|
||||
gfc.PedTextureDicts.TryGetValue(NameHash, out peddict);
|
||||
TextureFilesDict = peddict;
|
||||
TextureFiles = TextureFilesDict?.Values.ToArray();
|
||||
gfc.PedClothDicts.TryGetValue(NameHash, out peddict);
|
||||
ClothFilesDict = peddict;
|
||||
ClothFiles = ClothFilesDict?.Values.ToArray();
|
||||
|
||||
RpfFileEntry clothFile = null;
|
||||
if (ClothFilesDict?.TryGetValue(pedhash, out clothFile) ?? false)
|
||||
{
|
||||
Yld = gfc.GetFileUncached<YldFile>(clothFile);
|
||||
while ((Yld != null) && (!Yld.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(Yld);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
while ((Ydd != null) && (!Ydd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ydd = gfc.GetYdd(pedhash);
|
||||
}
|
||||
while ((Ytd != null) && (!Ytd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ytd = gfc.GetYtd(pedhash);
|
||||
}
|
||||
while ((Ycd != null) && (!Ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ycd = gfc.GetYcd(ycdhash);
|
||||
}
|
||||
while ((Yed != null) && (!Yed.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Yed = gfc.GetYed(yedhash);
|
||||
}
|
||||
while ((Yft != null) && (!Yft.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Yft = gfc.GetYft(pedhash);
|
||||
}
|
||||
|
||||
|
||||
Skeleton = Yft?.Fragment?.Drawable?.Skeleton?.Clone();
|
||||
|
||||
MetaHash cliphash = JenkHash.GenHash("idle");
|
||||
ClipMapEntry cme = null;
|
||||
Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||
AnimClip = cme;
|
||||
|
||||
var exprhash = JenkHash.GenHash(initdata.ExpressionName.ToLowerInvariant());
|
||||
Expression expr = null;
|
||||
Yed?.ExprMap?.TryGetValue(exprhash, out expr);
|
||||
Expression = expr;
|
||||
|
||||
|
||||
UpdateEntity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void SetComponentDrawable(int index, string name, string tex, GameFileCache gfc)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
DrawableNames[index] = null;
|
||||
Drawables[index] = null;
|
||||
Textures[index] = null;
|
||||
Expressions[index] = null;
|
||||
return;
|
||||
}
|
||||
|
||||
MetaHash namehash = JenkHash.GenHash(name.ToLowerInvariant());
|
||||
Drawable d = null;
|
||||
if (Ydd?.Dict != null)
|
||||
{
|
||||
Ydd.Dict.TryGetValue(namehash, out d);
|
||||
}
|
||||
if ((d == null) && (DrawableFilesDict != null))
|
||||
{
|
||||
RpfFileEntry file = null;
|
||||
if (DrawableFilesDict.TryGetValue(namehash, out file))
|
||||
{
|
||||
var ydd = gfc.GetFileUncached<YddFile>(file);
|
||||
while ((ydd != null) && (!ydd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(ydd);
|
||||
}
|
||||
if (ydd?.Drawables?.Length > 0)
|
||||
{
|
||||
d = ydd.Drawables[0];//should only be one in this dict
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetaHash texhash = JenkHash.GenHash(tex.ToLowerInvariant());
|
||||
Texture t = null;
|
||||
if (Ytd?.TextureDict?.Dict != null)
|
||||
{
|
||||
Ytd.TextureDict.Dict.TryGetValue(texhash, out t);
|
||||
}
|
||||
if ((t == null) && (TextureFilesDict != null))
|
||||
{
|
||||
RpfFileEntry file = null;
|
||||
if (TextureFilesDict.TryGetValue(texhash, out file))
|
||||
{
|
||||
var ytd = gfc.GetFileUncached<YtdFile>(file);
|
||||
while ((ytd != null) && (!ytd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(ytd);
|
||||
}
|
||||
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
|
||||
{
|
||||
t = ytd.TextureDict.Textures.data_items[0];//should only be one in this dict
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CharacterCloth cc = null;
|
||||
if (Yld?.Dict != null)
|
||||
{
|
||||
Yld.Dict.TryGetValue(namehash, out cc);
|
||||
}
|
||||
if ((cc == null) && (ClothFilesDict != null))
|
||||
{
|
||||
RpfFileEntry file = null;
|
||||
if (ClothFilesDict.TryGetValue(namehash, out file))
|
||||
{
|
||||
var yld = gfc.GetFileUncached<YldFile>(file);
|
||||
while ((yld != null) && (!yld.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(yld);
|
||||
}
|
||||
if (yld?.ClothDictionary?.Clothes?.data_items?.Length > 0)
|
||||
{
|
||||
cc = yld.ClothDictionary.Clothes.data_items[0];//should only be one in this dict
|
||||
}
|
||||
}
|
||||
}
|
||||
ClothInstance c = null;
|
||||
if (cc != null)
|
||||
{
|
||||
c = new ClothInstance();
|
||||
c.Init(cc, Skeleton);
|
||||
}
|
||||
|
||||
Expression e = null;
|
||||
if (Yed?.ExprMap != null)
|
||||
{
|
||||
Yed.ExprMap.TryGetValue(namehash, out e);
|
||||
}
|
||||
|
||||
|
||||
if (d != null) Drawables[index] = d.ShallowCopy() as Drawable;
|
||||
if (t != null) Textures[index] = t;
|
||||
if (c != null) Clothes[index] = c;
|
||||
if (e != null) Expressions[index] = e;
|
||||
|
||||
DrawableNames[index] = name;
|
||||
}
|
||||
|
||||
public void SetComponentDrawable(int index, int drawbl, int alt, int tex, GameFileCache gfc)
|
||||
{
|
||||
var vi = Ymt?.VariationInfo;
|
||||
if (vi != null)
|
||||
{
|
||||
var compData = vi.GetComponentData(index);
|
||||
if (compData?.DrawblData3 != null)
|
||||
{
|
||||
var item = (drawbl < (compData.DrawblData3?.Length ?? 0)) ? compData.DrawblData3[drawbl] : null;
|
||||
if (item != null)
|
||||
{
|
||||
var name = item?.GetDrawableName(alt);
|
||||
var texn = item?.GetTextureName(tex);
|
||||
SetComponentDrawable(index, name, texn, gfc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadDefaultComponents(GameFileCache gfc)
|
||||
{
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
SetComponentDrawable(i, 0, 0, 0, gfc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void UpdateEntity()
|
||||
{
|
||||
RenderEntity.SetPosition(Position);
|
||||
RenderEntity.SetOrientation(Rotation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
206
C#/CodeWalker.Core/World/PopZones.cs
Normal file
206
C#/CodeWalker.Core/World/PopZones.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class PopZones : BasePathData
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
public GameFileCache GameFileCache;
|
||||
|
||||
public Dictionary<string, PopZone> Groups = new Dictionary<string, PopZone>();
|
||||
|
||||
public Vector4[] GetNodePositions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public EditorVertex[] GetPathVertices()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public EditorVertex[] GetTriangleVertices()
|
||||
{
|
||||
return TriangleVerts;
|
||||
}
|
||||
|
||||
public EditorVertex[] TriangleVerts;
|
||||
|
||||
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
Inited = false;
|
||||
|
||||
GameFileCache = gameFileCache;
|
||||
|
||||
var rpfman = gameFileCache.RpfMan;
|
||||
|
||||
string filename = "common.rpf\\data\\levels\\gta5\\popzone.ipl";
|
||||
if (gameFileCache.EnableDlc)
|
||||
{
|
||||
filename = "update\\update.rpf\\common\\data\\levels\\gta5\\popzone.ipl";
|
||||
}
|
||||
|
||||
string ipltext = rpfman.GetFileUTF8Text(filename);
|
||||
|
||||
if (string.IsNullOrEmpty(ipltext))
|
||||
{
|
||||
ipltext = "";
|
||||
}
|
||||
|
||||
Groups.Clear();
|
||||
|
||||
var ipllines = ipltext.Split('\n');
|
||||
bool inzone = false;
|
||||
foreach (var iplline in ipllines)
|
||||
{
|
||||
var linet = iplline.Trim();
|
||||
if (linet == "zone")
|
||||
{
|
||||
inzone = true;
|
||||
}
|
||||
else if (linet == "end")
|
||||
{
|
||||
inzone = false;
|
||||
}
|
||||
else if (inzone)
|
||||
{
|
||||
PopZoneBox box = new PopZoneBox();
|
||||
box.Init(linet);
|
||||
|
||||
PopZone group;
|
||||
if (!Groups.TryGetValue(box.NameLabel, out group))
|
||||
{
|
||||
group = new PopZone();
|
||||
group.NameLabel = box.NameLabel;
|
||||
Groups[box.NameLabel] = group;
|
||||
}
|
||||
|
||||
group.Boxes.Add(box);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var group in Groups.Values)
|
||||
{
|
||||
var hash = JenkHash.GenHash(group.NameLabel.ToLowerInvariant());
|
||||
group.Name = GlobalText.TryGetString(hash);
|
||||
}
|
||||
|
||||
|
||||
BuildVertices();
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void BuildVertices()
|
||||
{
|
||||
|
||||
var vlist = new List<EditorVertex>();
|
||||
var v1 = new EditorVertex();
|
||||
var v2 = new EditorVertex();
|
||||
var v3 = new EditorVertex();
|
||||
var v4 = new EditorVertex();
|
||||
|
||||
foreach (var group in Groups.Values)
|
||||
{
|
||||
var hash = JenkHash.GenHash(group.NameLabel.ToLowerInvariant());
|
||||
byte cr = (byte)((hash >> 8) & 0xFF);
|
||||
byte cg = (byte)((hash >> 16) & 0xFF);
|
||||
byte cb = (byte)((hash >> 24) & 0xFF);
|
||||
byte ca = 60;
|
||||
uint cv = (uint)new Color(cr, cg, cb, ca).ToRgba();
|
||||
v1.Colour = cv;
|
||||
v2.Colour = cv;
|
||||
v3.Colour = cv;
|
||||
v4.Colour = cv;
|
||||
|
||||
foreach (var box in group.Boxes)
|
||||
{
|
||||
var min = box.Box.Minimum;
|
||||
var max = box.Box.Maximum;
|
||||
|
||||
v1.Position = new Vector3(min.X, min.Y, 0);
|
||||
v2.Position = new Vector3(max.X, min.Y, 0);
|
||||
v3.Position = new Vector3(min.X, max.Y, 0);
|
||||
v4.Position = new Vector3(max.X, max.Y, 0);
|
||||
|
||||
vlist.Add(v1);
|
||||
vlist.Add(v2);
|
||||
vlist.Add(v3);
|
||||
vlist.Add(v3);
|
||||
vlist.Add(v2);
|
||||
vlist.Add(v4);
|
||||
}
|
||||
}
|
||||
|
||||
if (vlist.Count > 0)
|
||||
{
|
||||
TriangleVerts = vlist.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
TriangleVerts = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public class PopZone
|
||||
{
|
||||
public string NameLabel { get; set; }
|
||||
public string Name { get; set; } //lookup from gxt2 with label..?
|
||||
public List<PopZoneBox> Boxes { get; set; } = new List<PopZoneBox>();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return NameLabel + ": " + Name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class PopZoneBox
|
||||
{
|
||||
public string ID { get; set; }
|
||||
public BoundingBox Box { get; set; }
|
||||
public string NameLabel { get; set; }
|
||||
public float UnkVal { get; set; }
|
||||
|
||||
|
||||
public void Init(string iplline)
|
||||
{
|
||||
var parts = iplline.Split(',');
|
||||
if (parts.Length >= 9)
|
||||
{
|
||||
ID = parts[0].Trim();
|
||||
BoundingBox b = new BoundingBox();
|
||||
b.Minimum.X = FloatUtil.Parse(parts[1].Trim());
|
||||
b.Minimum.Y = FloatUtil.Parse(parts[2].Trim());
|
||||
b.Minimum.Z = FloatUtil.Parse(parts[3].Trim());
|
||||
b.Maximum.X = FloatUtil.Parse(parts[4].Trim());
|
||||
b.Maximum.Y = FloatUtil.Parse(parts[5].Trim());
|
||||
b.Maximum.Z = FloatUtil.Parse(parts[6].Trim());
|
||||
Box = b;
|
||||
NameLabel = parts[7].Trim();
|
||||
UnkVal = FloatUtil.Parse(parts[8].Trim());
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ID + ": " + NameLabel + ": " + Box.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
2209
C#/CodeWalker.Core/World/Scenarios.cs
Normal file
2209
C#/CodeWalker.Core/World/Scenarios.cs
Normal file
File diff suppressed because it is too large
Load Diff
2231
C#/CodeWalker.Core/World/Space.cs
Normal file
2231
C#/CodeWalker.Core/World/Space.cs
Normal file
File diff suppressed because it is too large
Load Diff
124
C#/CodeWalker.Core/World/Timecycle.cs
Normal file
124
C#/CodeWalker.Core/World/Timecycle.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
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 Timecycle
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
|
||||
public float sun_roll { get; set; }
|
||||
public float sun_yaw { get; set; }
|
||||
public float moon_roll { get; set; }
|
||||
public float moon_wobble_freq { get; set; }
|
||||
public float moon_wobble_amp { get; set; }
|
||||
public float moon_wobble_offset { get; set; }
|
||||
public List<TimecycleSample> Samples { get; set; } = new List<TimecycleSample>();
|
||||
public List<string> Regions { get; set; } = new List<string>();
|
||||
|
||||
public float CurrentHour { get; set; } = 0;
|
||||
public int CurrentSampleIndex { get; set; } = 0;
|
||||
public float CurrentSampleBlend { get; set; } = 1.0f;
|
||||
public float NextSampleBlend { get; set; } = 0.0f;
|
||||
public Vector3 CurrentSunDirection { get; set; } = new Vector3(0, 0, 1);
|
||||
public Vector3 CurrentMoonDirection { get; set; } = new Vector3(0, 0, -1);
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
var rpfman = gameFileCache.RpfMan;
|
||||
|
||||
string filename = "common.rpf\\data\\levels\\gta5\\time.xml";
|
||||
|
||||
XmlDocument timexml = rpfman.GetFileXml(filename);
|
||||
|
||||
XmlElement time = timexml.DocumentElement;
|
||||
XmlNode suninfo = time.SelectSingleNode("suninfo");
|
||||
XmlNode mooninfo = time.SelectSingleNode("mooninfo");
|
||||
XmlNodeList samples = time.SelectNodes("sample");
|
||||
XmlNodeList regions = time.SelectNodes("region");
|
||||
|
||||
sun_roll = Xml.GetFloatAttribute(suninfo, "sun_roll");
|
||||
sun_yaw = Xml.GetFloatAttribute(suninfo, "sun_yaw");
|
||||
moon_roll = Xml.GetFloatAttribute(mooninfo, "moon_roll");
|
||||
moon_wobble_freq = Xml.GetFloatAttribute(mooninfo, "moon_wobble_freq");
|
||||
moon_wobble_amp = Xml.GetFloatAttribute(mooninfo, "moon_wobble_amp");
|
||||
moon_wobble_offset = Xml.GetFloatAttribute(mooninfo, "moon_wobble_offset");
|
||||
|
||||
Samples.Clear();
|
||||
for (int i = 0; i < samples.Count; i++)
|
||||
{
|
||||
TimecycleSample tcs = new TimecycleSample();
|
||||
tcs.Init(samples[i]);
|
||||
Samples.Add(tcs);
|
||||
}
|
||||
|
||||
Regions.Clear();
|
||||
for (int i = 0; i < regions.Count; i++)
|
||||
{
|
||||
Regions.Add(Xml.GetStringAttribute(regions[i], "name"));
|
||||
}
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
|
||||
public void SetTime(float hour)
|
||||
{
|
||||
float day = Math.Max(hour / 24.0f, 0.0f);
|
||||
float h = hour - ((float)Math.Floor(day) * 24.0f);
|
||||
CurrentHour = h;
|
||||
|
||||
for (int i = 0; i < Samples.Count; i++)
|
||||
{
|
||||
bool lasti = (i >= Samples.Count - 1);
|
||||
var cur = Samples[i];
|
||||
var nxt = Samples[lasti ? 0 : i+1];
|
||||
var nxth = lasti ? nxt.hour + 24.0f : nxt.hour;
|
||||
if (((h >= cur.hour) && (h < nxth)) || lasti)
|
||||
{
|
||||
float blendrange = (nxth - cur.hour) - cur.duration;
|
||||
float blendstart = cur.hour + cur.duration;
|
||||
float blendrel = h - blendstart;
|
||||
float blendval = blendrel / blendrange;
|
||||
float blend = Math.Min(Math.Max(blendval, 0.0f), 1.0f);
|
||||
NextSampleBlend = blend;
|
||||
CurrentSampleBlend = 1.0f - blend;
|
||||
CurrentSampleIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNightTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return (CurrentHour < 6.0f) || (CurrentHour > 20.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TimecycleSample
|
||||
{
|
||||
public string name { get; set; }
|
||||
public float hour { get; set; }
|
||||
public float duration { get; set; }
|
||||
public string uw_tc_mod { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
name = Xml.GetStringAttribute(node, "name");
|
||||
hour = Xml.GetFloatAttribute(node, "hour");
|
||||
duration = Xml.GetFloatAttribute(node, "duration");
|
||||
uw_tc_mod = Xml.GetStringAttribute(node, "uw_tc_mod");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
148
C#/CodeWalker.Core/World/TimecycleMods.cs
Normal file
148
C#/CodeWalker.Core/World/TimecycleMods.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class TimecycleMods
|
||||
{
|
||||
|
||||
public Dictionary<uint, TimecycleMod> Dict = new Dictionary<uint, TimecycleMod>();
|
||||
|
||||
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
Dict.Clear();
|
||||
|
||||
var rpfman = gameFileCache.RpfMan;
|
||||
|
||||
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_1.xml"));
|
||||
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_2.xml"));
|
||||
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_3.xml"));
|
||||
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_4.xml"));
|
||||
|
||||
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_1.xml"));
|
||||
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_2.xml"));//doesn't exist, but try anyway
|
||||
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_3.xml"));
|
||||
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_4.xml"));
|
||||
|
||||
if (gameFileCache.EnableDlc)
|
||||
{
|
||||
foreach (var dlcrpf in gameFileCache.DlcActiveRpfs)
|
||||
{
|
||||
foreach (var file in dlcrpf.AllEntries)
|
||||
{
|
||||
if (file.NameLower.EndsWith(".xml") && file.NameLower.StartsWith("timecycle_mods_"))
|
||||
{
|
||||
LoadXml(rpfman.GetFileXml(file.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gameFileCache.TimeCycleModsDict = Dict;
|
||||
}
|
||||
|
||||
private void LoadXml(XmlDocument doc)
|
||||
{
|
||||
var root = doc.DocumentElement;
|
||||
if (root == null)
|
||||
{ return; }
|
||||
|
||||
float version = Xml.GetFloatAttribute(root, "version");
|
||||
|
||||
var modnodes = root.SelectNodes("modifier");
|
||||
foreach (XmlNode modnode in modnodes)
|
||||
{
|
||||
if (!(modnode is XmlElement)) continue;
|
||||
TimecycleMod mod = new TimecycleMod();
|
||||
mod.Init(modnode);
|
||||
Dict[mod.nameHash] = mod;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))]
|
||||
public class TimecycleMod
|
||||
{
|
||||
public string name { get; set; }
|
||||
public uint nameHash { get; set; }
|
||||
public int numMods { get; set; }
|
||||
public int userFlags { get; set; }
|
||||
|
||||
public TimecycleModValue[] Values { get; set; }
|
||||
public Dictionary<string, TimecycleModValue> Dict { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
Dict = new Dictionary<string, TimecycleModValue>();
|
||||
|
||||
name = Xml.GetStringAttribute(node, "name");
|
||||
numMods = Xml.GetIntAttribute(node, "numMods");
|
||||
userFlags = Xml.GetIntAttribute(node, "userFlags");
|
||||
|
||||
string namel = name.ToLowerInvariant();
|
||||
JenkIndex.Ensure(namel);
|
||||
nameHash = JenkHash.GenHash(namel);
|
||||
|
||||
List<TimecycleModValue> vals = new List<TimecycleModValue>();
|
||||
foreach (XmlNode valnode in node.ChildNodes)
|
||||
{
|
||||
if (!(valnode is XmlElement)) continue;
|
||||
|
||||
TimecycleModValue val = new TimecycleModValue();
|
||||
val.Init(valnode);
|
||||
|
||||
vals.Add(val);
|
||||
Dict[val.name] = val;
|
||||
}
|
||||
Values = vals.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name + " (" + numMods.ToString() + " mods, userFlags: " + userFlags.ToString() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))]
|
||||
public class TimecycleModValue
|
||||
{
|
||||
public string name { get; set; }
|
||||
public float value1 { get; set; }
|
||||
public float value2 { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
name = node.Name;
|
||||
|
||||
string valstr = node.InnerText;
|
||||
string[] valstrs = valstr.Split(' ');
|
||||
if (valstrs.Length == 2)
|
||||
{
|
||||
value1 = FloatUtil.Parse(valstrs[0]);
|
||||
value2 = FloatUtil.Parse(valstrs[1]);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name + ": " + FloatUtil.ToString(value1) + ", " + FloatUtil.ToString(value2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
436
C#/CodeWalker.Core/World/Trains.cs
Normal file
436
C#/CodeWalker.Core/World/Trains.cs
Normal file
@@ -0,0 +1,436 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using SharpDX;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class Trains
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
public GameFileCache GameFileCache;
|
||||
|
||||
public List<TrainTrack> TrainTracks { get; set; } = new List<TrainTrack>();
|
||||
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
GameFileCache = gameFileCache;
|
||||
|
||||
var rpfman = gameFileCache.RpfMan;
|
||||
|
||||
string trainsfilename = "common.rpf\\data\\levels\\gta5\\trains.xml";
|
||||
XmlDocument trainsxml = rpfman.GetFileXml(trainsfilename);
|
||||
XmlElement trainsdata = trainsxml.DocumentElement;
|
||||
//TODO: parse train_configs
|
||||
|
||||
|
||||
string tracksfilename = "common.rpf\\data\\levels\\gta5\\traintracks.xml";
|
||||
XmlDocument tracksxml = rpfman.GetFileXml(tracksfilename);
|
||||
XmlElement tracksdata = tracksxml.DocumentElement;
|
||||
XmlNodeList tracks = tracksdata.SelectNodes("train_track");
|
||||
|
||||
TrainTracks.Clear();
|
||||
for (int i = 0; i < tracks.Count; i++)
|
||||
{
|
||||
var trackxml = tracks[i];
|
||||
TrainTrack tt = new TrainTrack();
|
||||
tt.Load(gameFileCache, trackxml);
|
||||
TrainTracks.Add(tt);
|
||||
}
|
||||
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TrainTrack : BasePathData
|
||||
{
|
||||
public string filename { get; set; }
|
||||
public string trainConfigName { get; set; }
|
||||
public bool isPingPongTrack { get; set; }
|
||||
public bool stopsAtStations { get; set; }
|
||||
public bool MPstopsAtStations { get; set; }
|
||||
public float speed { get; set; }
|
||||
public float brakingDist { get; set; }
|
||||
|
||||
|
||||
public List<TrainTrackNode> Nodes { get; set; }
|
||||
public int NodeCount { get; set; }
|
||||
|
||||
|
||||
public int StationCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int sc = 0;
|
||||
if (Nodes != null)
|
||||
{
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
if ((node.NodeType == 1) || (node.NodeType == 2) || (node.NodeType == 5))
|
||||
{
|
||||
sc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public EditorVertex[] LinkedVerts { get; set; }
|
||||
public Vector4[] NodePositions { get; set; }
|
||||
|
||||
public EditorVertex[] GetPathVertices()
|
||||
{
|
||||
return LinkedVerts;
|
||||
}
|
||||
public EditorVertex[] GetTriangleVertices()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public Vector4[] GetNodePositions()
|
||||
{
|
||||
return NodePositions;
|
||||
}
|
||||
|
||||
public PathBVH BVH { get; set; }
|
||||
|
||||
public string NodesString { get; set; }
|
||||
public RpfFileEntry RpfFileEntry { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public bool HasChanged { get; set; }
|
||||
public bool Loaded { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
public void Load(GameFileCache gameFileCache, XmlNode node)
|
||||
{
|
||||
//load from game file cache
|
||||
|
||||
filename = Xml.GetStringAttribute(node, "filename");
|
||||
trainConfigName = Xml.GetStringAttribute(node, "trainConfigName");
|
||||
isPingPongTrack = Xml.GetBoolAttribute(node, "isPingPongTrack");
|
||||
stopsAtStations = Xml.GetBoolAttribute(node, "stopsAtStations");
|
||||
MPstopsAtStations = Xml.GetBoolAttribute(node, "MPstopsAtStations");
|
||||
speed = Xml.GetFloatAttribute(node, "speed");
|
||||
brakingDist = Xml.GetFloatAttribute(node, "brakingDist");
|
||||
|
||||
RpfFileEntry = gameFileCache.RpfMan.GetEntry(filename) as RpfFileEntry;
|
||||
NodesString = gameFileCache.RpfMan.GetFileUTF8Text(filename);
|
||||
SetNameFromFilename();
|
||||
FilePath = Name;
|
||||
|
||||
Load(NodesString);
|
||||
|
||||
BuildVertices();
|
||||
|
||||
BuildBVH();
|
||||
|
||||
Loaded = true;
|
||||
}
|
||||
|
||||
public void Load(byte[] data)
|
||||
{
|
||||
filename = string.Empty;
|
||||
trainConfigName = string.Empty;
|
||||
RpfFileEntry = new RpfBinaryFileEntry();
|
||||
|
||||
|
||||
string str = Encoding.UTF8.GetString(data);
|
||||
Load(str);
|
||||
|
||||
BuildVertices();
|
||||
|
||||
BuildBVH();
|
||||
|
||||
Loaded = true;
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
NodeCount = Nodes.Count;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine(Nodes.Count.ToString());
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
var nstr = FloatUtil.GetVector3String(node.Position).Replace(",","") + " " + node.NodeType.ToString();
|
||||
sb.AppendLine(nstr);
|
||||
}
|
||||
string str = sb.ToString();
|
||||
return Encoding.UTF8.GetBytes(str);
|
||||
}
|
||||
|
||||
|
||||
public void SetNameFromFilename()
|
||||
{
|
||||
string[] fparts = filename.Replace('\\', '/').Split('/');
|
||||
if ((fparts == null) || (fparts.Length == 0))
|
||||
{
|
||||
Name = filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = fparts[fparts.Length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Load(string trackstr)
|
||||
{
|
||||
//load nodes from a text string...
|
||||
NodesString = trackstr;
|
||||
|
||||
if (!string.IsNullOrEmpty(trackstr))
|
||||
{
|
||||
string[] trackstrs = trackstr.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (trackstrs.Length > 1)
|
||||
{
|
||||
int nodecount;
|
||||
int.TryParse(trackstrs[0], out nodecount);
|
||||
NodeCount = nodecount;
|
||||
List<TrainTrackNode> nodes = new List<TrainTrackNode>();
|
||||
for (int i = 1; i < trackstrs.Length; i++)
|
||||
{
|
||||
var nodestr = trackstrs[i].Trim();
|
||||
var nodevals = nodestr.Split(' ');
|
||||
if (nodevals.Length == 4)
|
||||
{
|
||||
TrainTrackNode ttnode = new TrainTrackNode();
|
||||
var x = FloatUtil.Parse(nodevals[0]);
|
||||
var y = FloatUtil.Parse(nodevals[1]);
|
||||
var z = FloatUtil.Parse(nodevals[2]);
|
||||
int nodetype;
|
||||
int.TryParse(nodevals[3], out nodetype);
|
||||
ttnode.Position = new Vector3(x, y, z);
|
||||
ttnode.NodeType = nodetype;
|
||||
ttnode.Track = this;
|
||||
ttnode.Index = nodes.Count;
|
||||
ttnode.Links[0] = (nodes.Count > 0) ? nodes[nodes.Count - 1] : null;
|
||||
if (ttnode.Links[0] != null)
|
||||
{
|
||||
ttnode.Links[0].Links[1] = ttnode;
|
||||
}
|
||||
nodes.Add(ttnode);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
Nodes = nodes;
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
else
|
||||
{ }
|
||||
|
||||
if (Nodes == null)
|
||||
{
|
||||
Nodes = new List<TrainTrackNode>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void BuildVertices()
|
||||
{
|
||||
if ((Nodes != null) && (Nodes.Count > 0))
|
||||
{
|
||||
var nc = Nodes.Count;
|
||||
var lc = nc - 1;
|
||||
var lvc = lc * 2;
|
||||
var np = new Vector4[nc];
|
||||
var lv = new EditorVertex[lvc];
|
||||
for (int i = 0; i < nc; i++)
|
||||
{
|
||||
np[i] = new Vector4(Nodes[i].Position, 1.0f);
|
||||
if (i > 0)
|
||||
{
|
||||
var l = i - 1;
|
||||
var li = l * 2;
|
||||
var ni = li + 1;
|
||||
lv[li].Position = Nodes[l].Position;
|
||||
lv[ni].Position = Nodes[i].Position;
|
||||
lv[li].Colour = (uint)Nodes[l].GetColour();
|
||||
lv[ni].Colour = (uint)Nodes[i].GetColour();
|
||||
}
|
||||
}
|
||||
NodePositions = np;
|
||||
LinkedVerts = lv;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void UpdateBvhForNode(TrainTrackNode node)
|
||||
{
|
||||
//this needs to be called when a node's position changes...
|
||||
//need to recalc the BVH for mouse intersection optimisation purposes.
|
||||
|
||||
//if (BVH == null) return;
|
||||
//BVH.UpdateForNode(node);
|
||||
|
||||
BuildBVH();
|
||||
|
||||
//also updates the NodePositions for the visible vertex
|
||||
if (Nodes != null)
|
||||
{
|
||||
for (int i = 0; i < Nodes.Count; i++)
|
||||
{
|
||||
if (Nodes[i] == node)
|
||||
{
|
||||
NodePositions[i] = new Vector4(node.Position, 1.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void BuildBVH()
|
||||
{
|
||||
BVH = new PathBVH(Nodes, 10, 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public TrainTrackNode AddNode(TrainTrackNode afternode = null)
|
||||
{
|
||||
int cnt = Nodes?.Count ?? 0;
|
||||
TrainTrackNode tn = new TrainTrackNode();
|
||||
tn.Track = this;
|
||||
tn.Index = (afternode != null) ? afternode.Index + 1 : cnt;
|
||||
|
||||
if (Nodes == null)
|
||||
{
|
||||
Nodes = new List<TrainTrackNode>();
|
||||
}
|
||||
|
||||
if (afternode != null)
|
||||
{
|
||||
TrainTrackNode aln = afternode.Links[1];
|
||||
if (aln != null) aln.Links[0] = tn;
|
||||
afternode.Links[1] = tn;
|
||||
tn.Links[0] = afternode;
|
||||
tn.Links[1] = aln;
|
||||
|
||||
int idx = tn.Index;
|
||||
Nodes.Insert(idx, tn);
|
||||
|
||||
for (int i = 0; i < Nodes.Count; i++)
|
||||
{
|
||||
Nodes[i].Index = i;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cnt > 0)
|
||||
{
|
||||
TrainTrackNode ln = Nodes[cnt - 1];
|
||||
tn.Links[0] = ln;
|
||||
ln.Links[1] = tn;
|
||||
}
|
||||
|
||||
Nodes.Add(tn);
|
||||
}
|
||||
|
||||
|
||||
NodeCount = Nodes.Count;
|
||||
|
||||
return tn;
|
||||
}
|
||||
|
||||
public bool RemoveNode(TrainTrackNode node)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
r = Nodes.Remove(node);
|
||||
|
||||
NodeCount = Nodes.Count;
|
||||
|
||||
if (r)
|
||||
{
|
||||
var l0 = node.Links[0];
|
||||
var l1 = node.Links[1];
|
||||
|
||||
if (l0 != null)
|
||||
{
|
||||
l0.Links[1] = l1;
|
||||
}
|
||||
if (l1 != null)
|
||||
{
|
||||
l1.Links[0] = l0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Nodes.Count; i++)
|
||||
{
|
||||
Nodes[i].Index = i;
|
||||
}
|
||||
|
||||
BuildVertices();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name + ": " + filename + " (" + NodeCount.ToString() + " nodes)";
|
||||
}
|
||||
}
|
||||
|
||||
public class TrainTrackNode : BasePathNode
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public int NodeType { get; set; }
|
||||
|
||||
public TrainTrack Track { get; set; }
|
||||
public int Index { get; set; }
|
||||
public TrainTrackNode[] Links { get; set; } = new TrainTrackNode[2];
|
||||
|
||||
public int GetColour()
|
||||
{
|
||||
switch (NodeType)
|
||||
{
|
||||
case 0: return new Color4(1.0f, 0.0f, 0.0f, 1.0f).ToRgba();
|
||||
case 1: return new Color4(1.0f, 1.0f, 0.0f, 1.0f).ToRgba();
|
||||
case 2: return new Color4(0.0f, 1.0f, 0.0f, 1.0f).ToRgba();
|
||||
case 3: return new Color4(0.0f, 1.0f, 1.0f, 1.0f).ToRgba();
|
||||
case 4: return new Color4(0.0f, 0.0f, 1.0f, 1.0f).ToRgba();
|
||||
case 5: return new Color4(1.0f, 0.0f, 1.0f, 1.0f).ToRgba();
|
||||
default: return new Color4(1.0f, 1.0f, 1.0f, 1.0f).ToRgba();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetPosition(Vector3 pos)
|
||||
{
|
||||
Position = pos;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Index.ToString() + ": " + NodeType.ToString();// + ": " + FloatUtil.GetVector3String(Position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
102
C#/CodeWalker.Core/World/Vehicle.cs
Normal file
102
C#/CodeWalker.Core/World/Vehicle.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class Vehicle
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public MetaHash NameHash { get; set; } = 0;//base vehicle name hash
|
||||
public MetaHash ModelHash { get; set; } = 0;//vehicle model name hash, can be _hi
|
||||
|
||||
public VehicleInitData InitData { get; set; } = null;
|
||||
public YftFile Yft { get; set; } = null;
|
||||
|
||||
public YcdFile ConvRoofDict { get; set; } = null;
|
||||
public ClipMapEntry ConvRoofClip { get; set; } = null;
|
||||
|
||||
public string DisplayMake { get; set; } = string.Empty;//make display name
|
||||
public string DisplayName { get; set; } = string.Empty;//model display name
|
||||
|
||||
public YmapEntityDef RenderEntity = new YmapEntityDef(); //placeholder entity object for rendering
|
||||
|
||||
public Vector3 Position { get; set; } = Vector3.Zero;
|
||||
public Quaternion Rotation { get; set; } = Quaternion.Identity;
|
||||
|
||||
|
||||
public void Init(string name, GameFileCache gfc, bool hidef = true)
|
||||
{
|
||||
Name = name;
|
||||
var modelnamel = name.ToLowerInvariant();
|
||||
MetaHash modelhash = JenkHash.GenHash(modelnamel);
|
||||
MetaHash modelhashhi = JenkHash.GenHash(modelnamel + "_hi");
|
||||
var yfthash = hidef ? modelhashhi : modelhash;
|
||||
|
||||
VehicleInitData vid = null;
|
||||
if (gfc.VehiclesInitDict.TryGetValue(modelhash, out vid))
|
||||
{
|
||||
bool vehiclechange = NameHash != modelhash;
|
||||
ConvRoofDict = null;
|
||||
ConvRoofClip = null;
|
||||
ModelHash = yfthash;
|
||||
NameHash = modelhash;
|
||||
InitData = vid;
|
||||
Yft = gfc.GetYft(ModelHash);
|
||||
while ((Yft != null) && (!Yft.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Yft = gfc.GetYft(ModelHash);
|
||||
}
|
||||
|
||||
DisplayMake = GlobalText.TryGetString(JenkHash.GenHash(vid.vehicleMakeName.ToLowerInvariant()));
|
||||
DisplayName = GlobalText.TryGetString(JenkHash.GenHash(vid.gameName.ToLowerInvariant()));
|
||||
|
||||
if (!string.IsNullOrEmpty(vid.animConvRoofDictName) && (vid.animConvRoofDictName.ToLowerInvariant() != "null"))
|
||||
{
|
||||
var ycdhash = JenkHash.GenHash(vid.animConvRoofDictName.ToLowerInvariant());
|
||||
var cliphash = JenkHash.GenHash(vid.animConvRoofName?.ToLowerInvariant());
|
||||
ConvRoofDict = gfc.GetYcd(ycdhash);
|
||||
while ((ConvRoofDict != null) && (!ConvRoofDict.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
ConvRoofDict = gfc.GetYcd(ycdhash);
|
||||
}
|
||||
ClipMapEntry cme = null;
|
||||
ConvRoofDict?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||
ConvRoofClip = cme;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelHash = 0;
|
||||
NameHash = 0;
|
||||
InitData = null;
|
||||
Yft = null;
|
||||
DisplayMake = "-";
|
||||
DisplayName = "-";
|
||||
ConvRoofDict = null;
|
||||
ConvRoofClip = null;
|
||||
}
|
||||
|
||||
|
||||
UpdateEntity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void UpdateEntity()
|
||||
{
|
||||
RenderEntity.SetPosition(Position);
|
||||
RenderEntity.SetOrientation(Rotation);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
225
C#/CodeWalker.Core/World/Water.cs
Normal file
225
C#/CodeWalker.Core/World/Water.cs
Normal file
@@ -0,0 +1,225 @@
|
||||
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<WaterQuad> WaterQuads = new List<WaterQuad>();
|
||||
public List<WaterCalmingQuad> CalmingQuads = new List<WaterCalmingQuad>();
|
||||
public List<WaterWaveQuad> WaveQuads = new List<WaterWaveQuad>();
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
for (int i = 0; i < wavequads.Count; i++)
|
||||
{
|
||||
var wavequad = new WaterWaveQuad();
|
||||
wavequad.Init(wavequads[i], i);
|
||||
WaveQuads.Add(wavequad);
|
||||
}
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<T> GetVisibleQuads<T>(Camera camera, IEnumerable<T> allQuads) where T : BaseWaterQuad
|
||||
{
|
||||
List<T> quads = new List<T>();
|
||||
|
||||
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 string.Format("[{0}] X=({1} : {2}), Y=({3} : {4})", xmlNodeIndex, minX, maxX, 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");
|
||||
|
||||
/*
|
||||
<minX value="-1592" />
|
||||
<maxX value="-1304" />
|
||||
<minY value="-1744" />
|
||||
<maxY value="-1624" />
|
||||
<Type value="0" />
|
||||
<IsInvisible value="false" />
|
||||
<HasLimitedDepth value="false" />
|
||||
<z value="0.0" />
|
||||
<a1 value="26" />
|
||||
<a2 value="26" />
|
||||
<a3 value="26" />
|
||||
<a4 value="26" />
|
||||
<NoStencil value="false" />
|
||||
*/
|
||||
|
||||
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");
|
||||
|
||||
/*
|
||||
<minX value="1752" />
|
||||
<maxX value="2076" />
|
||||
<minY value="216" />
|
||||
<maxY value="800" />
|
||||
<fDampening value="0.05" />
|
||||
*/
|
||||
|
||||
CalcBS();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class WaterWaveQuad : BaseWaterQuad
|
||||
{
|
||||
public float Amplitude { get; set; }
|
||||
public float XDirection { get; set; }
|
||||
public float YDirection { get; set; }
|
||||
public Quaternion WaveOrientation { 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");
|
||||
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);
|
||||
WaveOrientation = Quaternion.RotationYawPitchRoll(0.0f, 0.0f, angl);
|
||||
|
||||
/*
|
||||
<minX value="1664" />
|
||||
<maxX value="1988" />
|
||||
<minY value="-120" />
|
||||
<maxY value="132" />
|
||||
<Amplitude value="0.1" />
|
||||
<XDirection value="-0.603208" />
|
||||
<YDirection value="-0.797584" />
|
||||
*/
|
||||
|
||||
CalcBS();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
290
C#/CodeWalker.Core/World/Watermaps.cs
Normal file
290
C#/CodeWalker.Core/World/Watermaps.cs
Normal file
@@ -0,0 +1,290 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
public class Watermaps : BasePathData
|
||||
{
|
||||
public volatile bool Inited = false;
|
||||
public GameFileCache GameFileCache;
|
||||
|
||||
public List<WatermapFile> WatermapFiles = new List<WatermapFile>();
|
||||
|
||||
|
||||
public Vector4[] GetNodePositions()
|
||||
{
|
||||
return NodePositions;
|
||||
}
|
||||
public EditorVertex[] GetPathVertices()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public EditorVertex[] GetTriangleVertices()
|
||||
{
|
||||
return TriangleVerts;
|
||||
}
|
||||
|
||||
public Vector4[] NodePositions;
|
||||
public EditorVertex[] TriangleVerts;
|
||||
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
||||
{
|
||||
Inited = false;
|
||||
|
||||
GameFileCache = gameFileCache;
|
||||
|
||||
|
||||
WatermapFiles.Clear();
|
||||
|
||||
|
||||
LoadWatermap("common.rpf\\data\\levels\\gta5\\waterheight.dat");
|
||||
|
||||
|
||||
|
||||
BuildVertices();
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
private void LoadWatermap(string filename)
|
||||
{
|
||||
var wmf = GameFileCache.RpfMan.GetFile<WatermapFile>(filename);
|
||||
WatermapFiles.Add(wmf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void BuildVertices()
|
||||
{
|
||||
|
||||
var vlist = new List<EditorVertex>();
|
||||
var nlist = new List<Vector4>();
|
||||
|
||||
foreach (var wmf in WatermapFiles)
|
||||
{
|
||||
BuildWatermapVertices(wmf, vlist, nlist);
|
||||
}
|
||||
|
||||
if (vlist.Count > 0)
|
||||
{
|
||||
TriangleVerts = vlist.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
TriangleVerts = null;
|
||||
}
|
||||
if (nlist.Count > 0)
|
||||
{
|
||||
NodePositions = nlist.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
NodePositions = null;
|
||||
}
|
||||
|
||||
}
|
||||
private void BuildWatermapVertices(WatermapFile wmf, List<EditorVertex> vl, List<Vector4> nl)
|
||||
{
|
||||
var v1 = new EditorVertex();
|
||||
var v2 = new EditorVertex();
|
||||
var v3 = new EditorVertex();
|
||||
var v4 = new EditorVertex();
|
||||
|
||||
uint cblu = (uint)new Color(0, 0, 128, 60).ToRgba();
|
||||
|
||||
|
||||
float getHeight(int o)
|
||||
{
|
||||
var harr = wmf.GridWatermapRefs[o];
|
||||
if (harr == null) return 0;
|
||||
if (harr.Length == 0) return 0;
|
||||
var h0 = harr[0];
|
||||
var i0 = h0.Item;
|
||||
if (h0.Type == WatermapFile.WaterItemType.River)
|
||||
{
|
||||
return h0.Vector.Z;
|
||||
}
|
||||
if (h0.Type == WatermapFile.WaterItemType.Lake)
|
||||
{
|
||||
if (i0 != null) return i0.Position.Z;
|
||||
}
|
||||
if (h0.Type == WatermapFile.WaterItemType.Pool)
|
||||
{
|
||||
if (i0 != null) return i0.Position.Z;
|
||||
}
|
||||
return h0.Vector.Z;
|
||||
}
|
||||
uint getColour(int o)
|
||||
{
|
||||
var harr = wmf.GridWatermapRefs[o];
|
||||
if (harr == null) return cblu;
|
||||
if (harr.Length == 0) return cblu;
|
||||
var i0 = harr[0].Item;
|
||||
if (i0 == null) return cblu;
|
||||
var c = i0.Colour;
|
||||
c.A = 128;
|
||||
return (uint)c.ToRgba();
|
||||
}
|
||||
var w = wmf.Width;
|
||||
var h = wmf.Height;
|
||||
var min = new Vector3(wmf.CornerX, wmf.CornerY, 0.0f);
|
||||
var step = new Vector3(wmf.TileX, -wmf.TileY, 1.0f);
|
||||
//var siz = new Vector3(w, h, 1) * step;
|
||||
for (int yi = 1; yi < h; yi++)
|
||||
{
|
||||
var yo = yi - 1;
|
||||
for (int xi = 1; xi < w; xi++)
|
||||
{
|
||||
var xo = xi - 1;
|
||||
var o1 = yi * w + xo;
|
||||
var o2 = yi * w + xi;
|
||||
var o3 = yo * w + xo;
|
||||
var o4 = yo * w + xi;
|
||||
v1.Position = min + step * new Vector3(xo, yi, getHeight(o1));
|
||||
v2.Position = min + step * new Vector3(xi, yi, getHeight(o2));
|
||||
v3.Position = min + step * new Vector3(xo, yo, getHeight(o3));
|
||||
v4.Position = min + step * new Vector3(xi, yo, getHeight(o4));
|
||||
v1.Colour = getColour(o1);
|
||||
v2.Colour = getColour(o2);
|
||||
v3.Colour = getColour(o3);
|
||||
v4.Colour = getColour(o4);
|
||||
//vl.Add(v1); vl.Add(v2); vl.Add(v3);
|
||||
//vl.Add(v3); vl.Add(v2); vl.Add(v4);
|
||||
}
|
||||
}
|
||||
//for (int y = 0; y < h; y++)
|
||||
//{
|
||||
// for (int x = 0; x < w; x++)
|
||||
// {
|
||||
// var o = y * w + x;
|
||||
// nl.Add(new Vector4(min + step * new Vector3(x, y, getHeight(o)), 10));
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
void addQuad(Quad q)
|
||||
{
|
||||
v1.Position = q.P1;
|
||||
v2.Position = q.P2;
|
||||
v3.Position = q.P3;
|
||||
v4.Position = q.P4;
|
||||
vl.Add(v1); vl.Add(v2); vl.Add(v3);
|
||||
vl.Add(v3); vl.Add(v2); vl.Add(v4);
|
||||
}
|
||||
void addRivEnd(Vector3 p, Vector3 s, Vector3 d, float r)
|
||||
{
|
||||
v1.Position = p;
|
||||
v2.Position = p + s * r;
|
||||
v3.Position = p + d * r;
|
||||
v4.Position = p - s * r;
|
||||
vl.Add(v1); vl.Add(v2); vl.Add(v3);
|
||||
vl.Add(v1); vl.Add(v3); vl.Add(v4);
|
||||
}
|
||||
var rivers = wmf.Rivers;
|
||||
if (rivers != null)
|
||||
{
|
||||
foreach (var river in rivers)
|
||||
{
|
||||
if ((river.Vectors == null) || (river.VectorCount <= 1))
|
||||
{ continue; }
|
||||
|
||||
var rwid = 20.0f;
|
||||
var rc = river.Colour;
|
||||
rc.A = 128;
|
||||
v1.Colour = v2.Colour = v3.Colour = v4.Colour = (uint)rc.ToRgba();
|
||||
var quads = new Quad[river.Vectors.Length - 1];
|
||||
var li = river.Vectors.Length - 1;
|
||||
for (int i = 1; i < river.Vectors.Length; i++)
|
||||
{
|
||||
var o = i - 1;
|
||||
var vo = river.Vectors[o];
|
||||
var vi = river.Vectors[i];
|
||||
var dif = vi.XYZ() - vo.XYZ();
|
||||
var dir = Vector3.Normalize(dif);
|
||||
var sid = Vector3.Normalize(Vector3.Cross(dir, Vector3.UnitZ));
|
||||
if (Math.Abs(dir.Z) > 0.95f)
|
||||
{
|
||||
dir = Vector3.UnitY;
|
||||
sid = Vector3.UnitX;
|
||||
}
|
||||
quads[o].P1 = vo.XYZ() - sid*rwid;
|
||||
quads[o].P2 = vo.XYZ() + sid*rwid;
|
||||
quads[o].P3 = vi.XYZ() - sid*rwid;
|
||||
quads[o].P4 = vi.XYZ() + sid*rwid;
|
||||
if (i == 1) addRivEnd(vo.XYZ(), -sid, -dir, rwid);
|
||||
if (i == li) addRivEnd(vi.XYZ(), sid, dir, rwid);
|
||||
}
|
||||
for (int i = 1; i < quads.Length; i++)
|
||||
{
|
||||
var o = i - 1;
|
||||
quads[o].P3 = quads[i].P1 = (quads[o].P3 + quads[i].P1) * 0.5f;
|
||||
quads[o].P4 = quads[i].P2 = (quads[o].P4 + quads[i].P2) * 0.5f;
|
||||
}
|
||||
for (int i = 0; i < quads.Length; i++)
|
||||
{
|
||||
addQuad(quads[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
var lakes = wmf.Lakes;
|
||||
if (lakes != null)
|
||||
{
|
||||
foreach (var lake in lakes)
|
||||
{
|
||||
if ((lake.Vectors == null) || (lake.VectorCount == 0))
|
||||
{ continue; }
|
||||
|
||||
var lp = lake.Position;
|
||||
var lc = lake.Colour;
|
||||
lc.A = 128;
|
||||
v1.Colour = v2.Colour = v3.Colour = v4.Colour = (uint)lc.ToRgba();
|
||||
for (int i = 0; i < lake.Vectors.Length; i++)
|
||||
{
|
||||
var vi = lake.Vectors[i];
|
||||
var vp = new Vector3(vi.X, vi.Y, lp.Z);
|
||||
var q = new Quad();
|
||||
q.P1 = vp + new Vector3(vi.Z, -vi.W, 0);
|
||||
q.P2 = vp + new Vector3(vi.Z, vi.W, 0);
|
||||
q.P3 = vp + new Vector3(-vi.Z, -vi.W, 0);
|
||||
q.P4 = vp + new Vector3(-vi.Z, vi.W, 0);
|
||||
addQuad(q);
|
||||
}
|
||||
}
|
||||
}
|
||||
var pools = wmf.Pools;
|
||||
if (pools != null)
|
||||
{
|
||||
foreach (var pool in pools)
|
||||
{
|
||||
var pp = pool.Position;
|
||||
var ps = pool.Size;
|
||||
var pc = pool.Colour;
|
||||
pc.A = 128;
|
||||
v1.Colour = v2.Colour = v3.Colour = v4.Colour = (uint)pc.ToRgba();
|
||||
var q = new Quad();
|
||||
q.P1 = pp + new Vector3(ps.X, -ps.Y, 0);
|
||||
q.P2 = pp + new Vector3(ps.X, ps.Y, 0);
|
||||
q.P3 = pp + new Vector3(-ps.X, -ps.Y, 0);
|
||||
q.P4 = pp + new Vector3(-ps.X, ps.Y, 0);
|
||||
addQuad(q);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Quad
|
||||
{
|
||||
public Vector3 P1;
|
||||
public Vector3 P2;
|
||||
public Vector3 P3;
|
||||
public Vector3 P4;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
C#/CodeWalker.Core/World/Weapon.cs
Normal file
70
C#/CodeWalker.Core/World/Weapon.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.World
|
||||
{
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class Weapon
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public MetaHash NameHash { get; set; } = 0;//base weapon name hash
|
||||
public MetaHash ModelHash { get; set; } = 0;//weapon model name hash, can be _hi
|
||||
|
||||
public YdrFile Ydr { get; set; } = null;
|
||||
public Drawable Drawable { get; set; } = null;
|
||||
|
||||
public YmapEntityDef RenderEntity = new YmapEntityDef(); //placeholder entity object for rendering
|
||||
|
||||
public Vector3 Position { get; set; } = Vector3.Zero;
|
||||
public Quaternion Rotation { get; set; } = Quaternion.Identity;
|
||||
|
||||
|
||||
public void Init(string name, GameFileCache gfc, bool hidef = true)
|
||||
{
|
||||
Name = name;
|
||||
var modelnamel = name.ToLowerInvariant();
|
||||
MetaHash modelhash = JenkHash.GenHash(modelnamel);
|
||||
MetaHash modelhashhi = JenkHash.GenHash(modelnamel + "_hi");
|
||||
var ydrhash = hidef ? modelhashhi : modelhash;
|
||||
|
||||
NameHash = modelhash;
|
||||
ModelHash = ydrhash;
|
||||
|
||||
var useHash = ModelHash;
|
||||
Ydr = gfc.GetYdr(ModelHash);
|
||||
if (Ydr == null)
|
||||
{
|
||||
useHash = NameHash;
|
||||
Ydr = gfc.GetYdr(NameHash);
|
||||
}
|
||||
|
||||
while ((Ydr != null) && (!Ydr.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ydr = gfc.GetYdr(useHash);
|
||||
}
|
||||
|
||||
if (Ydr != null)
|
||||
{
|
||||
Drawable = Ydr.Drawable?.ShallowCopy() as Drawable;
|
||||
}
|
||||
|
||||
|
||||
UpdateEntity();
|
||||
}
|
||||
|
||||
|
||||
public void UpdateEntity()
|
||||
{
|
||||
RenderEntity.SetPosition(Position);
|
||||
RenderEntity.SetOrientation(Rotation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
569
C#/CodeWalker.Core/World/Weather.cs
Normal file
569
C#/CodeWalker.Core/World/Weather.cs
Normal file
@@ -0,0 +1,569 @@
|
||||
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 Weather
|
||||
{
|
||||
|
||||
public Dictionary<string, WeatherGpuFx> WeatherGpuFx { get; set; } = new Dictionary<string, WeatherGpuFx>();
|
||||
public Dictionary<string, WeatherType> WeatherTypes { get; set; } = new Dictionary<string, WeatherType>();
|
||||
public List<WeatherCycle> WeatherCycles { get; set; } = new List<WeatherCycle>();
|
||||
public WeatherValues CurrentValues;
|
||||
|
||||
public volatile bool Inited = false;
|
||||
public WeatherType CurrentWeatherType;
|
||||
public WeatherType NextWeatherType;
|
||||
public float WeatherChangeTime = 0.33f;
|
||||
public float CurrentWeatherChangeTime = 0.0f;
|
||||
public float CurrentWeatherChangeBlend = 0.0f;
|
||||
public string Region = "GLOBAL"; //URBAN or GLOBAL..
|
||||
public WeatherCycleKeyframeRegion CurrentWeatherRegion;
|
||||
public WeatherCycleKeyframeRegion NextWeatherRegion;
|
||||
|
||||
public Timecycle Timecycle;
|
||||
public TimecycleMods TimecycleMods;
|
||||
|
||||
public void Init(GameFileCache gameFileCache, Action<string> updateStatus, Timecycle timecycle)
|
||||
{
|
||||
Timecycle = timecycle;
|
||||
var rpfman = gameFileCache.RpfMan;
|
||||
|
||||
//TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it!
|
||||
string filename = "common.rpf\\data\\levels\\gta5\\weather.xml";
|
||||
if (gameFileCache.EnableDlc)
|
||||
{
|
||||
filename = "update\\update.rpf\\common\\data\\levels\\gta5\\weather.xml";
|
||||
}
|
||||
|
||||
XmlDocument weatherxml = rpfman.GetFileXml(filename);
|
||||
|
||||
XmlElement weather = weatherxml.DocumentElement;
|
||||
|
||||
XmlNodeList weathergpufx = weather.SelectNodes("WeatherGpuFx/Item");
|
||||
WeatherGpuFx.Clear();
|
||||
for (int i = 0; i < weathergpufx.Count; i++)
|
||||
{
|
||||
var weathergpufxi = new WeatherGpuFx();
|
||||
weathergpufxi.Init(weathergpufx[i]);
|
||||
WeatherGpuFx[weathergpufxi.Name] = weathergpufxi;
|
||||
}
|
||||
|
||||
XmlNodeList weathertypes = weather.SelectNodes("WeatherTypes/Item");
|
||||
WeatherTypes.Clear();
|
||||
for (int i = 0; i < weathertypes.Count; i++)
|
||||
{
|
||||
var weathertype = new WeatherType();
|
||||
weathertype.Init(gameFileCache, weathertypes[i]);
|
||||
WeatherTypes[weathertype.Name] = weathertype;
|
||||
}
|
||||
|
||||
XmlNodeList weathercycles = weather.SelectNodes("WeatherCycles/Item");
|
||||
WeatherCycles.Clear();
|
||||
for (int i = 0; i < weathercycles.Count; i++)
|
||||
{
|
||||
var weathercycle = new WeatherCycle();
|
||||
weathercycle.Init(weathercycles[i]);
|
||||
WeatherCycles.Add(weathercycle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (WeatherTypes.Count > 0)
|
||||
{
|
||||
CurrentWeatherType = WeatherTypes.Values.First();
|
||||
CurrentWeatherRegion = CurrentWeatherType.GetRegion(Region);
|
||||
NextWeatherType = CurrentWeatherType;
|
||||
NextWeatherRegion = NextWeatherType.GetRegion(Region);
|
||||
}
|
||||
|
||||
|
||||
TimecycleMods = new TimecycleMods();
|
||||
TimecycleMods.Init(gameFileCache, updateStatus);
|
||||
|
||||
|
||||
Inited = true;
|
||||
}
|
||||
|
||||
public void Update(float elapsed)
|
||||
{
|
||||
if (!Inited) return;
|
||||
|
||||
if (CurrentWeatherType != NextWeatherType)
|
||||
{
|
||||
CurrentWeatherChangeTime += elapsed;
|
||||
if (CurrentWeatherChangeTime >= WeatherChangeTime)
|
||||
{
|
||||
CurrentWeatherType = NextWeatherType;
|
||||
CurrentWeatherChangeTime = 0.0f;
|
||||
}
|
||||
CurrentWeatherChangeBlend = Math.Min(CurrentWeatherChangeTime / WeatherChangeTime, 1.0f);
|
||||
}
|
||||
if (CurrentWeatherType != null)
|
||||
{
|
||||
CurrentWeatherRegion = CurrentWeatherType.GetRegion(Region);
|
||||
}
|
||||
if (NextWeatherType != null)
|
||||
{
|
||||
NextWeatherRegion = NextWeatherType.GetRegion(Region);
|
||||
}
|
||||
|
||||
CurrentValues.Update(this);
|
||||
}
|
||||
|
||||
public void SetNextWeather(string name)
|
||||
{
|
||||
WeatherTypes.TryGetValue(name, out NextWeatherType);
|
||||
if (NextWeatherType == null)
|
||||
{
|
||||
NextWeatherType = CurrentWeatherType;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentWeatherChangeTime = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetDynamicValue(string name)
|
||||
{
|
||||
int csi = Timecycle.CurrentSampleIndex;
|
||||
float csb = Timecycle.CurrentSampleBlend;
|
||||
if ((CurrentWeatherRegion != null) && (NextWeatherRegion != null))
|
||||
{
|
||||
float cv = CurrentWeatherRegion.GetCurrentValue(name, csi, csb);
|
||||
float nv = NextWeatherRegion.GetCurrentValue(name, csi, csb);
|
||||
return cv * (1.0f - CurrentWeatherChangeBlend) + nv * CurrentWeatherChangeBlend;
|
||||
}
|
||||
else if (CurrentWeatherRegion != null)
|
||||
{
|
||||
return CurrentWeatherRegion.GetCurrentValue(name, csi, csb);
|
||||
}
|
||||
//throw new Exception("CurrentWeatherRegion was null.");
|
||||
return 0.0f;
|
||||
}
|
||||
public Vector3 GetDynamicRGB(string rname, string gname, string bname)
|
||||
{
|
||||
int csi = Timecycle.CurrentSampleIndex;
|
||||
float csb = Timecycle.CurrentSampleBlend;
|
||||
if ((CurrentWeatherRegion != null) && (NextWeatherRegion != null))
|
||||
{
|
||||
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
|
||||
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
|
||||
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
|
||||
float nvr = NextWeatherRegion.GetCurrentValue(rname, csi, csb);
|
||||
float nvg = NextWeatherRegion.GetCurrentValue(gname, csi, csb);
|
||||
float nvb = NextWeatherRegion.GetCurrentValue(bname, csi, csb);
|
||||
Vector3 cv = new Vector3(cvr, cvg, cvb);
|
||||
Vector3 nv = new Vector3(nvr, nvg, nvb);
|
||||
return cv * (1.0f - CurrentWeatherChangeBlend) + nv * CurrentWeatherChangeBlend;
|
||||
}
|
||||
else if (CurrentWeatherRegion != null)
|
||||
{
|
||||
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
|
||||
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
|
||||
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
|
||||
return new Vector3(cvr, cvg, cvb);
|
||||
}
|
||||
//throw new Exception("CurrentWeatherRegion was null.");
|
||||
return Vector3.Zero;
|
||||
}
|
||||
public Vector4 GetDynamicRGBA(string rname, string gname, string bname, string aname)
|
||||
{
|
||||
int csi = Timecycle.CurrentSampleIndex;
|
||||
float csb = Timecycle.CurrentSampleBlend;
|
||||
if ((CurrentWeatherRegion != null) && (NextWeatherRegion != null))
|
||||
{
|
||||
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
|
||||
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
|
||||
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
|
||||
float cva = CurrentWeatherRegion.GetCurrentValue(aname, csi, csb);
|
||||
float nvr = NextWeatherRegion.GetCurrentValue(rname, csi, csb);
|
||||
float nvg = NextWeatherRegion.GetCurrentValue(gname, csi, csb);
|
||||
float nvb = NextWeatherRegion.GetCurrentValue(bname, csi, csb);
|
||||
float nva = NextWeatherRegion.GetCurrentValue(aname, csi, csb);
|
||||
Vector4 cv = new Vector4(cvr, cvg, cvb, cva);
|
||||
Vector4 nv = new Vector4(nvr, nvg, nvb, nva);
|
||||
return cv * (1.0f - CurrentWeatherChangeBlend) + nv * CurrentWeatherChangeBlend;
|
||||
}
|
||||
else if (CurrentWeatherRegion != null)
|
||||
{
|
||||
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
|
||||
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
|
||||
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
|
||||
float cva = CurrentWeatherRegion.GetCurrentValue(aname, csi, csb);
|
||||
return new Vector4(cvr, cvg, cvb, cva);
|
||||
}
|
||||
//throw new Exception("CurrentWeatherRegion was null.");
|
||||
return Vector4.Zero;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class WeatherGpuFx
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string SystemType { get; set; }
|
||||
public string diffuseName { get; set; }
|
||||
public string distortionTexture { get; set; }
|
||||
public string diffuseSplashName { get; set; }
|
||||
public string driveType { get; set; }
|
||||
public float windInfluence { get; set; }
|
||||
public float gravity { get; set; }
|
||||
public string emitterSettingsName { get; set; }
|
||||
public string renderSettingsName { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
Name = Xml.GetChildInnerText(node, "Name");
|
||||
SystemType = Xml.GetChildInnerText(node, "SystemType");
|
||||
diffuseName = Xml.GetChildInnerText(node, "diffuseName");
|
||||
distortionTexture = Xml.GetChildInnerText(node, "distortionTexture");
|
||||
diffuseSplashName = Xml.GetChildInnerText(node, "diffuseSplashName");
|
||||
driveType = Xml.GetChildInnerText(node, "driveType");
|
||||
windInfluence = Xml.GetChildFloatAttribute(node, "windInfluence", "value");
|
||||
gravity = Xml.GetChildFloatAttribute(node, "gravity", "value");
|
||||
emitterSettingsName = Xml.GetChildInnerText(node, "emitterSettingsName");
|
||||
renderSettingsName = Xml.GetChildInnerText(node, "renderSettingsName");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public class WeatherType
|
||||
{
|
||||
public MetaHash NameHash { get; set; }
|
||||
public string Name { get; set; }
|
||||
public float Sun { get; set; }
|
||||
public float Cloud { get; set; }
|
||||
public float WindMin { get; set; }
|
||||
public float WindMax { get; set; }
|
||||
public float Rain { get; set; }
|
||||
public float Snow { get; set; }
|
||||
public float SnowMist { get; set; }
|
||||
public float Fog { get; set; }
|
||||
public float RippleBumpiness { get; set; }
|
||||
public float RippleMinBumpiness { get; set; }
|
||||
public float RippleMaxBumpiness { get; set; }
|
||||
public float RippleBumpinessWindScale { get; set; }
|
||||
public float RippleScale { get; set; }
|
||||
public float RippleSpeed { get; set; }
|
||||
public float RippleVelocityTransfer { get; set; }
|
||||
public float OceanBumpiness { get; set; }
|
||||
public float DeepOceanScale { get; set; }
|
||||
public float OceanNoiseMinAmplitude { get; set; }
|
||||
public float OceanWaveAmplitude { get; set; }
|
||||
public float ShoreWaveAmplitude { get; set; }
|
||||
public float OceanWaveWindScale { get; set; }
|
||||
public float ShoreWaveWindScale { get; set; }
|
||||
public float OceanWaveMinAmplitude { get; set; }
|
||||
public float ShoreWaveMinAmplitude { get; set; }
|
||||
public float OceanWaveMaxAmplitude { get; set; }
|
||||
public float ShoreWaveMaxAmplitude { get; set; }
|
||||
public float OceanFoamIntensity { get; set; }
|
||||
public float OceanFoamScale { get; set; }
|
||||
public float RippleDisturb { get; set; }
|
||||
public float Lightning { get; set; }
|
||||
public float Sandstorm { get; set; }
|
||||
public string OldSettingName { get; set; }
|
||||
public string DropSettingName { get; set; }
|
||||
public string MistSettingName { get; set; }
|
||||
public string GroundSettingName { get; set; }
|
||||
public string TimeCycleFilename { get; set; }
|
||||
public string CloudSettingsName { get; set; }
|
||||
|
||||
public WeatherCycleKeyframeData TimeCycleData;
|
||||
|
||||
public void Init(GameFileCache gameFileCache, XmlNode node)
|
||||
{
|
||||
Name = Xml.GetChildInnerText(node, "Name");
|
||||
NameHash = new MetaHash(JenkHash.GenHash(Name.ToLowerInvariant()));
|
||||
Sun = Xml.GetChildFloatAttribute(node, "Sun", "value");
|
||||
Cloud = Xml.GetChildFloatAttribute(node, "Cloud", "value");
|
||||
WindMin = Xml.GetChildFloatAttribute(node, "WindMin", "value");
|
||||
WindMax = Xml.GetChildFloatAttribute(node, "WindMax", "value");
|
||||
Rain = Xml.GetChildFloatAttribute(node, "Rain", "value");
|
||||
Snow = Xml.GetChildFloatAttribute(node, "Snow", "value");
|
||||
SnowMist = Xml.GetChildFloatAttribute(node, "SnowMist", "value");
|
||||
Fog = Xml.GetChildFloatAttribute(node, "Fog", "value");
|
||||
RippleBumpiness = Xml.GetChildFloatAttribute(node, "RippleBumpiness", "value");
|
||||
RippleMinBumpiness = Xml.GetChildFloatAttribute(node, "RippleMinBumpiness", "value");
|
||||
RippleMaxBumpiness = Xml.GetChildFloatAttribute(node, "RippleMaxBumpiness", "value");
|
||||
RippleBumpinessWindScale = Xml.GetChildFloatAttribute(node, "RippleBumpinessWindScale", "value");
|
||||
RippleScale = Xml.GetChildFloatAttribute(node, "RippleScale", "value");
|
||||
RippleSpeed = Xml.GetChildFloatAttribute(node, "RippleSpeed", "value");
|
||||
RippleVelocityTransfer = Xml.GetChildFloatAttribute(node, "RippleVelocityTransfer", "value");
|
||||
OceanBumpiness = Xml.GetChildFloatAttribute(node, "OceanBumpiness", "value");
|
||||
DeepOceanScale = Xml.GetChildFloatAttribute(node, "DeepOceanScale", "value");
|
||||
OceanNoiseMinAmplitude = Xml.GetChildFloatAttribute(node, "OceanNoiseMinAmplitude", "value");
|
||||
OceanWaveAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveAmplitude", "value");
|
||||
ShoreWaveAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveAmplitude", "value");
|
||||
OceanWaveWindScale = Xml.GetChildFloatAttribute(node, "OceanWaveWindScale", "value");
|
||||
ShoreWaveWindScale = Xml.GetChildFloatAttribute(node, "ShoreWaveWindScale", "value");
|
||||
OceanWaveMinAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveMinAmplitude", "value");
|
||||
ShoreWaveMinAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveMinAmplitude", "value");
|
||||
OceanWaveMaxAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveMaxAmplitude", "value");
|
||||
ShoreWaveMaxAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveMaxAmplitude", "value");
|
||||
OceanFoamIntensity = Xml.GetChildFloatAttribute(node, "OceanFoamIntensity", "value");
|
||||
OceanFoamScale = Xml.GetChildFloatAttribute(node, "OceanFoamScale", "value");
|
||||
RippleDisturb = Xml.GetChildFloatAttribute(node, "RippleDisturb", "value");
|
||||
Lightning = Xml.GetChildFloatAttribute(node, "Lightning", "value");
|
||||
Sandstorm = Xml.GetChildFloatAttribute(node, "Sandstorm", "value");
|
||||
OldSettingName = Xml.GetChildInnerText(node, "OldSettingName");
|
||||
DropSettingName = Xml.GetChildInnerText(node, "DropSettingName");
|
||||
MistSettingName = Xml.GetChildInnerText(node, "MistSettingName");
|
||||
GroundSettingName = Xml.GetChildInnerText(node, "GroundSettingName");
|
||||
TimeCycleFilename = Xml.GetChildInnerText(node, "TimeCycleFilename");
|
||||
CloudSettingsName = Xml.GetChildInnerText(node, "CloudSettingsName");
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(TimeCycleFilename))
|
||||
{
|
||||
|
||||
//TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it!
|
||||
string fname = TimeCycleFilename.ToLowerInvariant();
|
||||
bool useupd = gameFileCache.EnableDlc;
|
||||
if (useupd)
|
||||
{
|
||||
fname = fname.Replace("common:", "update/update.rpf/common");
|
||||
}
|
||||
XmlDocument tcxml = gameFileCache.RpfMan.GetFileXml(fname);
|
||||
if (useupd && !tcxml.HasChildNodes)
|
||||
{
|
||||
fname = TimeCycleFilename.ToLowerInvariant();
|
||||
tcxml = gameFileCache.RpfMan.GetFileXml(fname);
|
||||
}
|
||||
|
||||
foreach (XmlNode cycle in tcxml.DocumentElement.ChildNodes)
|
||||
{
|
||||
TimeCycleData = new WeatherCycleKeyframeData();
|
||||
TimeCycleData.Init(cycle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public WeatherCycleKeyframeRegion GetRegion(string name)
|
||||
{
|
||||
if ((TimeCycleData != null) && (TimeCycleData.Regions != null))
|
||||
{
|
||||
WeatherCycleKeyframeRegion r;
|
||||
if (TimeCycleData.Regions.TryGetValue(name, out r))
|
||||
{
|
||||
return r;
|
||||
}
|
||||
return TimeCycleData.Regions.Values.FirstOrDefault();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public class WeatherCycle
|
||||
{
|
||||
public string CycleName { get; set; }
|
||||
public float TimeMult { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
CycleName = Xml.GetChildInnerText(node, "CycleName");
|
||||
TimeMult = Xml.GetChildFloatAttribute(node, "TimeMult", "value");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return CycleName + ", " + TimeMult.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class WeatherCycleKeyframeData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int RegionCount { get; set; }
|
||||
public Dictionary<string, WeatherCycleKeyframeRegion> Regions { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
//read cycle node
|
||||
Name = Xml.GetStringAttribute(node, "name");
|
||||
RegionCount = Xml.GetIntAttribute(node, "regions");
|
||||
Regions = new Dictionary<string, WeatherCycleKeyframeRegion>();
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
WeatherCycleKeyframeRegion r = new WeatherCycleKeyframeRegion();
|
||||
r.Init(child);
|
||||
Regions[r.Name] = r;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
public class WeatherCycleKeyframeRegion
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Dictionary<string, WeatherCycleKeyframeDataEntry> Data { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
//read region node
|
||||
Name = Xml.GetStringAttribute(node, "name");
|
||||
Data = new Dictionary<string, WeatherCycleKeyframeDataEntry>();
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
if (child != null)
|
||||
{
|
||||
WeatherCycleKeyframeDataEntry d = new WeatherCycleKeyframeDataEntry();
|
||||
d.Init(child);
|
||||
Data[d.Name] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetCurrentValue(string name, int sample, float curblend)
|
||||
{
|
||||
WeatherCycleKeyframeDataEntry e;
|
||||
if (Data.TryGetValue(name, out e))
|
||||
{
|
||||
if (sample >= e.Values.Length)
|
||||
{
|
||||
//System.Windows.Forms.MessageBox.Show("Sample index was out of range: " + sample.ToString());
|
||||
sample = e.Values.Length - 1;
|
||||
}
|
||||
int nxtsample = (sample < e.Values.Length - 1) ? sample + 1 : 0;
|
||||
float cv = e.Values[sample];
|
||||
float nv = e.Values[nxtsample];
|
||||
return cv * curblend + nv * (1.0f - curblend);
|
||||
}
|
||||
//throw new Exception("WeatherCycleKeyframeDataEntry " + name + " not found in region " + Name + ".");
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
public class WeatherCycleKeyframeDataEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public float[] Values { get; set; }
|
||||
|
||||
public void Init(XmlNode node)
|
||||
{
|
||||
//read data node
|
||||
Name = node.Name;
|
||||
string[] strvals = node.InnerText.Trim().Split(' ');
|
||||
Values = new float[strvals.Length];
|
||||
for (int i = 0; i < strvals.Length; i++)
|
||||
{
|
||||
if (!FloatUtil.TryParse(strvals[i], out Values[i]))
|
||||
{
|
||||
//System.Windows.Forms.MessageBox.Show("Error parsing float value: " + strvals[i] + "\n" +
|
||||
// "Node: " + node.OuterXml.ToString());
|
||||
//throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct WeatherValues
|
||||
{
|
||||
public Vector3 sunDirection;
|
||||
public Vector3 moonDirection;
|
||||
public Vector4 skyZenithCol;
|
||||
public Vector4 skyZenithTransitionCol;
|
||||
public Vector4 skyZenithTransition;
|
||||
public Vector4 skyAzimuthEastCol;
|
||||
public Vector4 skyAzimuthWestCol;
|
||||
public Vector4 skyAzimuthTransitionCol;
|
||||
public float skyAzimuthTransition;
|
||||
public float skyHdr;
|
||||
public Vector4 skyPlane;
|
||||
public Vector3 skySunCol;
|
||||
public Vector3 skySunDiscCol;
|
||||
public float skySunDiscSize;
|
||||
public float skySunHdr;
|
||||
public Vector3 skySunMie;
|
||||
public float skySunInfluenceRadius;
|
||||
public float skySunScatterInten;
|
||||
public Vector3 skyMoonCol;
|
||||
public float skyMoonDiscSize;
|
||||
public float skyMoonIten;
|
||||
public float skyMoonInfluenceRadius;
|
||||
public float skyMoonScatterInten;
|
||||
public float skyStarsIten;
|
||||
public Vector4 lightDirCol;
|
||||
public Vector4 lightDirAmbCol;
|
||||
public float lightDirAmbIntensityMult;
|
||||
public float lightDirAmbBounce;
|
||||
public Vector4 lightNaturalAmbDown;
|
||||
public Vector4 lightNaturalAmbUp;
|
||||
public float lightNaturalAmbUpIntensityMult;
|
||||
public Vector4 lightArtificialIntDown;
|
||||
public Vector4 lightArtificialIntUp;
|
||||
public Vector4 lightArtificialExtDown;
|
||||
public Vector4 lightArtificialExtUp;
|
||||
|
||||
public void Update(Weather w)
|
||||
{
|
||||
sunDirection = w.GetDynamicRGB("sun_direction_x", "sun_direction_y", "sun_direction_z");
|
||||
moonDirection = w.GetDynamicRGB("moon_direction_x", "moon_direction_y", "moon_direction_z");
|
||||
skyZenithCol = w.GetDynamicRGBA("sky_zenith_col_r", "sky_zenith_col_g", "sky_zenith_col_b", "sky_zenith_col_inten");
|
||||
skyZenithTransitionCol = w.GetDynamicRGBA("sky_zenith_transition_col_r", "sky_zenith_transition_col_g", "sky_zenith_transition_col_b", "sky_zenith_transition_col_inten");
|
||||
//skyZenithTransition = w.GetDynamicRGBA("sky_zenith_transition_position", "sky_zenith_transition_east_blend", "sky_zenith_transition_west_blend", "sky_zenith_blend_start");
|
||||
skyZenithTransition = w.GetDynamicRGBA("sky_zenith_blend_start", "sky_zenith_transition_east_blend", "sky_zenith_transition_west_blend", "sky_zenith_transition_position");
|
||||
skyAzimuthEastCol = w.GetDynamicRGBA("sky_azimuth_east_col_r", "sky_azimuth_east_col_g", "sky_azimuth_east_col_b", "sky_azimuth_east_col_inten");
|
||||
skyAzimuthWestCol = w.GetDynamicRGBA("sky_azimuth_west_col_r", "sky_azimuth_west_col_g", "sky_azimuth_west_col_b", "sky_azimuth_west_col_inten");
|
||||
skyAzimuthTransitionCol = w.GetDynamicRGBA("sky_azimuth_transition_col_r", "sky_azimuth_transition_col_g", "sky_azimuth_transition_col_b", "sky_azimuth_transition_col_inten");
|
||||
skyAzimuthTransition = w.GetDynamicValue("sky_azimuth_transition_position");
|
||||
skyHdr = w.GetDynamicValue("sky_hdr");
|
||||
skyPlane = w.GetDynamicRGBA("sky_plane_r", "sky_plane_g", "sky_plane_b", "sky_plane_inten");
|
||||
skySunCol = w.GetDynamicRGB("sky_sun_col_r", "sky_sun_col_g", "sky_sun_col_b");
|
||||
skySunDiscCol = w.GetDynamicRGB("sky_sun_disc_col_r", "sky_sun_disc_col_g", "sky_sun_disc_col_b");
|
||||
skySunDiscSize = w.GetDynamicValue("sky_sun_disc_size");
|
||||
skySunHdr = w.GetDynamicValue("sky_sun_hdr");
|
||||
skySunMie = w.GetDynamicRGB("sky_sun_miephase", "sky_sun_miescatter", "sky_sun_mie_intensity_mult");
|
||||
skySunInfluenceRadius = w.GetDynamicValue("sky_sun_influence_radius");
|
||||
skySunScatterInten = w.GetDynamicValue("sky_sun_scatter_inten");
|
||||
skyMoonCol = w.GetDynamicRGB("sky_moon_col_r", "sky_moon_col_g", "sky_moon_col_b");
|
||||
skyMoonDiscSize = w.GetDynamicValue("sky_moon_disc_size");
|
||||
skyMoonIten = w.GetDynamicValue("sky_moon_iten");
|
||||
skyMoonInfluenceRadius = w.GetDynamicValue("sky_moon_influence_radius");
|
||||
skyMoonScatterInten = w.GetDynamicValue("sky_moon_scatter_inten");
|
||||
skyStarsIten = w.GetDynamicValue("sky_stars_iten");
|
||||
lightDirCol = w.GetDynamicRGBA("light_dir_col_r", "light_dir_col_g", "light_dir_col_b", "light_dir_mult");
|
||||
lightDirAmbCol = w.GetDynamicRGBA("light_directional_amb_col_r", "light_directional_amb_col_g", "light_directional_amb_col_b", "light_directional_amb_intensity");
|
||||
lightDirAmbIntensityMult = w.GetDynamicValue("light_directional_amb_intensity_mult");
|
||||
lightDirAmbBounce = w.GetDynamicValue("light_directional_amb_bounce_enabled");
|
||||
lightNaturalAmbDown = w.GetDynamicRGBA("light_natural_amb_down_col_r", "light_natural_amb_down_col_g", "light_natural_amb_down_col_b", "light_natural_amb_down_intensity");
|
||||
lightNaturalAmbUp = w.GetDynamicRGBA("light_natural_amb_up_col_r", "light_natural_amb_up_col_g", "light_natural_amb_up_col_b", "light_natural_amb_up_intensity");
|
||||
lightNaturalAmbUpIntensityMult = w.GetDynamicValue("light_natural_amb_up_intensity_mult");
|
||||
lightArtificialIntDown = w.GetDynamicRGBA("light_artificial_int_down_col_r", "light_artificial_int_down_col_g", "light_artificial_int_down_col_b", "light_artificial_int_down_intensity");
|
||||
lightArtificialIntUp = w.GetDynamicRGBA("light_artificial_int_up_col_r", "light_artificial_int_up_col_g", "light_artificial_int_up_col_b", "light_artificial_int_up_intensity");
|
||||
lightArtificialExtDown = w.GetDynamicRGBA("light_artificial_ext_down_col_r", "light_artificial_ext_down_col_g", "light_artificial_ext_down_col_b", "light_artificial_ext_down_intensity");
|
||||
lightArtificialExtUp = w.GetDynamicRGBA("light_artificial_ext_up_col_r", "light_artificial_ext_up_col_g", "light_artificial_ext_up_col_b", "light_artificial_ext_up_intensity");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user