mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2025-01-09 23:15:09 +08:00
Replaced world grid with quadtrees, improved loading speed of cutscenes
This commit is contained in:
parent
d59663d87e
commit
a5259c17fe
@ -625,6 +625,22 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
|
||||
public void GetVisibleChildren(ref Vector3 p, List<MapDataStoreNode> items)
|
||||
{
|
||||
if (Children == null) return;
|
||||
for (int i = 0; i < Children.Length; i++)
|
||||
{
|
||||
var c = Children[i];
|
||||
if (c == null) continue;
|
||||
var cmin = c.streamingExtentsMin;
|
||||
var cmax = c.streamingExtentsMax;
|
||||
if ((p.X >= cmin.X) && (p.X <= cmax.X) && (p.Y >= cmin.Y) && (p.Y <= cmax.Y))
|
||||
{
|
||||
items.Add(c);
|
||||
c.GetVisibleChildren(ref p, items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ namespace CodeWalker.World
|
||||
Yld = gfc.GetFileUncached<YldFile>(clothFile);
|
||||
while ((Yld != null) && (!Yld.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(Yld);
|
||||
}
|
||||
}
|
||||
@ -110,22 +110,22 @@ namespace CodeWalker.World
|
||||
|
||||
while ((Ydd != null) && (!Ydd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ydd = gfc.GetYdd(pedhash);
|
||||
}
|
||||
while ((Ytd != null) && (!Ytd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ytd = gfc.GetYtd(pedhash);
|
||||
}
|
||||
while ((Ycd != null) && (!Ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ycd = gfc.GetYcd(ycdhash);
|
||||
}
|
||||
while ((Yft != null) && (!Yft.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Yft = gfc.GetYft(pedhash);
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ namespace CodeWalker.World
|
||||
var ydd = gfc.GetFileUncached<YddFile>(file);
|
||||
while ((ydd != null) && (!ydd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(ydd);
|
||||
}
|
||||
if (ydd?.Drawables?.Length > 0)
|
||||
@ -193,7 +193,7 @@ namespace CodeWalker.World
|
||||
var ytd = gfc.GetFileUncached<YtdFile>(file);
|
||||
while ((ytd != null) && (!ytd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(ytd);
|
||||
}
|
||||
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
|
||||
@ -216,7 +216,7 @@ namespace CodeWalker.World
|
||||
var yld = gfc.GetFileUncached<YldFile>(file);
|
||||
while ((yld != null) && (!yld.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(yld);
|
||||
}
|
||||
if (yld?.ClothDictionary?.Clothes?.data_items?.Length > 0)
|
||||
|
@ -18,8 +18,12 @@ namespace CodeWalker.World
|
||||
private GameFileCache GameFileCache = null;
|
||||
|
||||
|
||||
public SpaceGrid Grid;
|
||||
private Dictionary<SpaceBoundsKey, BoundsStoreItem> visibleBoundsDict = new Dictionary<SpaceBoundsKey, BoundsStoreItem>();
|
||||
|
||||
|
||||
public SpaceMapDataStore MapDataStore;
|
||||
public SpaceBoundsStore BoundsStore;
|
||||
|
||||
|
||||
|
||||
private Dictionary<MetaHash, MetaHash> interiorLookup = new Dictionary<MetaHash, MetaHash>();
|
||||
private Dictionary<MetaHash, YmfInterior> interiorManifest = new Dictionary<MetaHash, YmfInterior>();
|
||||
@ -58,9 +62,14 @@ namespace CodeWalker.World
|
||||
InitCacheData();
|
||||
|
||||
|
||||
updateStatus("Building world grid...");
|
||||
updateStatus("Building map data store...");
|
||||
|
||||
InitMapGrid();
|
||||
InitMapDataStore();
|
||||
|
||||
|
||||
updateStatus("Building bounds store...");
|
||||
|
||||
InitBoundsStore();
|
||||
|
||||
|
||||
updateStatus("Loading paths...");
|
||||
@ -313,101 +322,46 @@ namespace CodeWalker.World
|
||||
|
||||
}
|
||||
|
||||
private void InitMapGrid()
|
||||
private void InitMapDataStore()
|
||||
{
|
||||
|
||||
Grid = new SpaceGrid();
|
||||
MapDataStore = new SpaceMapDataStore();
|
||||
|
||||
//List<MapDataStoreNode> containers = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> critnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> hdnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> lodnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> strmnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> intnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> occlnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> grassnodes = new List<MapDataStoreNode>();
|
||||
//List<MapDataStoreNode> lodlightsnodes = new List<MapDataStoreNode>();
|
||||
List<MapDataStoreNode> rootnodes = new List<MapDataStoreNode>();
|
||||
List<MapDataStoreNode> lodnodes = new List<MapDataStoreNode>();
|
||||
List<MapDataStoreNode> orphnodes = new List<MapDataStoreNode>();
|
||||
|
||||
foreach (var node in nodedict.Values)
|
||||
{
|
||||
bool addtogrid = false;
|
||||
byte t = (byte)(node.ContentFlags & 0xFF);
|
||||
switch (node.ContentFlags)// t)
|
||||
if (node.ParentName == 0)
|
||||
{
|
||||
case 0: //for mods/unused stuff? could be interesting.
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 16://"container" node?
|
||||
//containers.Add(node);
|
||||
break;
|
||||
case 18:
|
||||
case 82: //HD nodes
|
||||
//hdnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 1:
|
||||
case 65: //Stream nodes
|
||||
//strmnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 513:
|
||||
case 577: //critical nodes
|
||||
//critnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 9:
|
||||
case 73: //interior nodes
|
||||
//intnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 2:
|
||||
case 4:
|
||||
case 20:
|
||||
case 66:
|
||||
case 514: //LOD nodes
|
||||
//lodnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 128:
|
||||
case 256: //LOD lights nodes
|
||||
//lodlightsnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 32: //occlusion nodes
|
||||
//occlnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
case 1088: //grass nodes
|
||||
//grassnodes.Add(node);
|
||||
addtogrid = true;
|
||||
break;
|
||||
default:
|
||||
addtogrid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (addtogrid)
|
||||
rootnodes.Add(node);
|
||||
if (((node.ContentFlags & 2) > 0) || ((node.ContentFlags & 4) > 0) || ((node.ContentFlags & 16) > 0))
|
||||
{
|
||||
Grid.AddNode(node);
|
||||
lodnodes.Add(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
foreach (var item in boundsdict.Values)
|
||||
else
|
||||
{
|
||||
Grid.AddBounds(item);
|
||||
orphnodes.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var intprx in interiorProxies.Values)
|
||||
|
||||
MapDataStore.Init(rootnodes);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void InitBoundsStore()
|
||||
{
|
||||
Grid.AddInterior(intprx);
|
||||
}
|
||||
|
||||
BoundsStore = new SpaceBoundsStore();
|
||||
|
||||
BoundsStore.Init(boundsdict.Values.ToList());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void InitNodeGrid()
|
||||
{
|
||||
|
||||
@ -786,7 +740,7 @@ namespace CodeWalker.World
|
||||
public void Update(float elapsed)
|
||||
{
|
||||
if (!Inited) return;
|
||||
if (Grid == null) return;
|
||||
if (BoundsStore == null) return;
|
||||
|
||||
if (elapsed > 0.1f) elapsed = 0.1f;
|
||||
|
||||
@ -1044,19 +998,12 @@ namespace CodeWalker.World
|
||||
public void GetVisibleYmaps(Camera cam, int hour, MetaHash weather, Dictionary<MetaHash, YmapFile> ymaps)
|
||||
{
|
||||
if (!Inited) return;
|
||||
if (Grid == null) return;
|
||||
|
||||
|
||||
ymaps.Clear();
|
||||
|
||||
//var pos = Grid.GetCellPos(cam.Position);
|
||||
var cell = Grid.GetCell(cam.Position);
|
||||
if (cell.NodesList != null)
|
||||
if (MapDataStore == null) return;
|
||||
var items = MapDataStore.GetItems(ref cam.Position);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
for (int n = 0; n < cell.NodesList.Count; n++)
|
||||
{
|
||||
var node = cell.NodesList[n];
|
||||
var hash = node.Name;
|
||||
var item = items[i];
|
||||
var hash = item.Name;
|
||||
if (!ymaps.ContainsKey(hash))
|
||||
{
|
||||
var ymap = (hash > 0) ? GameFileCache.GetYmap(hash) : null;
|
||||
@ -1073,86 +1020,17 @@ namespace CodeWalker.World
|
||||
}
|
||||
|
||||
|
||||
|
||||
//int gridrange = 0;
|
||||
|
||||
//var pos = Grid.GetCellPos(cam.Position);
|
||||
//int minx = Math.Min(Math.Max(pos.X - gridrange, 0), SpaceGrid.LastCell);
|
||||
//int maxx = Math.Min(Math.Max(pos.X + gridrange, 0), SpaceGrid.LastCell);
|
||||
//int miny = Math.Min(Math.Max(pos.Y - gridrange, 0), SpaceGrid.LastCell);
|
||||
//int maxy = Math.Min(Math.Max(pos.Y + gridrange, 0), SpaceGrid.LastCell);
|
||||
|
||||
//for (int x = minx; x <= maxx; x++)
|
||||
//{
|
||||
// for (int y = miny; y <= maxy; y++)
|
||||
// {
|
||||
// var cell = Grid.GetCell(new Vector2I(x, y));
|
||||
// if (cell.NodesList != null)
|
||||
// {
|
||||
// for (int n = 0; n < cell.NodesList.Count; n++)
|
||||
// {
|
||||
// var node = cell.NodesList[n];
|
||||
// var hash = node.Name;
|
||||
// if (!ymaps.ContainsKey(hash))
|
||||
// {
|
||||
// var ymap = (hash > 0) ? GameFileCache.GetYmap(hash) : null;
|
||||
// if ((ymap != null) && (ymap.Loaded))
|
||||
// {
|
||||
// ymaps[hash] = ymap;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void GetVisibleBounds(Camera cam, int gridrange, bool[] layers, List<BoundsStoreItem> boundslist)
|
||||
{
|
||||
if (!Inited) return;
|
||||
if (Grid == null) return;
|
||||
|
||||
visibleBoundsDict.Clear();
|
||||
|
||||
var pos = Grid.GetCellPos(cam.Position);
|
||||
int minx = Math.Min(Math.Max(pos.X - gridrange, 0), SpaceGrid.LastCell);
|
||||
int maxx = Math.Min(Math.Max(pos.X + gridrange, 0), SpaceGrid.LastCell);
|
||||
int miny = Math.Min(Math.Max(pos.Y - gridrange, 0), SpaceGrid.LastCell);
|
||||
int maxy = Math.Min(Math.Max(pos.Y + gridrange, 0), SpaceGrid.LastCell);
|
||||
|
||||
for (int x = minx; x <= maxx; x++)
|
||||
{
|
||||
for (int y = miny; y <= maxy; y++)
|
||||
{
|
||||
var cell = Grid.GetCell(new Vector2I(x, y));
|
||||
if (cell.BoundsList != null)
|
||||
{
|
||||
foreach (var item in cell.BoundsList)
|
||||
{
|
||||
uint l = item.Layer;
|
||||
if (l < 3)
|
||||
{
|
||||
if (!layers[l]) continue;
|
||||
}
|
||||
else
|
||||
{ }
|
||||
|
||||
visibleBoundsDict[new SpaceBoundsKey(item.Name, item.Min)] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//var cell = grid.GetCell(cam.Position);
|
||||
//if (cell.BoundsList != null)
|
||||
//{
|
||||
// boundslist.AddRange(cell.BoundsList);
|
||||
//}
|
||||
|
||||
boundslist.AddRange(visibleBoundsDict.Values);
|
||||
|
||||
if (BoundsStore == null) return;
|
||||
float dist = 50.0f * gridrange;
|
||||
var pos = cam.Position;
|
||||
var min = pos - dist;
|
||||
var max = pos + dist;
|
||||
var items = BoundsStore.GetItems(ref min, ref max);
|
||||
boundslist.AddRange(items);
|
||||
}
|
||||
|
||||
|
||||
@ -1174,7 +1052,7 @@ namespace CodeWalker.World
|
||||
public void GetVisibleYnvs(Camera cam, int gridrange, List<YnvFile> ynvs)
|
||||
{
|
||||
if (!Inited) return;
|
||||
if (Grid == null) return;
|
||||
if (NavGrid == null) return;
|
||||
|
||||
|
||||
ynvs.Clear();
|
||||
@ -1213,18 +1091,11 @@ namespace CodeWalker.World
|
||||
int polytestcount = 0;
|
||||
int nodetestcount = 0;
|
||||
bool testcomplete = true;
|
||||
var cellpos = Grid.GetCellPos(ray.Position);
|
||||
var cell = Grid.GetCell(cellpos);
|
||||
var startz = ray.Position.Z;
|
||||
var maxcells = 5;
|
||||
var cellcount = 0;
|
||||
var box = new BoundingBox();
|
||||
var tsph = new BoundingSphere();
|
||||
var rayt = new Ray();
|
||||
var rp = ray.Position;
|
||||
var rd = ray.Direction;
|
||||
float dirx = (rd.X < 0) ? -1 : (rd.X > 0) ? 1 : 0;
|
||||
float diry = (rd.Y < 0) ? -1 : (rd.Y > 0) ? 1 : 0;
|
||||
var boxhitdist = float.MaxValue;
|
||||
var itemhitdist = float.MaxValue;
|
||||
Vector3 p1, p2, p3, p4, a1, a2, a3;
|
||||
@ -1235,11 +1106,11 @@ namespace CodeWalker.World
|
||||
BoundMaterial_s hitmat = new BoundMaterial_s();
|
||||
Vector3 hitnorm = Vector3.Zero;
|
||||
Vector3 hitpos = Vector3.Zero;
|
||||
while (cell != null)
|
||||
{
|
||||
if (cell.BoundsList != null)
|
||||
{
|
||||
foreach (var bound in cell.BoundsList)
|
||||
|
||||
if (BoundsStore == null) return res;
|
||||
var boundslist = BoundsStore.GetItems(ref ray);
|
||||
|
||||
foreach (var bound in boundslist)
|
||||
{
|
||||
uint l = bound.Layer;
|
||||
if ((layers != null) && (l < 3))
|
||||
@ -1447,39 +1318,6 @@ namespace CodeWalker.World
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//walk the line to the next cell...
|
||||
|
||||
cellcount++;
|
||||
if (cellcount >= maxcells) break;
|
||||
if ((dirx == 0) && (diry == 0)) break; //vertical ray
|
||||
|
||||
Vector3 cellwp = Grid.GetWorldPos(cellpos);
|
||||
float compx = (dirx < 0) ? cellwp.X : cellwp.X + SpaceGrid.CellSize;
|
||||
float compy = (diry < 0) ? cellwp.Y : cellwp.Y + SpaceGrid.CellSize;
|
||||
float deltx = Math.Abs(compx - rp.X);
|
||||
float delty = Math.Abs(compy - rp.Y);
|
||||
float nextd = 0;
|
||||
if (deltx < delty)
|
||||
{
|
||||
cellpos.X += (int)dirx;
|
||||
nextd = (rd.X != 0) ? (deltx / rd.X) : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellpos.Y += (int)diry;
|
||||
nextd = (rd.Y != 0) ? (delty / rd.Y) : 0;
|
||||
}
|
||||
|
||||
cell = Grid.GetCell(cellpos);
|
||||
|
||||
if (nextd > itemhitdist)
|
||||
{ break; } //next cell is further away than current hit.. no need to continue
|
||||
if (nextd > maxdist)
|
||||
{ break; } //next cell is out of the testing range.. stop now
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
@ -1508,9 +1346,6 @@ namespace CodeWalker.World
|
||||
bool testcomplete = true;
|
||||
Vector3 sphmin = sph.Center - sph.Radius;
|
||||
Vector3 sphmax = sph.Center + sph.Radius;
|
||||
var cellmin = Grid.GetCellPos(sphmin);
|
||||
var cellmax = Grid.GetCellPos(sphmax);
|
||||
var cellcount = 0;
|
||||
var box = new BoundingBox();
|
||||
var tsph = new BoundingSphere();
|
||||
var spht = new BoundingSphere();
|
||||
@ -1525,15 +1360,13 @@ namespace CodeWalker.World
|
||||
BoundPolygon hitpoly = null;
|
||||
Vector3 hitnorm = Vector3.Zero;
|
||||
Vector3 hitpos = Vector3.Zero;
|
||||
for (int x = cellmin.X; x <= cellmax.X; x++)
|
||||
{
|
||||
for (int y = cellmin.Y; y <= cellmax.Y; y++)
|
||||
{
|
||||
var cell = Grid.GetCell(new Vector2I(x, y));
|
||||
if (cell == null) continue;
|
||||
if (cell.BoundsList == null) continue;
|
||||
|
||||
foreach (var bound in cell.BoundsList)
|
||||
|
||||
if (BoundsStore == null) return res;
|
||||
var boundslist = BoundsStore.GetItems(ref sphmin, ref sphmax);
|
||||
|
||||
|
||||
foreach (var bound in boundslist)
|
||||
{
|
||||
box.Minimum = bound.Min;
|
||||
box.Maximum = bound.Max;
|
||||
@ -1722,9 +1555,6 @@ namespace CodeWalker.World
|
||||
}
|
||||
}
|
||||
|
||||
cellcount++;
|
||||
}
|
||||
}
|
||||
|
||||
//if (hit)
|
||||
//{
|
||||
@ -1745,205 +1575,8 @@ namespace CodeWalker.World
|
||||
|
||||
}
|
||||
|
||||
public class SpaceGrid
|
||||
{
|
||||
public const int CellCount = 500; //cells along a side, total cell count is this squared
|
||||
public const int LastCell = CellCount - 1; //the last cell index in the array
|
||||
public const float WorldSize = 10000.0f; //max world grid size +/- 10000 units
|
||||
public const float CellSize = 2.0f * WorldSize / (float)CellCount;//40.0f; //size of a cell
|
||||
public const float CellSizeInv = 1.0f / CellSize; //inverse of the cell size.
|
||||
public const float CellSizeHalf = CellSize * 0.5f; //half the cell size
|
||||
|
||||
public int TotalBoundsCount = 0; //total number of bounds in this grid
|
||||
public int TotalBoundsRefCount = 0; //total number of bounds placements in cells
|
||||
private int MaxBoundsInCell = 0; //biggest number of bounds added to a single cell
|
||||
private SpaceGridCell DensestBoundsCell = null;
|
||||
|
||||
public int TotalNodeCount = 0; //total map nodes in grid
|
||||
public int TotalNodeRefCount = 0; //total number of map node placements in cells
|
||||
public int MaxNodesInCell = 0; //biggest number of nodes added to a single cell
|
||||
private SpaceGridCell DensestNodeCell = null;
|
||||
|
||||
public int TotalInteriorCount = 0;
|
||||
public int TotalInteriorRefCount = 0;
|
||||
public int MaxInteriorsInCell = 0;
|
||||
private SpaceGridCell DensestInteriorCell = null;
|
||||
|
||||
public SpaceGridCell[,] Cells { get; set; } = new SpaceGridCell[CellCount, CellCount];
|
||||
|
||||
|
||||
public Vector3 GetWorldPos(Vector2I p)
|
||||
{
|
||||
Vector3 ind = new Vector3(p.X, p.Y, 0.0f);
|
||||
return (ind * CellSize) - new Vector3(WorldSize, WorldSize, 0);
|
||||
}
|
||||
public Vector2I GetCellPos(Vector3 p)
|
||||
{
|
||||
Vector3 ind = (p + WorldSize) * CellSizeInv;
|
||||
int x = (int)ind.X;
|
||||
int y = (int)ind.Y;
|
||||
x = (x < 0) ? 0 : (x > LastCell) ? LastCell : x;
|
||||
y = (y < 0) ? 0 : (y > LastCell) ? LastCell : y;
|
||||
return new Vector2I(x, y);
|
||||
}
|
||||
public SpaceGridCell GetCell(Vector2I g)
|
||||
{
|
||||
if ((g.X < 0) || (g.Y < 0) || (g.X >= CellCount) || (g.Y >= CellCount))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var cell = Cells[g.X, g.Y];
|
||||
if (cell == null)
|
||||
{
|
||||
cell = new SpaceGridCell();
|
||||
Cells[g.X, g.Y] = cell;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
public SpaceGridCell GetCell(Vector3 p)
|
||||
{
|
||||
return GetCell(GetCellPos(p));
|
||||
}
|
||||
|
||||
public void AddBounds(BoundsStoreItem item)
|
||||
{
|
||||
Vector2I min = GetCellPos(item.Min);
|
||||
Vector2I max = GetCellPos(item.Max);
|
||||
|
||||
int cellcount = 0;
|
||||
for (int x = min.X; x <= max.X; x++)
|
||||
{
|
||||
for (int y = min.Y; y <= max.Y; y++)
|
||||
{
|
||||
var cell = GetCell(new Vector2I(x, y));
|
||||
cell.AddBounds(item);
|
||||
TotalBoundsRefCount++;
|
||||
if (cell.BoundsList.Count > MaxBoundsInCell)
|
||||
{
|
||||
MaxBoundsInCell = cell.BoundsList.Count;
|
||||
DensestBoundsCell = cell;
|
||||
}
|
||||
cellcount++;
|
||||
}
|
||||
}
|
||||
if (cellcount == 0)
|
||||
{ }
|
||||
|
||||
TotalBoundsCount++;
|
||||
}
|
||||
|
||||
public void AddNode(MapDataStoreNode node)
|
||||
{
|
||||
bool useouter = true;// false;
|
||||
//switch (node.Unk01)
|
||||
//{
|
||||
// case 2:
|
||||
// case 4:
|
||||
// case 20:
|
||||
// case 66:
|
||||
// case 514://lods
|
||||
// useouter = true;
|
||||
// break;
|
||||
// case 128:
|
||||
// case 256://lodlights
|
||||
// useouter = true;
|
||||
// break;
|
||||
// case 18:
|
||||
// case 82://HD nodes
|
||||
// useouter = true;
|
||||
// break;
|
||||
//}
|
||||
|
||||
//Vector2I min = GetCellPos(node.OuterBBMin);
|
||||
//Vector2I max = GetCellPos(node.OuterBBMax);
|
||||
Vector2I min = GetCellPos(useouter ? node.streamingExtentsMin : node.entitiesExtentsMin);
|
||||
Vector2I max = GetCellPos(useouter ? node.streamingExtentsMax : node.entitiesExtentsMax);
|
||||
|
||||
for (int x = min.X; x <= max.X; x++)
|
||||
{
|
||||
for (int y = min.Y; y <= max.Y; y++)
|
||||
{
|
||||
var cell = GetCell(new Vector2I(x, y));
|
||||
cell.AddNode(node);
|
||||
TotalNodeRefCount++;
|
||||
if (cell.NodesList.Count > MaxNodesInCell)
|
||||
{
|
||||
MaxNodesInCell = cell.NodesList.Count;
|
||||
DensestNodeCell = cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TotalNodeCount++;
|
||||
}
|
||||
|
||||
public void AddInterior(CInteriorProxy intprx)
|
||||
{
|
||||
Vector2I min = GetCellPos(intprx.BBMin);
|
||||
Vector2I max = GetCellPos(intprx.BBMax);
|
||||
|
||||
int cellcount = 0;
|
||||
for (int x = min.X; x <= max.X; x++)
|
||||
{
|
||||
for (int y = min.Y; y <= max.Y; y++)
|
||||
{
|
||||
var cell = GetCell(new Vector2I(x, y));
|
||||
cell.AddInterior(intprx);
|
||||
TotalInteriorRefCount++;
|
||||
if (cell.InteriorList.Count > MaxInteriorsInCell)
|
||||
{
|
||||
MaxInteriorsInCell = cell.InteriorList.Count;
|
||||
DensestInteriorCell = cell;
|
||||
}
|
||||
cellcount++;
|
||||
}
|
||||
}
|
||||
if (cellcount == 0)
|
||||
{ }
|
||||
|
||||
TotalInteriorCount++;
|
||||
}
|
||||
}
|
||||
public class SpaceGridCell
|
||||
{
|
||||
public List<MapDataStoreNode> NodesList;
|
||||
public List<BoundsStoreItem> BoundsList;
|
||||
public List<CInteriorProxy> InteriorList;
|
||||
|
||||
public void AddNode(MapDataStoreNode node)
|
||||
{
|
||||
if (NodesList == null)
|
||||
{
|
||||
NodesList = new List<MapDataStoreNode>();
|
||||
}
|
||||
NodesList.Add(node);
|
||||
}
|
||||
|
||||
public void AddBounds(BoundsStoreItem item)
|
||||
{
|
||||
if (BoundsList == null)
|
||||
{
|
||||
BoundsList = new List<BoundsStoreItem>(5);
|
||||
}
|
||||
BoundsList.Add(item);
|
||||
}
|
||||
public void RemoveBounds(BoundsStoreItem item)
|
||||
{
|
||||
if (BoundsList != null)
|
||||
{
|
||||
BoundsList.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddInterior(CInteriorProxy intprx)
|
||||
{
|
||||
if (InteriorList == null)
|
||||
{
|
||||
InteriorList = new List<CInteriorProxy>(5);
|
||||
}
|
||||
InteriorList.Add(intprx);
|
||||
}
|
||||
}
|
||||
public struct SpaceBoundsKey
|
||||
{
|
||||
public MetaHash Name { get; set; }
|
||||
@ -1956,6 +1589,317 @@ namespace CodeWalker.World
|
||||
}
|
||||
|
||||
|
||||
public class SpaceMapDataStore
|
||||
{
|
||||
public SpaceMapDataStoreNode RootNode;
|
||||
public int SplitThreshold = 10;
|
||||
|
||||
public List<MapDataStoreNode> VisibleItems = new List<MapDataStoreNode>();
|
||||
|
||||
public void Init(List<MapDataStoreNode> rootnodes)
|
||||
{
|
||||
RootNode = new SpaceMapDataStoreNode();
|
||||
RootNode.Owner = this;
|
||||
foreach (var item in rootnodes)
|
||||
{
|
||||
RootNode.Add(item);
|
||||
}
|
||||
RootNode.TrySplit(SplitThreshold);
|
||||
}
|
||||
|
||||
public List<MapDataStoreNode> GetItems(ref Vector3 p)
|
||||
{
|
||||
VisibleItems.Clear();
|
||||
|
||||
if (RootNode != null)
|
||||
{
|
||||
RootNode.GetItems(ref p, VisibleItems);
|
||||
}
|
||||
|
||||
return VisibleItems;
|
||||
}
|
||||
}
|
||||
public class SpaceMapDataStoreNode
|
||||
{
|
||||
public SpaceMapDataStore Owner = null;
|
||||
public SpaceMapDataStoreNode[] Children = null;
|
||||
public List<MapDataStoreNode> Items = null;
|
||||
public Vector3 BBMin = new Vector3(float.MaxValue);
|
||||
public Vector3 BBMax = new Vector3(float.MinValue);
|
||||
public int Depth = 0;
|
||||
|
||||
public void Add(MapDataStoreNode item)
|
||||
{
|
||||
if (Items == null)
|
||||
{
|
||||
Items = new List<MapDataStoreNode>();
|
||||
}
|
||||
BBMin = Vector3.Min(BBMin, item.streamingExtentsMin);
|
||||
BBMax = Vector3.Max(BBMax, item.streamingExtentsMax);
|
||||
Items.Add(item);
|
||||
}
|
||||
|
||||
public void TrySplit(int threshold)
|
||||
{
|
||||
if ((Items == null) || (Items.Count <= threshold))
|
||||
{ return; }
|
||||
|
||||
Children = new SpaceMapDataStoreNode[4];
|
||||
|
||||
var newItems = new List<MapDataStoreNode>();
|
||||
|
||||
var ncen = (BBMax + BBMin) * 0.5f;
|
||||
var next = (BBMax - BBMin) * 0.5f;
|
||||
var nsiz = Math.Max(next.X, next.Y);
|
||||
var nsizh = nsiz * 0.5f;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var imin = item.streamingExtentsMin;
|
||||
var imax = item.streamingExtentsMax;
|
||||
var icen = (imax + imin) * 0.5f;
|
||||
var iext = (imax - imin) * 0.5f;
|
||||
var isiz = Math.Max(iext.X, iext.Y);
|
||||
|
||||
if (isiz >= nsizh)
|
||||
{
|
||||
newItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
var cind = ((icen.X > ncen.X) ? 1 : 0) + ((icen.Y > ncen.Y) ? 2 : 0);
|
||||
var c = Children[cind];
|
||||
if (c == null)
|
||||
{
|
||||
c = new SpaceMapDataStoreNode();
|
||||
c.Owner = Owner;
|
||||
c.Depth = Depth + 1;
|
||||
Children[cind] = c;
|
||||
}
|
||||
c.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var c = Children[i];
|
||||
if (c != null)
|
||||
{
|
||||
c.TrySplit(threshold);
|
||||
}
|
||||
}
|
||||
|
||||
Items = newItems;
|
||||
}
|
||||
|
||||
public void GetItems(ref Vector3 p, List<MapDataStoreNode> items)
|
||||
{
|
||||
if ((p.X >= BBMin.X) && (p.X <= BBMax.X) && (p.Y >= BBMin.Y) && (p.Y <= BBMax.Y))
|
||||
{
|
||||
if (Items != null)
|
||||
{
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
var item = Items[i];
|
||||
var imin = item.streamingExtentsMin;
|
||||
var imax = item.streamingExtentsMax;
|
||||
if ((p.X >= imin.X) && (p.X <= imax.X) && (p.Y >= imin.Y) && (p.Y <= imax.Y))
|
||||
{
|
||||
items.Add(item);
|
||||
item.GetVisibleChildren(ref p, items);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Children != null)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var c = Children[i];
|
||||
if (c != null)
|
||||
{
|
||||
c.GetItems(ref p, items);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SpaceBoundsStore
|
||||
{
|
||||
public SpaceBoundsStoreNode RootNode;
|
||||
public int SplitThreshold = 10;
|
||||
|
||||
public List<BoundsStoreItem> VisibleItems = new List<BoundsStoreItem>();
|
||||
|
||||
public void Init(List<BoundsStoreItem> items)
|
||||
{
|
||||
RootNode = new SpaceBoundsStoreNode();
|
||||
RootNode.Owner = this;
|
||||
foreach (var item in items)
|
||||
{
|
||||
RootNode.Add(item);
|
||||
}
|
||||
RootNode.TrySplit(SplitThreshold);
|
||||
}
|
||||
|
||||
public List<BoundsStoreItem> GetItems(ref Vector3 min, ref Vector3 max)
|
||||
{
|
||||
VisibleItems.Clear();
|
||||
|
||||
if (RootNode != null)
|
||||
{
|
||||
RootNode.GetItems(ref min, ref max, VisibleItems);
|
||||
}
|
||||
|
||||
return VisibleItems;
|
||||
}
|
||||
public List<BoundsStoreItem> GetItems(ref Ray ray)
|
||||
{
|
||||
VisibleItems.Clear();
|
||||
|
||||
if (RootNode != null)
|
||||
{
|
||||
RootNode.GetItems(ref ray, VisibleItems);
|
||||
}
|
||||
|
||||
return VisibleItems;
|
||||
}
|
||||
}
|
||||
public class SpaceBoundsStoreNode
|
||||
{
|
||||
public SpaceBoundsStore Owner = null;
|
||||
public SpaceBoundsStoreNode[] Children = null;
|
||||
public List<BoundsStoreItem> Items = null;
|
||||
public Vector3 BBMin = new Vector3(float.MaxValue);
|
||||
public Vector3 BBMax = new Vector3(float.MinValue);
|
||||
public int Depth = 0;
|
||||
|
||||
public void Add(BoundsStoreItem item)
|
||||
{
|
||||
if (Items == null)
|
||||
{
|
||||
Items = new List<BoundsStoreItem>();
|
||||
}
|
||||
BBMin = Vector3.Min(BBMin, item.Min);
|
||||
BBMax = Vector3.Max(BBMax, item.Max);
|
||||
Items.Add(item);
|
||||
}
|
||||
|
||||
public void TrySplit(int threshold)
|
||||
{
|
||||
if ((Items == null) || (Items.Count <= threshold))
|
||||
{ return; }
|
||||
|
||||
Children = new SpaceBoundsStoreNode[4];
|
||||
|
||||
var newItems = new List<BoundsStoreItem>();
|
||||
|
||||
var ncen = (BBMax + BBMin) * 0.5f;
|
||||
var next = (BBMax - BBMin) * 0.5f;
|
||||
var nsiz = Math.Max(next.X, next.Y);
|
||||
var nsizh = nsiz * 0.5f;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var imin = item.Min;
|
||||
var imax = item.Max;
|
||||
var icen = (imax + imin) * 0.5f;
|
||||
var iext = (imax - imin) * 0.5f;
|
||||
var isiz = Math.Max(iext.X, iext.Y);
|
||||
|
||||
if (isiz >= nsizh)
|
||||
{
|
||||
newItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
var cind = ((icen.X > ncen.X) ? 1 : 0) + ((icen.Y > ncen.Y) ? 2 : 0);
|
||||
var c = Children[cind];
|
||||
if (c == null)
|
||||
{
|
||||
c = new SpaceBoundsStoreNode();
|
||||
c.Owner = Owner;
|
||||
c.Depth = Depth + 1;
|
||||
Children[cind] = c;
|
||||
}
|
||||
c.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var c = Children[i];
|
||||
if (c != null)
|
||||
{
|
||||
c.TrySplit(threshold);
|
||||
}
|
||||
}
|
||||
|
||||
Items = newItems;
|
||||
}
|
||||
|
||||
public void GetItems(ref Vector3 min, ref Vector3 max, List<BoundsStoreItem> items)
|
||||
{
|
||||
if ((max.X >= BBMin.X) && (min.X <= BBMax.X) && (max.Y >= BBMin.Y) && (min.Y <= BBMax.Y))
|
||||
{
|
||||
if (Items != null)
|
||||
{
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
var item = Items[i];
|
||||
if ((max.X >= item.Min.X) && (min.X <= item.Max.X) && (max.Y >= item.Min.Y) && (min.Y <= item.Max.Y))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Children != null)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var c = Children[i];
|
||||
if (c != null)
|
||||
{
|
||||
c.GetItems(ref min, ref max, items);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void GetItems(ref Ray ray, List<BoundsStoreItem> items)
|
||||
{
|
||||
var box = new BoundingBox(BBMin, BBMax);
|
||||
if (ray.Intersects(ref box))
|
||||
{
|
||||
if (Items != null)
|
||||
{
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
var item = Items[i];
|
||||
box = new BoundingBox(item.Min, item.Max);
|
||||
if (ray.Intersects(box))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Children != null)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var c = Children[i];
|
||||
if (c != null)
|
||||
{
|
||||
c.GetItems(ref ray, items);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SpaceNodeGrid
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ namespace CodeWalker.World
|
||||
Yft = gfc.GetYft(ModelHash);
|
||||
while ((Yft != null) && (!Yft.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Yft = gfc.GetYft(ModelHash);
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ namespace CodeWalker.World
|
||||
ConvRoofDict = gfc.GetYcd(ycdhash);
|
||||
while ((ConvRoofDict != null) && (!ConvRoofDict.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
ConvRoofDict = gfc.GetYcd(ycdhash);
|
||||
}
|
||||
ClipMapEntry cme = null;
|
||||
|
@ -46,7 +46,7 @@ namespace CodeWalker.World
|
||||
|
||||
while ((Ydr != null) && (!Ydr.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
Ydr = gfc.GetYdr(useHash);
|
||||
}
|
||||
|
||||
|
@ -800,7 +800,7 @@ namespace CodeWalker.Forms
|
||||
var ycd = gameFileCache.GetYcd(ycdhash);
|
||||
while ((ycd != null) && (!ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
ycd = gameFileCache.GetYcd(ycdhash);
|
||||
}
|
||||
|
||||
|
@ -826,7 +826,7 @@ namespace CodeWalker.Peds
|
||||
var ycd = GameFileCache.GetYcd(ycdhash);
|
||||
while ((ycd != null) && (!ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
ycd = GameFileCache.GetYcd(ycdhash);
|
||||
}
|
||||
|
||||
|
@ -82,8 +82,6 @@ namespace CodeWalker.Project.Panels
|
||||
float density = 0.5f; //distance between vertices for the initial grid
|
||||
//float clipdz = 0.5f; //any polygons with greater steepness should be removed
|
||||
|
||||
Vector2I imin = space.Grid.GetCellPos(new Vector3(min, 0));
|
||||
Vector2I imax = space.Grid.GetCellPos(new Vector3(max, 0));
|
||||
|
||||
//Vector2 vertexCounts = (max - min) / density;
|
||||
//int vertexCountX = (int)vertexCounts.X;
|
||||
@ -113,30 +111,22 @@ namespace CodeWalker.Project.Panels
|
||||
|
||||
var polys = new List<GenPoly>();
|
||||
|
||||
for (int x = imin.X; x <= imax.X; x++) //generate verts for each world cell
|
||||
{
|
||||
for (int y = imin.Y; y <= imax.Y; y++)
|
||||
{
|
||||
Vector2I gi = new Vector2I(x, y);
|
||||
var cell = space.Grid.GetCell(gi);
|
||||
var cellstr = gi.ToString();
|
||||
var cellmin = space.Grid.GetWorldPos(gi);
|
||||
var cellmax = cellmin + SpaceGrid.CellSize;
|
||||
var vertexCountXY = (cellmax - cellmin) / density;
|
||||
var vertexCountXY = (max - min) / density;
|
||||
int vertexCountX = (int)vertexCountXY.X+1;
|
||||
int vertexCountY = (int)vertexCountXY.Y+1;
|
||||
//int vertexCountTot = vertexCountX * vertexCountY;
|
||||
vgrid.BeginGrid(vertexCountX, vertexCountY);
|
||||
cellmin.Z = 0.0f;//min probably not needed here
|
||||
cellmax.Z = 0.0f;
|
||||
|
||||
Ray ray = new Ray(Vector3.Zero, new Vector3(0, 0, -1));//for casting with
|
||||
|
||||
UpdateStatus("Loading cell " + cellstr + " ...");
|
||||
UpdateStatus("Loading YBNs...");
|
||||
|
||||
//pre-warm the bounds cache for this cell, and find the min/max Z
|
||||
if (cell.BoundsList != null)
|
||||
{
|
||||
foreach (var boundsitem in cell.BoundsList)
|
||||
var bmin = new Vector3(min, 0);
|
||||
var bmax = new Vector3(max, 0);
|
||||
var boundslist = space.BoundsStore.GetItems(ref bmin, ref bmax);
|
||||
|
||||
//pre-warm the bounds cache for this area, and find the min/max Z
|
||||
foreach (var boundsitem in boundslist)
|
||||
{
|
||||
YbnFile ybn = gameFileCache.GetYbn(boundsitem.Name);
|
||||
if (ybn == null)
|
||||
@ -160,9 +150,8 @@ namespace CodeWalker.Project.Panels
|
||||
}
|
||||
if (ybn.Loaded && (ybn.Bounds != null))
|
||||
{
|
||||
cellmin.Z = Math.Min(cellmin.Z, ybn.Bounds.BoundingBoxMin.Z);
|
||||
cellmax.Z = Math.Max(cellmax.Z, ybn.Bounds.BoundingBoxMax.Z);
|
||||
}
|
||||
bmin.Z = Math.Min(bmin.Z, ybn.Bounds.BoundingBoxMin.Z);
|
||||
bmax.Z = Math.Max(bmax.Z, ybn.Bounds.BoundingBoxMax.Z);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +160,7 @@ namespace CodeWalker.Project.Panels
|
||||
//ray-cast each XY vertex position, and find the height and surface from ybn's
|
||||
//continue casting down to find more surfaces...
|
||||
|
||||
UpdateStatus("Processing cell " + cellstr + " ...");
|
||||
UpdateStatus("Processing...");
|
||||
|
||||
for (int vx = 0; vx < vertexCountX; vx++)
|
||||
{
|
||||
@ -179,8 +168,8 @@ namespace CodeWalker.Project.Panels
|
||||
{
|
||||
vgrid.BeginCell(vx, vy);
|
||||
var vcoffset = new Vector3(vx, vy, 0) * density;
|
||||
ray.Position = cellmin + vcoffset;
|
||||
ray.Position.Z = cellmax.Z + 1.0f;//start the ray at the top of the cell
|
||||
ray.Position = bmin + vcoffset;
|
||||
ray.Position.Z = bmax.Z + 1.0f;//start the ray at the top of the cell
|
||||
var intres = space.RayIntersect(ray, float.MaxValue, layers);
|
||||
hitTestCount++;
|
||||
while (intres.Hit)// && (intres.HitDist > 0))
|
||||
@ -229,8 +218,20 @@ namespace CodeWalker.Project.Panels
|
||||
newCount += genPolys.Count;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//try merge generated polys into bigger ones, while keeping convex!
|
||||
|
@ -381,7 +381,7 @@ namespace CodeWalker.World
|
||||
var ycd = GameFileCache.GetYcd(ycdhash);
|
||||
while ((ycd != null) && (!ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//bite me
|
||||
Thread.Sleep(1);//bite me
|
||||
ycd = GameFileCache.GetYcd(ycdhash);
|
||||
}
|
||||
if (ycd != null)
|
||||
|
@ -2213,7 +2213,7 @@ namespace CodeWalker
|
||||
public SpaceRayIntersectResult GetSpaceMouseRay()
|
||||
{
|
||||
SpaceRayIntersectResult ret = new SpaceRayIntersectResult();
|
||||
if (space.Inited && space.Grid != null)
|
||||
if (space.Inited && space.BoundsStore != null)
|
||||
{
|
||||
Ray mray = new Ray();
|
||||
mray.Position = camera.MouseRay.Position + camera.Position;
|
||||
|
Loading…
Reference in New Issue
Block a user