Cutscene viewer rendering peds

This commit is contained in:
dexy 2019-11-26 01:26:28 +11:00
parent 319214fd7c
commit 6467797c3d
8 changed files with 264 additions and 96 deletions

View File

@ -93,7 +93,7 @@ namespace CodeWalker.GameFiles
public bool BuildExtendedJenkIndex = true; public bool BuildExtendedJenkIndex = true;
public bool LoadArchetypes = true; public bool LoadArchetypes = true;
public bool LoadVehicles = false; public bool LoadVehicles = false;
public bool LoadPeds = false; public bool LoadPeds = true;
private bool PreloadedMode = false; private bool PreloadedMode = false;
private string GTAFolder; private string GTAFolder;

View File

@ -6259,6 +6259,7 @@ namespace CodeWalker.GameFiles
} }
public string GetTextureSuffix(int texnum) public string GetTextureSuffix(int texnum)
{ {
if (texnum < 0) texnum = 0;
const string alphas = "abcdefghijklmnopqrstuvwxyz"; const string alphas = "abcdefghijklmnopqrstuvwxyz";
var tex = TexData[texnum]; var tex = TexData[texnum];
var texid = tex.texId; var texid = tex.texId;

View File

@ -2902,6 +2902,8 @@ namespace CodeWalker.GameFiles
public ClipMapEntry Next { get; set; } public ClipMapEntry Next { get; set; }
public bool EnableRootMotion { get; set; } = false; //used by CW to toggle whether or not to include root motion when playing animations public bool EnableRootMotion { get; set; } = false; //used by CW to toggle whether or not to include root motion when playing animations
public bool OverridePlayTime { get; set; } = false; //used by CW to manually override the animation playback time
public float PlayTime { get; set; } = 0.0f;
public override void Read(ResourceDataReader reader, params object[] parameters) public override void Read(ResourceDataReader reader, params object[] parameters)

View File

@ -117,5 +117,100 @@ namespace CodeWalker.World
public void SetComponentDrawable(int index, string name, string tex, GameFileCache gfc)
{
if (string.IsNullOrEmpty(name))
{
DrawableNames[index] = null;
Drawables[index] = null;
Textures[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(20);//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(20);//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
}
}
}
if (d != null) Drawables[index] = d;
if (t != null) Textures[index] = t;
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);
}
}
} }
} }

View File

@ -807,70 +807,9 @@ namespace CodeWalker.Peds
var comboItem = comboObj as ComponentComboItem; var comboItem = comboObj as ComponentComboItem;
var name = comboItem?.DrawableName; var name = comboItem?.DrawableName;
if (string.IsNullOrEmpty(name)) var tex = comboItem?.TextureName;
{
SelectedPed.DrawableNames[index] = null;
SelectedPed.Drawables[index] = null;
SelectedPed.Textures[index] = null;
UpdateModelsUI();
return;
}
MetaHash namehash = JenkHash.GenHash(name.ToLowerInvariant()); SelectedPed.SetComponentDrawable(index, name, tex, GameFileCache);
Drawable d = null;
if (SelectedPed.Ydd?.Dict != null)
{
SelectedPed.Ydd.Dict.TryGetValue(namehash, out d);
}
if ((d == null) && (SelectedPed.DrawableFilesDict != null))
{
RpfFileEntry file = null;
if (SelectedPed.DrawableFilesDict.TryGetValue(namehash, out file))
{
var ydd = GameFileCache.GetFileUncached<YddFile>(file);
while ((ydd != null) && (!ydd.Loaded))
{
Thread.Sleep(20);//kinda hacky
GameFileCache.TryLoadEnqueue(ydd);
}
if (ydd?.Drawables?.Length > 0)
{
d = ydd.Drawables[0];//should only be one in this dict
}
}
}
var tex = comboItem.TextureName;
MetaHash texhash = JenkHash.GenHash(tex.ToLowerInvariant());
Texture t = null;
if (SelectedPed.Ytd?.TextureDict?.Dict != null)
{
SelectedPed.Ytd.TextureDict.Dict.TryGetValue(texhash, out t);
}
if ((t == null) && (SelectedPed.TextureFilesDict != null))
{
RpfFileEntry file = null;
if (SelectedPed.TextureFilesDict.TryGetValue(texhash, out file))
{
var ytd = GameFileCache.GetFileUncached<YtdFile>(file);
while ((ytd != null) && (!ytd.Loaded))
{
Thread.Sleep(20);//kinda hacky
GameFileCache.TryLoadEnqueue(ytd);
}
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
{
t = ytd.TextureDict.Textures.data_items[0];//should only be one in this dict
}
}
}
if (d != null) SelectedPed.Drawables[index] = d;
if (t != null) SelectedPed.Textures[index] = t;
SelectedPed.DrawableNames[index] = name;
UpdateModelsUI(); UpdateModelsUI();
} }

