mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 00:43:00 +08:00
Cutscene viewer rendering peds
This commit is contained in:
parent
319214fd7c
commit
6467797c3d
@ -93,7 +93,7 @@ namespace CodeWalker.GameFiles
|
||||
public bool BuildExtendedJenkIndex = true;
|
||||
public bool LoadArchetypes = true;
|
||||
public bool LoadVehicles = false;
|
||||
public bool LoadPeds = false;
|
||||
public bool LoadPeds = true;
|
||||
private bool PreloadedMode = false;
|
||||
|
||||
private string GTAFolder;
|
||||
|
@ -6259,6 +6259,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
public string GetTextureSuffix(int texnum)
|
||||
{
|
||||
if (texnum < 0) texnum = 0;
|
||||
const string alphas = "abcdefghijklmnopqrstuvwxyz";
|
||||
var tex = TexData[texnum];
|
||||
var texid = tex.texId;
|
||||
|
@ -2902,6 +2902,8 @@ namespace CodeWalker.GameFiles
|
||||
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 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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
65
PedsForm.cs
65
PedsForm.cs
@ -807,70 +807,9 @@ namespace CodeWalker.Peds
|
||||
|
||||
var comboItem = comboObj as ComponentComboItem;
|
||||
var name = comboItem?.DrawableName;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
SelectedPed.DrawableNames[index] = null;
|
||||
SelectedPed.Drawables[index] = null;
|
||||
SelectedPed.Textures[index] = null;
|
||||
UpdateModelsUI();
|
||||
return;
|
||||
}
|
||||
var tex = comboItem?.TextureName;
|
||||
|
||||
MetaHash namehash = JenkHash.GenHash(name.ToLowerInvariant());
|
||||
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;
|
||||
SelectedPed.SetComponentDrawable(index, name, tex, GameFileCache);
|
||||
|
||||
UpdateModelsUI();
|
||||
}
|
||||
|
@ -427,6 +427,11 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public void UpdateAnims(double realTime)
|
||||
{
|
||||
if (ClipMapEntry?.OverridePlayTime ?? false)
|
||||
{
|
||||
realTime = ClipMapEntry.PlayTime;
|
||||
}
|
||||
|
||||
if (CurrentAnimTime == realTime) return;//already updated this!
|
||||
CurrentAnimTime = realTime;
|
||||
|
||||
|
@ -2496,7 +2496,7 @@ namespace CodeWalker.Rendering
|
||||
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.
|
||||
|
||||
@ -2521,10 +2521,10 @@ namespace CodeWalker.Rendering
|
||||
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.
|
||||
|
||||
@ -2564,6 +2564,15 @@ namespace CodeWalker.Rendering
|
||||
camrel += position;
|
||||
distance = entity.Distance;
|
||||
}
|
||||
else if (ped != null)
|
||||
{
|
||||
position = ped.Position;
|
||||
orientation = ped.Rotation;
|
||||
bbmin += position;
|
||||
bbmax += position;
|
||||
camrel += position;
|
||||
distance = (camrel + bscen).Length();
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = (camrel + bscen).Length();
|
||||
@ -2799,7 +2808,7 @@ namespace CodeWalker.Rendering
|
||||
|
||||
if (drawFlag)
|
||||
{
|
||||
RenderDrawable(drawable, null, null, 0, td, texture, ac);
|
||||
RenderDrawable(drawable, null, null, 0, td, texture, ac, ped);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using CodeWalker.Rendering;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -69,7 +70,13 @@ namespace CodeWalker.World
|
||||
|
||||
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);
|
||||
csnode.Tag = cs;
|
||||
|
||||
if (cf.pCutsceneObjects != null)
|
||||
if (cs.SceneObjects != null)
|
||||
{
|
||||
var objsnode = csnode.Nodes.Add("Objects");
|
||||
objsnode.Name = "Objects";
|
||||
|
||||
foreach (var obj in cf.pCutsceneObjects)
|
||||
foreach (var obj in cs.SceneObjects.Values)
|
||||
{
|
||||
var objnode = objsnode.Nodes.Add(obj.ToString());
|
||||
objnode.Tag = obj;
|
||||
@ -400,34 +407,83 @@ namespace CodeWalker.World
|
||||
|
||||
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.Clip is ClipAnimation canim)
|
||||
{
|
||||
if (canim.Animation != null)
|
||||
{
|
||||
var t = canim.GetPlaybackTime(PlaybackTime);
|
||||
var t = canim.GetPlaybackTime(cutOffset);
|
||||
var f = canim.Animation.GetFramePosition(t);
|
||||
var p = canim.Animation.FindBoneIndex(0, 7);//camera position
|
||||
var r = canim.Animation.FindBoneIndex(0, 8);//camera rotation
|
||||
if (p >= 0) CameraObject.Position = canim.Animation.EvaluateVector4(f, p, true).XYZ();
|
||||
if (r >= 0) CameraObject.Rotation = canim.Animation.EvaluateQuaternion(f, r, true);
|
||||
var p = canim.Animation.FindBoneIndex(boneTag, posTrack);
|
||||
var r = canim.Animation.FindBoneIndex(boneTag, rotTrack);
|
||||
if (p >= 0) obj.Position = canim.Animation.EvaluateVector4(f, p, true).XYZ();
|
||||
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)
|
||||
@ -747,8 +820,10 @@ namespace CodeWalker.World
|
||||
var dur = args.fSubtitleDuration;
|
||||
|
||||
txt = txt.Replace("~z~", "");
|
||||
txt = txt.Replace("~c~~n~", "\n - ");
|
||||
txt = txt.Replace("~n~", "\n");
|
||||
txt = txt.Replace("~c~", " - ");
|
||||
txt = txt.Replace("~t~", " - ");
|
||||
|
||||
WorldForm.ShowSubtitle(txt, dur);
|
||||
}
|
||||
@ -858,7 +933,7 @@ namespace CodeWalker.World
|
||||
foreach (var obj in Objects.Values)
|
||||
{
|
||||
var sobj = new CutsceneObject();
|
||||
sobj.Init(obj);
|
||||
sobj.Init(obj, GameFileCache);
|
||||
SceneObjects[sobj.ObjectID] = sobj;
|
||||
}
|
||||
}
|
||||
@ -873,8 +948,10 @@ namespace CodeWalker.World
|
||||
public Vector3 Position { 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;
|
||||
ObjectID = obj?.iObjectId ?? -1;
|
||||
@ -895,18 +972,23 @@ namespace CodeWalker.World
|
||||
}
|
||||
else if (obj is CutPedModelObject ped)
|
||||
{
|
||||
InitPed(ped, gfc);
|
||||
}
|
||||
else if (obj is CutPropModelObject prop)
|
||||
{
|
||||
InitProp(prop, gfc);
|
||||
}
|
||||
else if (obj is CutVehicleModelObject veh)
|
||||
{
|
||||
InitVehicle(veh, gfc);
|
||||
}
|
||||
else if (obj is CutWeaponModelObject weap)
|
||||
{
|
||||
InitWeapon(weap, gfc);
|
||||
}
|
||||
else if (obj is CutHiddenModelObject hid)
|
||||
{
|
||||
InitHiddenModel(hid, gfc);
|
||||
}
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user