diff --git a/CodeWalker.Core/CodeWalker.Core.csproj b/CodeWalker.Core/CodeWalker.Core.csproj
index e1ee816..c0142de 100644
--- a/CodeWalker.Core/CodeWalker.Core.csproj
+++ b/CodeWalker.Core/CodeWalker.Core.csproj
@@ -60,6 +60,7 @@
+
diff --git a/CodeWalker.Core/GameFiles/FileTypes/GtxdFile.cs b/CodeWalker.Core/GameFiles/FileTypes/GtxdFile.cs
index 53dcaf3..4c47102 100644
--- a/CodeWalker.Core/GameFiles/FileTypes/GtxdFile.cs
+++ b/CodeWalker.Core/GameFiles/FileTypes/GtxdFile.cs
@@ -15,7 +15,7 @@ namespace CodeWalker.GameFiles
public RbfFile Rbf { get; set; }
- public Dictionary CMapParentTxds { get; set; }
+ public Dictionary TxdRelationships { get; set; }
@@ -46,7 +46,7 @@ namespace CodeWalker.GameFiles
if (rbfstruct.Name == "CMapParentTxds")
{
- LoadMapParentTxds(rbfstruct);
+ LoadTxdRelationships(rbfstruct);
}
Loaded = true;
@@ -68,7 +68,7 @@ namespace CodeWalker.GameFiles
xml = xml.Remove(0, bom.Length);
}
- LoadMapParentTxds(xml);
+ LoadTxdRelationships(xml);
Loaded = true;
}
@@ -76,10 +76,10 @@ namespace CodeWalker.GameFiles
}
- private void LoadMapParentTxds(RbfStructure rbfstruct)
+ private void LoadTxdRelationships(RbfStructure rbfstruct)
{
- CMapParentTxds = new Dictionary();
+ TxdRelationships = new Dictionary();
//StringBuilder sblist = new StringBuilder();
foreach (var child in rbfstruct.Children)
{
@@ -118,9 +118,9 @@ namespace CodeWalker.GameFiles
}
if ((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
{
- if (!CMapParentTxds.ContainsKey(childstr))
+ if (!TxdRelationships.ContainsKey(childstr))
{
- CMapParentTxds.Add(childstr, parentstr);
+ TxdRelationships.Add(childstr, parentstr);
}
else
{
@@ -140,13 +140,13 @@ namespace CodeWalker.GameFiles
- private void LoadMapParentTxds(string xml)
+ private void LoadTxdRelationships(string xml)
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xml); //maybe better load xml.ToLower() and use "cmapparenttxds/txdrelationships/item" as xpath?
XmlNodeList items = xmldoc.SelectNodes("CMapParentTxds/txdRelationships/Item | CMapParentTxds/txdRelationships/item");
- CMapParentTxds = new Dictionary();
+ TxdRelationships = new Dictionary();
for (int i = 0; i < items.Count; i++)
{
string parentstr = Xml.GetChildInnerText(items[i], "parent");
@@ -154,9 +154,9 @@ namespace CodeWalker.GameFiles
if ((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
{
- if (!CMapParentTxds.ContainsKey(childstr))
+ if (!TxdRelationships.ContainsKey(childstr))
{
- CMapParentTxds.Add(childstr, parentstr);
+ TxdRelationships.Add(childstr, parentstr);
}
}
}
diff --git a/CodeWalker.Core/GameFiles/FileTypes/VehiclesFile.cs b/CodeWalker.Core/GameFiles/FileTypes/VehiclesFile.cs
new file mode 100644
index 0000000..8b3ad01
--- /dev/null
+++ b/CodeWalker.Core/GameFiles/FileTypes/VehiclesFile.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace CodeWalker.GameFiles
+{
+ public class VehiclesFile : GameFile, PackedFile
+ {
+
+ public RbfFile Rbf { get; set; }
+
+
+ public Dictionary TxdRelationships { get; set; }
+
+
+
+
+ public VehiclesFile() : base(null, GameFileType.Vehicles)
+ {
+ }
+ public VehiclesFile(RpfFileEntry entry) : base(entry, GameFileType.Vehicles)
+ {
+ }
+
+
+
+ public void Load(byte[] data, RpfFileEntry entry)
+ {
+ RpfFileEntry = entry;
+ Name = entry.Name;
+ FilePath = Name;
+
+
+ if (entry.NameLower.EndsWith(".meta"))
+ {
+ //required for update\x64\dlcpacks\mpheist\dlc.rpf\common\data\gtxd.meta and update\x64\dlcpacks\mpluxe\dlc.rpf\common\data\gtxd.meta
+ string bom = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
+ string xml = Encoding.UTF8.GetString(data);
+
+ if (xml.StartsWith(bom, StringComparison.Ordinal))
+ {
+ xml = xml.Remove(0, bom.Length);
+ }
+
+ XmlDocument xmldoc = new XmlDocument();
+ xmldoc.LoadXml(xml);
+
+ LoadVehicles(xmldoc);
+
+ LoadTxdRelationships(xmldoc);
+
+ Loaded = true;
+ }
+ }
+
+
+ private void LoadVehicles(XmlDocument xmldoc)
+ {
+ XmlNodeList items = xmldoc.SelectNodes("CVehicleModelInfo__InitDataList/InitDatas/Item | CVehicleModelInfo__InitDataList/InitDatas/item");
+ for (int i = 0; i < items.Count; i++)
+ {
+ //TODO...
+ }
+ }
+
+ private void LoadTxdRelationships(XmlDocument xmldoc)
+ {
+ XmlNodeList items = xmldoc.SelectNodes("CVehicleModelInfo__InitDataList/txdRelationships/Item | CVehicleModelInfo__InitDataList/txdRelationships/item");
+
+ TxdRelationships = new Dictionary();
+ for (int i = 0; i < items.Count; i++)
+ {
+ string parentstr = Xml.GetChildInnerText(items[i], "parent");
+ string childstr = Xml.GetChildInnerText(items[i], "child");
+
+ if ((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
+ {
+ if (!TxdRelationships.ContainsKey(childstr))
+ {
+ TxdRelationships.Add(childstr, parentstr);
+ }
+ }
+ }
+ }
+
+
+ }
+}
diff --git a/CodeWalker.Core/GameFiles/GameFile.cs b/CodeWalker.Core/GameFiles/GameFile.cs
index 0a82198..44806f1 100644
--- a/CodeWalker.Core/GameFiles/GameFile.cs
+++ b/CodeWalker.Core/GameFiles/GameFile.cs
@@ -70,6 +70,7 @@ namespace CodeWalker.GameFiles
Ywr = 14,
Yvr = 15,
Gtxd = 16,
+ Vehicles = 17,
}
diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs
index 2e38f4e..95a87c8 100644
--- a/CodeWalker.Core/GameFiles/GameFileCache.cs
+++ b/CodeWalker.Core/GameFiles/GameFileCache.cs
@@ -27,7 +27,8 @@ namespace CodeWalker.GameFiles
private volatile bool archetypesLoaded = false;
private Dictionary archetypeDict = new Dictionary();
private Dictionary textureLookup = new Dictionary();
- private Dictionary textureParents;
+ private Dictionary textureParents;
+ private Dictionary hdtexturelookup;
private object updateSyncRoot = new object();
private object requestSyncRoot = new object();
@@ -132,6 +133,7 @@ namespace CodeWalker.GameFiles
mainCache.Clear();
textureLookup.Clear();
+
GameFile queueclear;
while (requestQueue.TryPop(out queueclear))
{ } //empty the old queue out...
@@ -958,6 +960,7 @@ namespace CodeWalker.GameFiles
private void InitManifestDicts()
{
AllManifests = new List();
+ hdtexturelookup = new Dictionary();
foreach (RpfFile file in ActiveMapRpfFiles.Values) //RpfMan.BaseRpfs)
{
if (file.AllEntries == null) continue;
@@ -985,6 +988,19 @@ namespace CodeWalker.GameFiles
{ }
else
{ }
+
+
+ if (ymffile.HDTxdAssetBindings != null)
+ {
+ for (int i = 0; i < ymffile.HDTxdAssetBindings.Length; i++)
+ {
+ var b = ymffile.HDTxdAssetBindings[i];
+ var targetasset = JenkHash.GenHash(b.targetAsset.ToString().ToLowerInvariant());
+ var hdtxd = JenkHash.GenHash(b.HDTxd.ToString().ToLowerInvariant());
+ hdtexturelookup[targetasset] = hdtxd;
+ }
+ }
+
}
}
@@ -996,70 +1012,49 @@ namespace CodeWalker.GameFiles
private void InitGtxds()
{
- Dictionary parentTxds = new Dictionary();
+ var parentTxds = new Dictionary();
IEnumerable rpfs = PreloadedMode ? AllRpfs : (IEnumerable)ActiveMapRpfFiles.Values;
- foreach (RpfFile file in rpfs)
+ var addTxdRelationships = new Action>((from) =>
{
- if (file.AllEntries == null) continue;
- foreach (RpfEntry entry in file.AllEntries)
+ foreach (var kvp in from)
{
- try
+ uint chash = JenkHash.GenHash(kvp.Key.ToLowerInvariant());
+ uint phash = JenkHash.GenHash(kvp.Value.ToLowerInvariant());
+ if (!parentTxds.ContainsKey(chash))
{
- if ((entry.NameLower == "gtxd.ymt") || (entry.NameLower == "gtxd.meta"))
- {
- GtxdFile ymt = RpfMan.GetFile(entry);
- if (ymt.CMapParentTxds != null)
- {
- foreach (var kvp in ymt.CMapParentTxds)
- {
- uint chash = JenkHash.GenHash(kvp.Key.ToLowerInvariant());
- uint phash = JenkHash.GenHash(kvp.Value.ToLowerInvariant());
- if (!parentTxds.ContainsKey(chash))
- {
- parentTxds.Add(chash, phash);
- }
- else
- {
- }
- }
- }
- }
+ parentTxds.Add(chash, phash);
}
- catch (Exception ex)
+ else
{
- string errstr = entry.Path + "\n" + ex.ToString();
- ErrorLog(errstr);
}
}
- }
+ });
- if (EnableDlc)
+ var addRpfTxdRelationships = new Action>((from) =>
{
- foreach (var dlcfile in DlcActiveRpfs)
+ foreach (RpfFile file in from)
{
- foreach (RpfEntry entry in dlcfile.AllEntries)
+ if (file.AllEntries == null) continue;
+ foreach (RpfEntry entry in file.AllEntries)
{
try
{
- if (entry.NameLower == "gtxd.meta")
+ if ((entry.NameLower == "gtxd.ymt") || (entry.NameLower == "gtxd.meta"))
{
GtxdFile ymt = RpfMan.GetFile(entry);
- if (ymt.CMapParentTxds != null)
+ if (ymt.TxdRelationships != null)
{
- foreach (var kvp in ymt.CMapParentTxds)
- {
- uint chash = JenkHash.GenHash(kvp.Key.ToLowerInvariant());
- uint phash = JenkHash.GenHash(kvp.Value.ToLowerInvariant());
- if (!parentTxds.ContainsKey(chash))
- {
- parentTxds.Add(chash, phash);
- }
- else
- {
- }
- }
+ addTxdRelationships(ymt.TxdRelationships);
+ }
+ }
+ else if (entry.NameLower == "vehicles.meta")
+ {
+ VehiclesFile vf = RpfMan.GetFile(entry);
+ if (vf.TxdRelationships != null)
+ {
+ addTxdRelationships(vf.TxdRelationships);
}
}
}
@@ -1070,6 +1065,16 @@ namespace CodeWalker.GameFiles
}
}
}
+
+ });
+
+
+ addRpfTxdRelationships(rpfs);
+
+
+ if (EnableDlc)
+ {
+ addRpfTxdRelationships(DlcActiveRpfs);
}
@@ -1078,7 +1083,7 @@ namespace CodeWalker.GameFiles
- //ensure global texture dicts:
+ //ensure resident global texture dicts:
YtdFile ytd1 = new YtdFile(GetYtdEntry(JenkHash.GenHash("mapdetail")));
LoadFile(ytd1);
AddTextureLookups(ytd1);
@@ -1087,17 +1092,6 @@ namespace CodeWalker.GameFiles
LoadFile(ytd2);
AddTextureLookups(ytd2);
- YtdFile ytd3 = new YtdFile(GetYtdEntry(JenkHash.GenHash("vehshare_worn")));
- LoadFile(ytd3);
- AddTextureLookups(ytd3);
-
- YtdFile ytd4 = new YtdFile(GetYtdEntry(JenkHash.GenHash("vehshare_army")));
- LoadFile(ytd4);
- AddTextureLookups(ytd4);
-
- YtdFile ytd5 = new YtdFile(GetYtdEntry(JenkHash.GenHash("vehshare_truck")));
- LoadFile(ytd5);
- AddTextureLookups(ytd5);
}
@@ -1435,7 +1429,7 @@ namespace CodeWalker.GameFiles
{
lock (updateSyncRoot)
{
- lock (textureSyncRoot)
+ //lock (textureSyncRoot)
{
SelectedDlc = dlc;
EnableDlc = enable;
@@ -1459,7 +1453,7 @@ namespace CodeWalker.GameFiles
{
lock (updateSyncRoot)
{
- lock (textureSyncRoot)
+ //lock (textureSyncRoot)
{
EnableMods = enable;
RpfMan.EnableMods = enable;
@@ -1901,7 +1895,7 @@ namespace CodeWalker.GameFiles
break;
case GameFileType.Ytd:
req.Loaded = LoadFile(req as YtdFile);
- if (req.Loaded) AddTextureLookups(req as YtdFile);
+ //if (req.Loaded) AddTextureLookups(req as YtdFile);
break;
case GameFileType.Ymap:
YmapFile y = req as YmapFile;
@@ -1983,7 +1977,7 @@ namespace CodeWalker.GameFiles
}
public YtdFile TryGetParentYtd(uint hash)
{
- uint phash;
+ MetaHash phash;
if(textureParents.TryGetValue(hash, out phash))
{
return GetYtd(phash);
@@ -1992,19 +1986,31 @@ namespace CodeWalker.GameFiles
}
public uint TryGetParentYtdHash(uint hash)
{
- uint phash = 0;
+ MetaHash phash = 0;
textureParents.TryGetValue(hash, out phash);
return phash;
}
+ public uint TryGetHDTextureHash(uint txdhash)
+ {
+ MetaHash hdhash = 0;
+ if (hdtexturelookup?.TryGetValue(txdhash, out hdhash) ?? false)
+ {
+ return hdhash;
+ }
+ return txdhash;
+ }
public Texture TryFindTextureInParent(uint texhash, uint txdhash)
{
Texture tex = null;
var ytd = TryGetParentYtd(txdhash);
- while ((ytd != null) && (ytd.Loaded) && (ytd.TextureDict != null) && (tex == null))
+ while ((ytd != null) && (tex == null))
{
- tex = ytd.TextureDict.Lookup(texhash);
+ if (ytd.Loaded && (ytd.TextureDict != null))
+ {
+ tex = ytd.TextureDict.Lookup(texhash);
+ }
if (tex == null)
{
ytd = TryGetParentYtd(ytd.Key.Hash);
diff --git a/CodeWalker.Core/GameFiles/Resources/Texture.cs b/CodeWalker.Core/GameFiles/Resources/Texture.cs
index fba5a30..60b12aa 100644
--- a/CodeWalker.Core/GameFiles/Resources/Texture.cs
+++ b/CodeWalker.Core/GameFiles/Resources/Texture.cs
@@ -29,6 +29,7 @@ namespace CodeWalker.GameFiles
public ResourcePointerList64 Textures { get; set; }
public Dictionary Dict { get; set; }
+
public long MemoryUsage
{
get
@@ -81,7 +82,7 @@ namespace CodeWalker.GameFiles
dict[hash] = tex;
}
}
- Dict = new Dictionary(dict);
+ Dict = dict;// new Dictionary(dict);
}
///
@@ -108,21 +109,6 @@ namespace CodeWalker.GameFiles
};
}
- public Dictionary GetDictionary()
- {
- Dictionary td = new Dictionary();
- if ((Textures != null) && (Textures.data_items != null))
- {
- var texs = Textures.data_items;
- var hashes = TextureNameHashes;
- for (int i = 0; (i < texs.Length) && (i < hashes.Length); i++)
- {
- td.Add(hashes[i], texs[i]);
- }
- }
- return td;
- }
-
public Texture Lookup(uint hash)
{
Texture tex = null;
@@ -132,6 +118,21 @@ namespace CodeWalker.GameFiles
}
return tex;
}
+
+ //public Dictionary GetDictionary()
+ //{
+ // Dictionary td = new Dictionary();
+ // if ((Textures != null) && (Textures.data_items != null))
+ // {
+ // var texs = Textures.data_items;
+ // var hashes = TextureNameHashes;
+ // for (int i = 0; (i < texs.Length) && (i < hashes.Length); i++)
+ // {
+ // td.Add(hashes[i], texs[i]);
+ // }
+ // }
+ // return td;
+ //}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureBase : ResourceSystemBlock
diff --git a/Forms/ModelForm.cs b/Forms/ModelForm.cs
index d95e9d4..8ee1146 100644
--- a/Forms/ModelForm.cs
+++ b/Forms/ModelForm.cs
@@ -519,7 +519,14 @@ namespace CodeWalker.Forms
{
var f = Yft.Fragment;
- hash = Yft?.RpfFileEntry?.ShortNameHash ?? 0;
+ hash = Yft.RpfFileEntry?.ShortNameHash ?? 0;
+
+ var namelower = Yft.RpfFileEntry?.GetShortNameLower();
+ if (namelower?.EndsWith("_hi") ?? false)
+ {
+ hash = JenkHash.GenHash(namelower.Substring(0, namelower.Length - 3));
+ }
+
arch = TryGetArchetype(hash);
Renderer.RenderFragment(arch, null, f, hash);
diff --git a/Rendering/Renderable.cs b/Rendering/Renderable.cs
index 4112796..d23e69e 100644
--- a/Rendering/Renderable.cs
+++ b/Rendering/Renderable.cs
@@ -59,6 +59,9 @@ namespace CodeWalker.Rendering
public bool AllTexturesLoaded = false;
public RenderableModel[] HDModels;
+ public RenderableModel[] MedModels;
+ public RenderableModel[] LowModels;
+ public RenderableModel[] VlowModels;
public RenderableModel[] AllModels;
//public Dictionary TextureDict { get; private set; }
//public long EmbeddedTextureSize { get; private set; }
@@ -88,25 +91,31 @@ namespace CodeWalker.Rendering
}
if (med != null)
{
+ MedModels = new RenderableModel[med.Length];
for (int i = 0; i < med.Length; i++)
{
- AllModels[curmodel + i] = InitModel(med[i]);
+ MedModels[i] = InitModel(med[i]);
+ AllModels[curmodel + i] = MedModels[i];
}
curmodel += med.Length;
}
if (low != null)
{
+ LowModels = new RenderableModel[low.Length];
for (int i = 0; i < low.Length; i++)
{
- AllModels[curmodel + i] = InitModel(low[i]);
+ LowModels[i] = InitModel(low[i]);
+ AllModels[curmodel + i] = LowModels[i];
}
curmodel += low.Length;
}
if (vlow != null)
{
+ VlowModels = new RenderableModel[vlow.Length];
for (int i = 0; i < vlow.Length; i++)
{
- AllModels[curmodel + i] = InitModel(vlow[i]);
+ VlowModels[i] = InitModel(vlow[i]);
+ AllModels[curmodel + i] = VlowModels[i];
}
curmodel += vlow.Length;
}
@@ -364,7 +373,9 @@ namespace CodeWalker.Rendering
public uint IndexDataSize { get; set; }
public uint TotalDataSize { get; set; }
public TextureBase[] Textures;
+ public Texture[] TexturesHD;
public RenderableTexture[] RenderableTextures;
+ public RenderableTexture[] RenderableTexturesHD;
public MetaName[] TextureParamHashes;
public PrimitiveTopology Topology { get; set; }
public bool IsFragment = false;
@@ -392,6 +403,7 @@ namespace CodeWalker.Rendering
public float WaterHeight { get; set; } = 0; //for terrainfoam
public float WaveMovement { get; set; } = 0; //for terrainfoam
public float HeightOpacity { get; set; } = 0; //for terrainfoam
+ public bool HDTextureEnable = true;
public static MetaName[] GetTextureSamplerList()
@@ -595,60 +607,9 @@ namespace CodeWalker.Rendering
{
TextureParamHashes = phashes.ToArray();
Textures = texs.ToArray();
+ TexturesHD = new Texture[texs.Count];
RenderableTextures = new RenderableTexture[texs.Count]; //these will get populated at render time.
- //Textures = new RenderableTexture[texs.Count];
- for (int i = 0; i < texs.Count; i++)
- {
- //RenderableTexture tex = new RenderableTexture();
- //tex.Init(texs[i]);
- //Textures[i] = tex;
-
-
- ////testing texture usage
- //MetaName thash = phashes[i];
- //switch (thash)
- //{
- // case MetaName.DiffuseSampler: //base diffuse
- // case MetaName.SpecSampler: //base specular
- // case MetaName.BumpSampler: //base normal
- // case MetaName.TintPaletteSampler: // _pal
- // case MetaName.DetailSampler: // ENV_
- // case MetaName.FlowSampler: //river _flow
- // case MetaName.FogSampler: //river _fog , water slod
- // case MetaName.TextureSampler_layer0: //CS_RSN_SL_Road_0007
- // case MetaName.BumpSampler_layer0: //CS_RSN_SL_Road_0007_n
- // case MetaName.heightMapSamplerLayer0: //nxg_cs_rsn_sl_road_0007_h
- // case MetaName.TextureSampler_layer1: //IM_Road_009b
- // case MetaName.BumpSampler_layer1: //IM_Road_010b_N
- // case MetaName.heightMapSamplerLayer1: //nxg_im_road_010b_h
- // case MetaName.TextureSampler_layer2: //IM_Concrete10
- // case MetaName.BumpSampler_layer2: //IM_Concrete13_N
- // case MetaName.heightMapSamplerLayer2: //nxg_im_concrete13_h
- // case MetaName.TextureSampler_layer3: //SC1_RSN_NS_ground_0009
- // case MetaName.BumpSampler_layer3: //sc1_rsn_ns_ground_0010_n
- // case MetaName.heightMapSamplerLayer3: //nxg_sc1_rsn_ns_ground_0010_b_h
- // case MetaName.lookupSampler: //TF_RSN_Msk_CS1_DesHill1, bh1_43_golf_blendmap_04_LOD
- // case MetaName.heightSampler: //nxg_prop_tree_palm2_displ_l
- // case MetaName.FoamSampler: //bj_beachfoam01_lod, CS_RSN_SL_RiverFoam_01_A_lodCS_RSN_SL_RiverFoam_01_A
- // case MetaName.textureSamp://cable...
- // break;
- // //not yet implemented:
- // case MetaName.DiffuseSampler2:
- // case MetaName.DiffuseHfSampler:
- // case MetaName.ComboHeightSamplerFur01:
- // case MetaName.ComboHeightSamplerFur23:
- // case MetaName.ComboHeightSamplerFur45:
- // case MetaName.ComboHeightSamplerFur67:
- // case MetaName.StippleSampler:
- // case MetaName.FurMaskSampler:
- // case MetaName.EnvironmentSampler:
- // case MetaName.distanceMapSampler:
- // break;
- // default:
- // break;
- //}
-
- }
+ RenderableTexturesHD = new RenderableTexture[texs.Count]; //these will get populated at render time.
}
}
@@ -771,6 +732,14 @@ namespace CodeWalker.Rendering
}
RenderableTextures = null;
}
+ if (RenderableTexturesHD != null)
+ {
+ for (int i = 0; i < RenderableTexturesHD.Length; i++)
+ {
+ RenderableTexturesHD[i] = null;
+ }
+ RenderableTexturesHD = null;
+ }
}
diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs
index 1bca21f..27717a6 100644
--- a/Rendering/Renderer.cs
+++ b/Rendering/Renderer.cs
@@ -111,6 +111,9 @@ namespace CodeWalker.Rendering
private List renderskeletonlist = new List();
private List skeletonLineVerts = new List();
+ public bool renderhdtextures = true;
+
+
public MapSelectionMode SelectionMode = MapSelectionMode.Entity; //to assist in rendering embedded collisions properly...
@@ -146,6 +149,7 @@ namespace CodeWalker.Rendering
public bool RenderedBoundCompsListEnable = false; //whether or not to add rendered bound comps to the list
+ private List tryGetRenderableHDtxds = new List();
@@ -1578,38 +1582,31 @@ namespace CodeWalker.Rendering
}
- //go through the render list, and try ensure renderables and textures for all.
- //if an entity is not fully loaded, set a flag for its parent, then traverse to root
- //until found an entity that is fully loaded.
- //on a second loop, build a final render list based on the flags.
-
- for (int i = 0; i < renderworldentities.Count; i++)
+ if (renderentities)
{
- var ent = renderworldentities[i];
- var arch = ent.Archetype;
- var pent = ent.Parent;
- var drawable = gameFileCache.TryGetDrawable(arch);
- Renderable rndbl = TryGetRenderable(arch, drawable);
- if ((rndbl != null) && rndbl.IsLoaded && (rndbl.AllTexturesLoaded || !waitforchildrentoload))
+ //go through the render list, and try ensure renderables and textures for all.
+ //if an entity is not fully loaded, set a flag for its parent, then traverse to root
+ //until found an entity that is fully loaded.
+ //on a second loop, build a final render list based on the flags.
+ for (int i = 0; i < renderworldentities.Count; i++)
{
- RenderableEntity rent = new RenderableEntity();
- rent.Entity = ent;
- rent.Renderable = rndbl;
- renderworldrenderables.Add(rent);
+ var ent = renderworldentities[i];
+ var arch = ent.Archetype;
+ var pent = ent.Parent;
+ var drawable = gameFileCache.TryGetDrawable(arch);
+ Renderable rndbl = TryGetRenderable(arch, drawable);
+ if ((rndbl != null) && rndbl.IsLoaded && (rndbl.AllTexturesLoaded || !waitforchildrentoload))
+ {
+ RenderableEntity rent = new RenderableEntity();
+ rent.Entity = ent;
+ rent.Renderable = rndbl;
+ renderworldrenderables.Add(rent);
+ }
+ else if (waitforchildrentoload)
+ {
+ //todo: render parent if children loading.......
+ }
}
- else if (waitforchildrentoload)
- {
- //todo: render parent if children loading.......
- }
-
- if ((rendercollisionmeshes || (SelectionMode == MapSelectionMode.Collision)) && renderinteriors)
- {
- RenderInteriorCollisionMesh(ent);
- }
- }
-
- if(renderentities)
- {
for (int i = 0; i < renderworldrenderables.Count; i++)
{
var rent = renderworldrenderables[i];
@@ -1621,6 +1618,21 @@ namespace CodeWalker.Rendering
}
+
+ if (renderinteriors && (rendercollisionmeshes || (SelectionMode == MapSelectionMode.Collision)))
+ {
+ for (int i = 0; i < renderworldentities.Count; i++)
+ {
+ var ent = renderworldentities[i];
+ if (ent.IsMlo)
+ {
+ RenderInteriorCollisionMesh(ent);
+ }
+ }
+ }
+
+
+
if (rendercars)
{
for (int y = 0; y < VisibleYmaps.Count; y++)
@@ -1766,59 +1778,9 @@ namespace CodeWalker.Rendering
renderworldentities.Add(ent);
- if (renderinteriors && ent.IsMlo) //render Mlo child entities...
+ if (renderinteriors && ent.IsMlo && (ent.MloInstance != null)) //render Mlo child entities...
{
- if ((ent.MloInstance != null))
- {
- if (ent.MloInstance.Entities != null)
- {
- for (int j = 0; j < ent.MloInstance.Entities.Length; j++)
- {
- var intent = ent.MloInstance.Entities[j];
- if (intent.Archetype == null) continue; //missing archetype...
- if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
-
- intent.IsVisible = true;
-
- var iebscent = intent.Position + intent.BSCenter - camera.Position;
- float iebsrad = intent.BSRadius;
- if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad))
- {
- continue; //frustum cull interior ents
- }
-
- renderworldentities.Add(intent);
- }
- }
- if (ent.MloInstance.EntitySets != null)
- {
- foreach (var entitysets in ent.MloInstance.EntitySets)
- {
- var entityset = entitysets.Value;
- if (!entityset.Visible) continue;
-
- var entities = entityset.Entities;
- for (int i = 0; i < entities.Count; i++)
- {
- var intent = entities[i];
- if (intent.Archetype == null) continue; //missing archetype...
- if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
-
- intent.IsVisible = true;
-
- var iebscent = intent.Position + intent.BSCenter - camera.Position;
- float iebsrad = intent.BSRadius;
- if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad))
- {
- continue; //frustum cull interior ents
- }
-
- renderworldentities.Add(intent);
-
- }
- }
- }
- }
+ RenderWorldAddInteriorEntities(ent);
}
}
@@ -1835,7 +1797,57 @@ namespace CodeWalker.Rendering
}
}
}
+ private void RenderWorldAddInteriorEntities(YmapEntityDef ent)
+ {
+ if (ent.MloInstance.Entities != null)
+ {
+ for (int j = 0; j < ent.MloInstance.Entities.Length; j++)
+ {
+ var intent = ent.MloInstance.Entities[j];
+ if (intent.Archetype == null) continue; //missing archetype...
+ if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
+ intent.IsVisible = true;
+
+ var iebscent = intent.Position + intent.BSCenter - camera.Position;
+ float iebsrad = intent.BSRadius;
+ if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad))
+ {
+ continue; //frustum cull interior ents
+ }
+
+ renderworldentities.Add(intent);
+ }
+ }
+ if (ent.MloInstance.EntitySets != null)
+ {
+ foreach (var entitysets in ent.MloInstance.EntitySets)
+ {
+ var entityset = entitysets.Value;
+ if (!entityset.Visible) continue;
+
+ var entities = entityset.Entities;
+ for (int i = 0; i < entities.Count; i++)
+ {
+ var intent = entities[i];
+ if (intent.Archetype == null) continue; //missing archetype...
+ if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
+
+ intent.IsVisible = true;
+
+ var iebscent = intent.Position + intent.BSCenter - camera.Position;
+ float iebsrad = intent.BSRadius;
+ if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad))
+ {
+ continue; //frustum cull interior ents
+ }
+
+ renderworldentities.Add(intent);
+
+ }
+ }
+ }
+ }
@@ -2381,6 +2393,16 @@ namespace CodeWalker.Rendering
float distance = (camrel + bscen).Length();
+
+ //bool usehdtxd = renderhdtextures && ((dist - bsrad) <= arche._BaseArchetypeDef.hdTextureDist);
+ //var usehdtxd = false;
+ //if ((arch != null) && (renderhdtextures))
+ //{
+ // usehdtxd = ((ent.Distance - arch.BSRadius) <= arch._BaseArchetypeDef.hdTextureDist);
+ //}
+
+
+
if ((rendercollisionmeshes || (SelectionMode == MapSelectionMode.Collision)) && rendercollisionmeshlayerdrawable)
{
Drawable sdrawable = rndbl.Key as Drawable;
@@ -2581,14 +2603,27 @@ namespace CodeWalker.Rendering
-
private Renderable TryGetRenderable(Archetype arche, DrawableBase drawable, uint txdHash = 0)
{
if (drawable == null) return null;
//BUG: only last texdict used!! needs to cache textures per archetype........
//(but is it possible to have the same drawable with different archetypes?)
- uint texDict = (arche != null) ? arche.TextureDict.Hash : txdHash;
- uint clipDict = (arche != null) ? arche.ClipDict.Hash : 0;
+ MetaHash texDict = txdHash;
+ //uint texDictOrig = txdHash;
+ uint clipDict = 0;
+
+ if (arche != null)
+ {
+ texDict = arche.TextureDict.Hash;
+ clipDict = arche.ClipDict.Hash;
+
+ //texDictOrig = texDict;
+ //if (hdtxd)
+ //{
+ // texDict = gameFileCache.TryGetHDTextureHash(texDict);
+ //}
+ }
+
Renderable rndbl = renderableCache.GetRenderable(drawable);
if (rndbl == null) return null;
@@ -2624,11 +2659,61 @@ namespace CodeWalker.Rendering
var yptTexDict = (drawable.Owner as YptFile)?.PtfxList?.TextureDictionary;
+
+ tryGetRenderableHDtxds.Clear();
+ if (renderhdtextures)
+ {
+ if (arche != null) //try get HD txd for the asset
+ {
+ MetaHash hdtxd = gameFileCache.TryGetHDTextureHash(arche._BaseArchetypeDef.assetName);
+ if (hdtxd != arche._BaseArchetypeDef.assetName)
+ {
+ var asshdytd = gameFileCache.GetYtd(hdtxd);
+ if ((asshdytd != null) && (asshdytd.Loaded))
+ {
+ tryGetRenderableHDtxds.Add(asshdytd);
+ }
+ }
+ }
+ if (texDict != 0) //try get HD txd for the current txd
+ {
+ MetaHash hdtxd = gameFileCache.TryGetHDTextureHash(texDict);
+ if (hdtxd != texDict)
+ {
+ var txdhdytd = gameFileCache.GetYtd(hdtxd);
+ if ((txdhdytd != null) && (txdhdytd.Loaded))
+ {
+ tryGetRenderableHDtxds.Add(txdhdytd);
+ }
+ }
+
+ MetaHash ptxdname = gameFileCache.TryGetParentYtdHash(texDict);
+ while (ptxdname != 0) //look for parent HD txds
+ {
+ MetaHash phdtxdname = gameFileCache.TryGetHDTextureHash(ptxdname);
+ if (phdtxdname != ptxdname)
+ {
+ var phdytd = gameFileCache.GetYtd(phdtxdname);
+ if ((phdytd != null) && (phdytd.Loaded))
+ {
+ tryGetRenderableHDtxds.Add(phdytd);
+ }
+ }
+ ptxdname = gameFileCache.TryGetParentYtdHash(ptxdname);
+ }
+ }
+ if (tryGetRenderableHDtxds.Count > 0)
+ { }
+ }
+
+ YtdFile ytd = (texDict != 0) ? gameFileCache.GetYtd(texDict) : null;
+
+
bool alltexsloaded = true;
int missingtexcount = 0;
- for (int mi = 0; mi < rndbl.HDModels.Length; mi++)
+ for (int mi = 0; mi < rndbl.AllModels.Length; mi++)
{
- var model = rndbl.HDModels[mi];
+ var model = rndbl.AllModels[mi];
//if (!RenderIsModelFinalRender(model) && !renderproxies)
//{
@@ -2644,56 +2729,32 @@ namespace CodeWalker.Rendering
{
var tex = geom.Textures[i];
var ttex = tex as Texture;
+ Texture dtex = null;
RenderableTexture rdtex = null;
- if ((ttex == null) && (tex != null))
+ if ((tex != null) && (ttex == null))
{
//TextureRef means this RenderableTexture needs to be loaded from texture dict...
if (yptTexDict != null) //for ypt files, first try the embedded tex dict..
{
- var dtex = yptTexDict.Lookup(tex.NameHash);
- rdtex = renderableCache.GetRenderableTexture(dtex);
+ dtex = yptTexDict.Lookup(tex.NameHash);
}
else if (texDict != 0)
{
- YtdFile ytd = gameFileCache.GetYtd(texDict);
if ((ytd != null) && (ytd.Loaded) && (ytd.TextureDict != null))
{
- var dtex = ytd.TextureDict.Lookup(tex.NameHash);
+ dtex = ytd.TextureDict.Lookup(tex.NameHash);
if (dtex == null)
{
- //not present in dictionary... check already loaded texture dicts...
- var ytd2 = gameFileCache.TryGetTextureDictForTexture(tex.NameHash);
- if ((ytd2 != null) && (ytd2.Loaded) && (ytd2.TextureDict != null))
- {
- dtex = ytd2.TextureDict.Lookup(tex.NameHash);
- }
- else
- {
- //couldn't find texture dict?
- //first try going through ytd hierarchy...
- dtex = gameFileCache.TryFindTextureInParent(tex.NameHash, texDict);
-
-
- //if (dtex == null)
- //{ //try for a texture dict with the same hash as the archetype?
- // dtex = gameFileCache.TryFindTextureInParent(tex.TextureRef.NameHash, arche.Hash);
- // if (dtex != null)
- // { }
- //}
- }
- }
- if (dtex != null)
- {
- geom.Textures[i] = dtex; //cache it for next time to avoid the lookup...
- rdtex = renderableCache.GetRenderableTexture(dtex);
+ //couldn't find texture in specified dict
+ //first try going through ytd hierarchy...
+ dtex = gameFileCache.TryFindTextureInParent(tex.NameHash, texDict);
}
if (rdtex == null)
{ } //nothing to see here :(
}
- else if ((ytd == null))
+ else if ((ytd == null))//ytd not found
{
- Texture dtex = null;
- if (drawable.ShaderGroup.TextureDictionary != null)
+ if (drawable.ShaderGroup.TextureDictionary != null)//check any embedded texdict
{
dtex = drawable.ShaderGroup.TextureDictionary.Lookup(tex.NameHash);
if (dtex == null)
@@ -2703,19 +2764,8 @@ namespace CodeWalker.Rendering
}
if (dtex == null)
{
- var ytd2 = gameFileCache.TryGetTextureDictForTexture(tex.NameHash);
- if ((ytd2 != null) && (ytd2.Loaded) && (ytd2.TextureDict != null))
- {
- dtex = ytd2.TextureDict.Lookup(tex.NameHash);
- }
- if (dtex == null)
- {
- dtex = gameFileCache.TryFindTextureInParent(tex.NameHash, texDict);
- }
+ dtex = gameFileCache.TryFindTextureInParent(tex.NameHash, texDict);
}
- rdtex = renderableCache.GetRenderableTexture(dtex);
- if (rdtex == null)
- { missingtexcount -= 2; } //(give extra chance..) couldn't find the texture! :(
}
else if (ytd != null)
{
@@ -2724,13 +2774,26 @@ namespace CodeWalker.Rendering
}
}
else //no texdict specified, nothing to see here..
+ { }
+ if (dtex == null)
{
+ //not present in dictionary... check already loaded texture dicts... (maybe resident?)
var ytd2 = gameFileCache.TryGetTextureDictForTexture(tex.NameHash);
if ((ytd2 != null) && (ytd2.Loaded) && (ytd2.TextureDict != null))
{
- var dtex = ytd2.TextureDict.Lookup(tex.NameHash);
- rdtex = renderableCache.GetRenderableTexture(dtex);
+ dtex = ytd2.TextureDict.Lookup(tex.NameHash);
}
+ //else
+ //{
+ // //couldn't find texture dict?
+ //}
+ }
+
+ if (dtex != null)
+ {
+ geom.Textures[i] = dtex; //cache it for next time to avoid the lookup...
+ ttex = dtex;
+ rdtex = renderableCache.GetRenderableTexture(dtex);
}
}
else if (ttex != null) //ensure embedded renderable texture
@@ -2757,6 +2820,29 @@ namespace CodeWalker.Rendering
}
+ RenderableTexture rhdtex = null;
+ if (renderhdtextures)
+ {
+ Texture hdtex = geom.TexturesHD[i];
+ if (hdtex == null)
+ {
+ for (int j = 0; j < tryGetRenderableHDtxds.Count; j++)
+ {
+ hdtex = tryGetRenderableHDtxds[j].TextureDict?.Lookup(tex.NameHash);
+ if (hdtex != null) break;
+ }
+ if (hdtex != null)
+ {
+ geom.TexturesHD[i] = hdtex;
+ }
+ }
+ if (hdtex != null)
+ {
+ rhdtex = renderableCache.GetRenderableTexture(hdtex);
+ }
+ }
+ geom.RenderableTexturesHD[i] = rhdtex;
+
}
}
}
diff --git a/Rendering/Shaders/BasicShader.cs b/Rendering/Shaders/BasicShader.cs
index b586e77..9cc5f52 100644
--- a/Rendering/Shaders/BasicShader.cs
+++ b/Rendering/Shaders/BasicShader.cs
@@ -529,6 +529,14 @@ namespace CodeWalker.Rendering
for (int i = 0; i < geom.RenderableTextures.Length; i++)
{
var itex = geom.RenderableTextures[i];
+ if (geom.HDTextureEnable)
+ {
+ var hdtex = geom.RenderableTexturesHD[i];
+ if ((hdtex != null) && (hdtex.IsLoaded))
+ {
+ itex = hdtex;
+ }
+ }
var ihash = geom.TextureParamHashes[i];
if (itex == null) continue;
if (itex.Key?.NameHash == 1678728908 /*"blank"*/) continue;
diff --git a/Rendering/Shaders/TerrainShader.cs b/Rendering/Shaders/TerrainShader.cs
index 446015b..6f5c151 100644
--- a/Rendering/Shaders/TerrainShader.cs
+++ b/Rendering/Shaders/TerrainShader.cs
@@ -376,6 +376,14 @@ namespace CodeWalker.Rendering
for (int i = 0; i < geom.RenderableTextures.Length; i++)
{
var itex = geom.RenderableTextures[i];
+ if (geom.HDTextureEnable)
+ {
+ var hdtex = geom.RenderableTexturesHD[i];
+ if ((hdtex != null) && (hdtex.IsLoaded))
+ {
+ itex = hdtex;
+ }
+ }
var ihash = geom.TextureParamHashes[i];
switch (ihash)
{
diff --git a/WorldForm.Designer.cs b/WorldForm.Designer.cs
index 38132cf..23b5394 100644
--- a/WorldForm.Designer.cs
+++ b/WorldForm.Designer.cs
@@ -109,6 +109,7 @@ namespace CodeWalker
this.tabPage4 = new System.Windows.Forms.TabPage();
this.OptionsTabControl = new System.Windows.Forms.TabControl();
this.tabPage8 = new System.Windows.Forms.TabPage();
+ this.CarGeneratorsCheckBox = new System.Windows.Forms.CheckBox();
this.RenderEntitiesCheckBox = new System.Windows.Forms.CheckBox();
this.AdvancedSettingsButton = new System.Windows.Forms.Button();
this.ControlSettingsButton = new System.Windows.Forms.Button();
@@ -286,7 +287,7 @@ namespace CodeWalker
this.ToolbarCameraMapViewButton = new System.Windows.Forms.ToolStripMenuItem();
this.ToolbarCameraOrthographicButton = new System.Windows.Forms.ToolStripMenuItem();
this.ToolbarPanel = new System.Windows.Forms.Panel();
- this.CarGeneratorsCheckBox = new System.Windows.Forms.CheckBox();
+ this.HDTexturesCheckBox = new System.Windows.Forms.CheckBox();
this.StatusStrip.SuspendLayout();
this.ToolsPanel.SuspendLayout();
this.ToolsTabControl.SuspendLayout();
@@ -1335,6 +1336,17 @@ namespace CodeWalker
this.tabPage8.Text = "General";
this.tabPage8.UseVisualStyleBackColor = true;
//
+ // CarGeneratorsCheckBox
+ //
+ this.CarGeneratorsCheckBox.AutoSize = true;
+ this.CarGeneratorsCheckBox.Location = new System.Drawing.Point(10, 72);
+ this.CarGeneratorsCheckBox.Name = "CarGeneratorsCheckBox";
+ this.CarGeneratorsCheckBox.Size = new System.Drawing.Size(124, 17);
+ this.CarGeneratorsCheckBox.TabIndex = 31;
+ this.CarGeneratorsCheckBox.Text = "Show car generators";
+ this.CarGeneratorsCheckBox.UseVisualStyleBackColor = true;
+ this.CarGeneratorsCheckBox.CheckedChanged += new System.EventHandler(this.CarGeneratorsCheckBox_CheckedChanged);
+ //
// RenderEntitiesCheckBox
//
this.RenderEntitiesCheckBox.AutoSize = true;
@@ -1633,6 +1645,7 @@ namespace CodeWalker
//
// tabPage14
//
+ this.tabPage14.Controls.Add(this.HDTexturesCheckBox);
this.tabPage14.Controls.Add(this.WireframeCheckBox);
this.tabPage14.Controls.Add(this.RenderModeComboBox);
this.tabPage14.Controls.Add(this.label11);
@@ -3270,16 +3283,18 @@ namespace CodeWalker
this.ToolbarPanel.TabIndex = 7;
this.ToolbarPanel.Visible = false;
//
- // CarGeneratorsCheckBox
+ // HDTexturesCheckBox
//
- this.CarGeneratorsCheckBox.AutoSize = true;
- this.CarGeneratorsCheckBox.Location = new System.Drawing.Point(10, 72);
- this.CarGeneratorsCheckBox.Name = "CarGeneratorsCheckBox";
- this.CarGeneratorsCheckBox.Size = new System.Drawing.Size(124, 17);
- this.CarGeneratorsCheckBox.TabIndex = 31;
- this.CarGeneratorsCheckBox.Text = "Show car generators";
- this.CarGeneratorsCheckBox.UseVisualStyleBackColor = true;
- this.CarGeneratorsCheckBox.CheckedChanged += new System.EventHandler(this.CarGeneratorsCheckBox_CheckedChanged);
+ this.HDTexturesCheckBox.AutoSize = true;
+ this.HDTexturesCheckBox.Checked = true;
+ this.HDTexturesCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.HDTexturesCheckBox.Location = new System.Drawing.Point(10, 231);
+ this.HDTexturesCheckBox.Name = "HDTexturesCheckBox";
+ this.HDTexturesCheckBox.Size = new System.Drawing.Size(82, 17);
+ this.HDTexturesCheckBox.TabIndex = 57;
+ this.HDTexturesCheckBox.Text = "HD textures";
+ this.HDTexturesCheckBox.UseVisualStyleBackColor = true;
+ this.HDTexturesCheckBox.CheckedChanged += new System.EventHandler(this.HDTexturesCheckBox_CheckedChanged);
//
// WorldForm
//
@@ -3624,5 +3639,6 @@ namespace CodeWalker
private System.Windows.Forms.CheckBox RenderEntitiesCheckBox;
private System.Windows.Forms.ToolStripMenuItem ToolbarSelectOcclusionButton;
private System.Windows.Forms.CheckBox CarGeneratorsCheckBox;
+ private System.Windows.Forms.CheckBox HDTexturesCheckBox;
}
}
\ No newline at end of file
diff --git a/WorldForm.cs b/WorldForm.cs
index 6d28357..459e56d 100644
--- a/WorldForm.cs
+++ b/WorldForm.cs
@@ -6634,6 +6634,11 @@ namespace CodeWalker
Renderer.renderproxies = ProxiesCheckBox.Checked;
}
+ private void HDTexturesCheckBox_CheckedChanged(object sender, EventArgs e)
+ {
+ Renderer.renderhdtextures = HDTexturesCheckBox.Checked;
+ }
+
private void PathsCheckBox_CheckedChanged(object sender, EventArgs e)
{
renderpaths = PathsCheckBox.Checked;
diff --git a/WorldForm.resx b/WorldForm.resx
index 8689d72..fe93ed0 100644
--- a/WorldForm.resx
+++ b/WorldForm.resx
@@ -240,14 +240,6 @@ ufo
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB4SURBVDhP3ZC7DcAgDEQZKTMwHOvSIFriS7BlEB+HMic9
QJbvFThLUkpXzjkSpaeuzMPlEELx3jdsBauyCHBY6UWYPQI93KEljQD3jL6EGzN6x0bASyNYwkKU8Udm
gd6TMnIikDJyIqjVNz8T7FgKrAwFX6lVinM3aJ05lWDPRRcAAAAASUVORK5CYII=
-
-
-
-
- iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB0SURBVDhP7ZNBCoAgEEXnSJ3BqxmetNpaMLhVv5DNRJS2
- CxIeuvA9XSjtg5mHEILPxB6U7JyLxphmSkDK1o5x9dst87SUfTXwRsYsA+paT0BGDGsVOJ92hdz3Bz4f
- wGPC48uu7w5IGd+gBlpRMgYCnRwyESUj3CsQkYNFDwAAAABJRU5ErkJggg==
@@ -269,13 +261,12 @@ ufo
WBXYx9R1nV75RuyHKrrnzCcGjE1u9ZyD4BugoZigQ9xrngAAAABJRU5ErkJggg==
-
+
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACtSURBVDhPrZBBEsIgEAR5Gy/wFV55T/wHr+KgHuCKNsVY
- ZI2JiU7VVIVlp7OL+1mllIr7cb8Ie++PQwQYITnnM24NWxoBgsQYm/l+gk699bMsRA4h1JTSPsg0Xert
- em/mGwh3vW1Z7MvIABSWqXG3+iZHAEw1m4wD49oVANgVOL/VeSgeDAiX1mpWeKy9BIQiI+OxWQF77tG5
- 2Fc729BmeElf/3lNhORe+oecewDObEqX49RqCgAAAABJRU5ErkJggg==
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB0SURBVDhP7ZNBCoAgEEXnSJ3BqxmetNpaMLhVv5DNRJS2
+ CxIeuvA9XSjtg5mHEILPxB6U7JyLxphmSkDK1o5x9dst87SUfTXwRsYsA+paT0BGDGsVOJ92hdz3Bz4f
+ wGPC48uu7w5IGd+gBlpRMgYCnRwyESUj3CsQkYNFDwAAAABJRU5ErkJggg==
@@ -304,6 +295,15 @@ ufo
EcMw2DzPDMEke9AsYBrHs10vN4I1QqImwwDcFyMjQGaBHr5Bo8nEoYCnCQTGzVeI4oj6fIi+KHgoPBhC
4knCjTww9vxfbIUQNDEyiGIZ8t6tW/k0vC/AOpuiueNOLwVkUeylvju9FJCg8E1vM/2PlTv5UoervVTJ
uQAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACtSURBVDhPrZBBEsIgEAR5Gy/wFV55T/wHr+KgHuCKNsVY
+ ZI2JiU7VVIVlp7OL+1mllIr7cb8Ie++PQwQYITnnM24NWxoBgsQYm/l+gk699bMsRA4h1JTSPsg0Xert
+ em/mGwh3vW1Z7MvIABSWqXG3+iZHAEw1m4wD49oVANgVOL/VeSgeDAiX1mpWeKy9BIQiI+OxWQF77tG5
+ 2Fc729BmeElf/3lNhORe+oecewDObEqX49RqCgAAAABJRU5ErkJggg==
@@ -389,17 +389,6 @@ ufo
4BJN+IjGo5O8ZJndGVhKxpjWWts551aih0fre+0BLaVchRAezPB2NXSSV/gVwXGYPJiVUt6ns1ghCDjn
UQG86w3FToVgDcWCWS9Fvi/Ao0RVAcwUjwpyhzmf4n8BFApS5HZRwRuONGMbrIJ1JIN8O2QAAAAASUVO
RK5CYII=
-
-
-
-
- iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
- YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEvSURBVDhP3dK/K0dRGMfxKxRJopCSEkLya/guUhQRmQwG
- WfwIkYySgYUSKUKJlOK/MBoMFMofYLUIsfJ+f3NuF3+A8tRree5zP/fcc070f6oHT/jAPTqQj6WvXvCM
- TZQgG3H58gFGcYVLtGIN15jBNDbwiGNUIg4pQx8GsQuHhrCDW8yjHyns4Q0DcCXpykM5bFzgHGPYxw1G
- UIVMtMHfWUUj4nIg/KurGIYrSAZYOXDGlbhXcZlegUO8Yxzb+BlQAwNW0G0jVAYK0AwHtnCEOyQDZvGC
- ObTbKIIvLMA9WIYDizhFMsDjfsAZptCA9JcdfoVBvryOSbgCe4HPTuCz+BQMKEUvJmCy96ET1ehCuAf2
- 5ZF+uwdZKEYtmuBGFSIXhtejBe5PHX7dxL+qKPoEppRHcXOtiDsAAAAASUVORK5CYII=
@@ -435,6 +424,17 @@ ufo
rp3fhGJScIRLzKMLFTC9cMIu3nCDVUyjB6WkYA93mEWbAyH9cMImPuA+rWMA31YwBU82kF6BS32Er/aO
M8zAh+OEghpcwQ2bg3uwBW8ewFd7xQkm0IA4oaAS7bh2KHjBIZbhV/D6GJkFphrdcIP8lFrAGPwPOjCO
QdQiTqrAWNICd7gPnUj+xBKaU9dxfhTkjwV/FxU+AbsiGnc46OYIAAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEvSURBVDhP3dK/K0dRGMfxKxRJopCSEkLya/guUhQRmQwG
+ WfwIkYySgYUSKUKJlOK/MBoMFMofYLUIsfJ+f3NuF3+A8tRree5zP/fcc070f6oHT/jAPTqQj6WvXvCM
+ TZQgG3H58gFGcYVLtGIN15jBNDbwiGNUIg4pQx8GsQuHhrCDW8yjHyns4Q0DcCXpykM5bFzgHGPYxw1G
+ UIVMtMHfWUUj4nIg/KurGIYrSAZYOXDGlbhXcZlegUO8Yxzb+BlQAwNW0G0jVAYK0AwHtnCEOyQDZvGC
+ ObTbKIIvLMA9WIYDizhFMsDjfsAZptCA9JcdfoVBvryOSbgCe4HPTuCz+BQMKEUvJmCy96ET1ehCuAf2
+ 5ZF+uwdZKEYtmuBGFSIXhtejBe5PHX7dxL+qKPoEppRHcXOtiDsAAAAASUVORK5CYII=