View File

@ -427,6 +427,11 @@ namespace CodeWalker.Rendering
public void UpdateAnims(double realTime) public void UpdateAnims(double realTime)
{ {
if (ClipMapEntry?.OverridePlayTime ?? false)
{
realTime = ClipMapEntry.PlayTime;
}
if (CurrentAnimTime == realTime) return;//already updated this! if (CurrentAnimTime == realTime) return;//already updated this!
CurrentAnimTime = realTime; CurrentAnimTime = realTime;

View File

@ -2496,7 +2496,7 @@ namespace CodeWalker.Rendering
return res; return res;
} }
public bool RenderDrawable(DrawableBase drawable, Archetype arche, YmapEntityDef entity, uint txdHash = 0, TextureDictionary txdExtra = null, Texture diffOverride = null, ClipMapEntry animClip = null) public bool RenderDrawable(DrawableBase drawable, Archetype arche, YmapEntityDef entity, uint txdHash = 0, TextureDictionary txdExtra = null, Texture diffOverride = null, ClipMapEntry animClip = null, Ped ped = null)
{ {
//enqueue a single drawable for rendering. //enqueue a single drawable for rendering.
@ -2521,10 +2521,10 @@ namespace CodeWalker.Rendering
rndbl.ResetBoneTransforms(); rndbl.ResetBoneTransforms();
} }
return RenderRenderable(rndbl, arche, entity); return RenderRenderable(rndbl, arche, entity, ped);
} }
private bool RenderRenderable(Renderable rndbl, Archetype arche, YmapEntityDef entity) private bool RenderRenderable(Renderable rndbl, Archetype arche, YmapEntityDef entity, Ped ped = null)
{ {
//enqueue a single renderable for rendering. //enqueue a single renderable for rendering.
@ -2564,6 +2564,15 @@ namespace CodeWalker.Rendering
camrel += position; camrel += position;
distance = entity.Distance; distance = entity.Distance;
} }
else if (ped != null)
{
position = ped.Position;
orientation = ped.Rotation;
bbmin += position;
bbmax += position;
camrel += position;
distance = (camrel + bscen).Length();
}
else else
{ {
distance = (camrel + bscen).Length(); distance = (camrel + bscen).Length();
@ -2799,7 +2808,7 @@ namespace CodeWalker.Rendering
if (drawFlag) if (drawFlag)
{ {
RenderDrawable(drawable, null, null, 0, td, texture, ac); RenderDrawable(drawable, null, null, 0, td, texture, ac, ped);
} }

View File

@ -1,4 +1,5 @@
using CodeWalker.GameFiles; using CodeWalker.GameFiles;
using CodeWalker.Rendering;
using SharpDX; using SharpDX;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -69,7 +70,13 @@ namespace CodeWalker.World
public void GetVisibleYmaps(Camera camera, Dictionary<MetaHash, YmapFile> ymaps) public void GetVisibleYmaps(Camera camera, Dictionary<MetaHash, YmapFile> ymaps)
{ {
//use a temporary ymap for entities. //use a temporary ymap for entities?
var renderer = WorldForm?.Renderer;
if (renderer == null) return;
if (Cutscene == null) return;
Cutscene.Render(renderer);
} }
@ -140,12 +147,12 @@ namespace CodeWalker.World
var csnode = CutsceneTreeView.Nodes.Add(cutFile.FileEntry?.Name); var csnode = CutsceneTreeView.Nodes.Add(cutFile.FileEntry?.Name);
csnode.Tag = cs; csnode.Tag = cs;
if (cf.pCutsceneObjects != null) if (cs.SceneObjects != null)
{ {
var objsnode = csnode.Nodes.Add("Objects"); var objsnode = csnode.Nodes.Add("Objects");
objsnode.Name = "Objects"; objsnode.Name = "Objects";
foreach (var obj in cf.pCutsceneObjects) foreach (var obj in cs.SceneObjects.Values)
{ {
var objnode = objsnode.Nodes.Add(obj.ToString()); var objnode = objsnode.Nodes.Add(obj.ToString());
objnode.Tag = obj; objnode.Tag = obj;
@ -400,34 +407,83 @@ namespace CodeWalker.World
float cutOffset = newTime - cutStart;//offset into the current cut float cutOffset = newTime - cutStart;//offset into the current cut
var ycd = (cutIndex < (Ycds?.Length ?? 0)) ? Ycds[cutIndex] : null;
if (ycd?.CutsceneMap != null)
{
if (CameraObject != null)
{
ClipMapEntry cme = null;
ycd.CutsceneMap.TryGetValue(CameraObject.Name, out cme);
void updateObjectTransform(CutsceneObject obj, ClipMapEntry cme, ushort boneTag, byte posTrack, byte rotTrack)
{
if (cme != null) if (cme != null)
{ {
if (cme.Clip is ClipAnimation canim) if (cme.Clip is ClipAnimation canim)
{ {
if (canim.Animation != null) if (canim.Animation != null)
{ {
var t = canim.GetPlaybackTime(PlaybackTime); var t = canim.GetPlaybackTime(cutOffset);
var f = canim.Animation.GetFramePosition(t); var f = canim.Animation.GetFramePosition(t);
var p = canim.Animation.FindBoneIndex(0, 7);//camera position var p = canim.Animation.FindBoneIndex(boneTag, posTrack);
var r = canim.Animation.FindBoneIndex(0, 8);//camera rotation var r = canim.Animation.FindBoneIndex(boneTag, rotTrack);
if (p >= 0) CameraObject.Position = canim.Animation.EvaluateVector4(f, p, true).XYZ(); if (p >= 0) obj.Position = canim.Animation.EvaluateVector4(f, p, true).XYZ();
if (r >= 0) CameraObject.Rotation = canim.Animation.EvaluateQuaternion(f, r, true); if (r >= 0) obj.Rotation = canim.Animation.EvaluateQuaternion(f, r, true);
}
}
else if (cme.Clip is ClipAnimationList alist)
{
if (alist.Animations?.Data != null)
{
foreach (var anim in alist.Animations.Data)
{
var t = anim.GetPlaybackTime(cutOffset);
var f = anim.Animation.GetFramePosition(t);
var p = anim.Animation.FindBoneIndex(boneTag, posTrack);
var r = anim.Animation.FindBoneIndex(boneTag, rotTrack);
if (p >= 0) obj.Position = anim.Animation.EvaluateVector4(f, p, true).XYZ();
if (r >= 0) obj.Rotation = anim.Animation.EvaluateQuaternion(f, r, true);
}
}
}
}
} }
var ycd = (cutIndex < (Ycds?.Length ?? 0)) ? Ycds[cutIndex] : null;
if (ycd?.CutsceneMap != null)
{
ClipMapEntry cme = null;
if (CameraObject != null)
{
ycd.CutsceneMap.TryGetValue(CameraObject.Name, out cme);
updateObjectTransform(CameraObject, cme, 0, 7, 8);
} }
if (SceneObjects != null)
{
foreach (var obj in SceneObjects.Values)
{
if (obj.Ped != null)
{
ycd.CutsceneMap.TryGetValue(obj.Ped.NameHash, out cme);
var pos = Position;
var rot = Rotation;
if (cme != null)
{
cme.OverridePlayTime = true;
cme.PlayTime = cutOffset;
updateObjectTransform(obj, cme, 0, 5, 6);
pos = pos + obj.Position;
rot = rot * obj.Rotation;
}
obj.Ped.Position = pos;
obj.Ped.Rotation = rot;
obj.Ped.AnimClip = cme;
}
}
} }
//var animname = CameraObject.Name.ToString() + "-" + cutIndex.ToString();
//MetaHash animhash = JenkHash.GenHash()
} }
@ -436,7 +492,24 @@ namespace CodeWalker.World
} }
public void Render(Renderer renderer)
{
if (SceneObjects != null)
{
foreach (var obj in SceneObjects.Values)
{
if (obj.Ped != null)
{
renderer.RenderPed(obj.Ped);
} }
}
}
}
private void RaiseEvents(float upToTime) private void RaiseEvents(float upToTime)
@ -747,8 +820,10 @@ namespace CodeWalker.World
var dur = args.fSubtitleDuration; var dur = args.fSubtitleDuration;
txt = txt.Replace("~z~", ""); txt = txt.Replace("~z~", "");
txt = txt.Replace("~c~~n~", "\n - ");
txt = txt.Replace("~n~", "\n"); txt = txt.Replace("~n~", "\n");
txt = txt.Replace("~c~", " - "); txt = txt.Replace("~c~", " - ");
txt = txt.Replace("~t~", " - ");
WorldForm.ShowSubtitle(txt, dur); WorldForm.ShowSubtitle(txt, dur);
} }
@ -858,7 +933,7 @@ namespace CodeWalker.World
foreach (var obj in Objects.Values) foreach (var obj in Objects.Values)
{ {
var sobj = new CutsceneObject(); var sobj = new CutsceneObject();
sobj.Init(obj); sobj.Init(obj, GameFileCache);
SceneObjects[sobj.ObjectID] = sobj; SceneObjects[sobj.ObjectID] = sobj;
} }
} }
@ -873,8 +948,10 @@ namespace CodeWalker.World
public Vector3 Position { get; set; } public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; } public Quaternion Rotation { get; set; }
public Ped Ped { get; set; }
public void Init(CutObject obj)
public void Init(CutObject obj, GameFileCache gfc)
{ {
CutObject = obj; CutObject = obj;
ObjectID = obj?.iObjectId ?? -1; ObjectID = obj?.iObjectId ?? -1;
@ -895,18 +972,23 @@ namespace CodeWalker.World
} }
else if (obj is CutPedModelObject ped) else if (obj is CutPedModelObject ped)
{ {
InitPed(ped, gfc);
} }
else if (obj is CutPropModelObject prop) else if (obj is CutPropModelObject prop)
{ {
InitProp(prop, gfc);
} }
else if (obj is CutVehicleModelObject veh) else if (obj is CutVehicleModelObject veh)
{ {
InitVehicle(veh, gfc);
} }
else if (obj is CutWeaponModelObject weap) else if (obj is CutWeaponModelObject weap)
{ {
InitWeapon(weap, gfc);
} }
else if (obj is CutHiddenModelObject hid) else if (obj is CutHiddenModelObject hid)
{ {
InitHiddenModel(hid, gfc);
} }
else if (obj is CutFixupModelObject fix) else if (obj is CutFixupModelObject fix)
{ {
@ -948,6 +1030,41 @@ namespace CodeWalker.World
{ } { }
} }
private void InitPed(CutPedModelObject ped, GameFileCache gfc)
{
Ped = new Ped();
Ped.Init(ped.StreamingName, gfc);
Ped.LoadDefaultComponents(gfc);
if (ped.StreamingName == JenkHash.GenHash("player_zero"))
{
//for michael, switch his outfit so it's not glitching everywhere (until it's fixed?)
Ped.SetComponentDrawable(3, 27, 0, 0, gfc);
Ped.SetComponentDrawable(4, 19, 0, 0, gfc);
Ped.SetComponentDrawable(6, null, null, gfc);
}
}
private void InitProp(CutPropModelObject prop, GameFileCache gfc)
{
}
private void InitVehicle(CutVehicleModelObject veh, GameFileCache gfc)
{
}
private void InitWeapon(CutWeaponModelObject weap, GameFileCache gfc)
{
}
private void InitHiddenModel(CutHiddenModelObject hid, GameFileCache gfc)
{
}
public override string ToString() public override string ToString()