mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2025-01-25 15:02:56 +08:00
Experimental new resource packing
This commit is contained in:
parent
211764c0f9
commit
d63bc6e12b
@ -20,86 +20,166 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
var systemBlocks = new HashSet<IResourceBlock>();
|
var systemBlocks = new HashSet<IResourceBlock>();
|
||||||
var graphicBlocks = new HashSet<IResourceBlock>();
|
var graphicBlocks = new HashSet<IResourceBlock>();
|
||||||
var protectedBlocks = new List<IResourceBlock>();
|
|
||||||
|
|
||||||
var stack = new Stack<IResourceBlock>();
|
|
||||||
stack.Push(rootBlock);
|
|
||||||
|
|
||||||
var processed = new HashSet<IResourceBlock>();
|
var processed = new HashSet<IResourceBlock>();
|
||||||
processed.Add(rootBlock);
|
|
||||||
|
|
||||||
while (stack.Count > 0)
|
|
||||||
|
|
||||||
|
//var protectedBlocks = new List<IResourceBlock>();
|
||||||
|
//var stack = new Stack<IResourceBlock>();
|
||||||
|
//stack.Push(rootBlock);
|
||||||
|
//processed.Add(rootBlock);
|
||||||
|
//while (stack.Count > 0)
|
||||||
|
//{
|
||||||
|
// var block = stack.Pop();
|
||||||
|
// if (block == null)
|
||||||
|
// continue;
|
||||||
|
// if (block is IResourceSystemBlock)
|
||||||
|
// {
|
||||||
|
// if (!systemBlocks.Contains(block))
|
||||||
|
// systemBlocks.Add(block);
|
||||||
|
// // for system blocks, also process references...
|
||||||
|
// var references = ((IResourceSystemBlock)block).GetReferences();
|
||||||
|
// //Array.Reverse(references);
|
||||||
|
// foreach (var reference in references)
|
||||||
|
// if (!processed.Contains(reference))
|
||||||
|
// {
|
||||||
|
// stack.Push(reference);
|
||||||
|
// processed.Add(reference);
|
||||||
|
// }
|
||||||
|
// var subs = new Stack<IResourceSystemBlock>();
|
||||||
|
// foreach (var part in ((IResourceSystemBlock)block).GetParts())
|
||||||
|
// subs.Push((IResourceSystemBlock)part.Item2);
|
||||||
|
// while (subs.Count > 0)
|
||||||
|
// {
|
||||||
|
// var sub = subs.Pop();
|
||||||
|
// foreach (var x in sub.GetReferences())
|
||||||
|
// if (!processed.Contains(x))
|
||||||
|
// {
|
||||||
|
// stack.Push(x);
|
||||||
|
// processed.Add(x);
|
||||||
|
// }
|
||||||
|
// foreach (var x in sub.GetParts())
|
||||||
|
// subs.Push((IResourceSystemBlock)x.Item2);
|
||||||
|
// protectedBlocks.Add(sub);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (!graphicBlocks.Contains(block))
|
||||||
|
// graphicBlocks.Add(block);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//// there are now sys-blocks in the list that actually
|
||||||
|
//// only substructures and therefore must not get
|
||||||
|
//// a new position!
|
||||||
|
//// -> remove them from the list
|
||||||
|
//foreach (var q in protectedBlocks)
|
||||||
|
// if (systemBlocks.Contains(q))
|
||||||
|
// systemBlocks.Remove(q);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void addBlock(IResourceBlock block)
|
||||||
{
|
{
|
||||||
var block = stack.Pop();
|
|
||||||
if (block == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (block is IResourceSystemBlock)
|
if (block is IResourceSystemBlock)
|
||||||
{
|
{
|
||||||
if (!systemBlocks.Contains(block))
|
if (!systemBlocks.Contains(block)) systemBlocks.Add(block);
|
||||||
systemBlocks.Add(block);
|
}
|
||||||
|
else if(block is IResourceGraphicsBlock)
|
||||||
// for system blocks, also process references...
|
{
|
||||||
|
if (!graphicBlocks.Contains(block)) graphicBlocks.Add(block);
|
||||||
var references = ((IResourceSystemBlock)block).GetReferences();
|
}
|
||||||
//Array.Reverse(references);
|
}
|
||||||
|
void addChildren(IResourceBlock block)
|
||||||
|
{
|
||||||
|
if (block is IResourceSystemBlock sblock)
|
||||||
|
{
|
||||||
|
var references = sblock.GetReferences();
|
||||||
foreach (var reference in references)
|
foreach (var reference in references)
|
||||||
|
{
|
||||||
if (!processed.Contains(reference))
|
if (!processed.Contains(reference))
|
||||||
{
|
{
|
||||||
stack.Push(reference);
|
|
||||||
processed.Add(reference);
|
processed.Add(reference);
|
||||||
|
addBlock(reference);
|
||||||
|
addChildren(reference);
|
||||||
}
|
}
|
||||||
var subs = new Stack<IResourceSystemBlock>();
|
|
||||||
foreach (var part in ((IResourceSystemBlock)block).GetParts())
|
|
||||||
subs.Push((IResourceSystemBlock)part.Item2);
|
|
||||||
while (subs.Count > 0)
|
|
||||||
{
|
|
||||||
var sub = subs.Pop();
|
|
||||||
|
|
||||||
foreach (var x in sub.GetReferences())
|
|
||||||
if (!processed.Contains(x))
|
|
||||||
{
|
|
||||||
stack.Push(x);
|
|
||||||
processed.Add(x);
|
|
||||||
}
|
|
||||||
foreach (var x in sub.GetParts())
|
|
||||||
subs.Push((IResourceSystemBlock)x.Item2);
|
|
||||||
|
|
||||||
protectedBlocks.Add(sub);
|
|
||||||
}
|
}
|
||||||
|
var parts = sblock.GetParts();
|
||||||
}
|
foreach (var part in parts)
|
||||||
else
|
{
|
||||||
{
|
addChildren(part.Item2);
|
||||||
if (!graphicBlocks.Contains(block))
|
}
|
||||||
graphicBlocks.Add(block);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//var result = new List<IResourceBlock>();
|
addBlock(rootBlock);
|
||||||
//result.AddRange(systemBlocks);
|
addChildren(rootBlock);
|
||||||
//result.AddRange(graphicBlocks);
|
|
||||||
//return result;
|
|
||||||
|
|
||||||
// there are now sys-blocks in the list that actually
|
|
||||||
// only substructures and therefore must not get
|
|
||||||
// a new position!
|
|
||||||
// -> remove them from the list
|
|
||||||
foreach (var q in protectedBlocks)
|
|
||||||
if (systemBlocks.Contains(q))
|
|
||||||
systemBlocks.Remove(q);
|
|
||||||
|
|
||||||
|
|
||||||
sys = new List<IResourceBlock>();
|
sys = new List<IResourceBlock>();
|
||||||
foreach (var s in systemBlocks)
|
foreach (var s in systemBlocks)
|
||||||
|
{
|
||||||
sys.Add(s);
|
sys.Add(s);
|
||||||
|
}
|
||||||
gfx = new List<IResourceBlock>();
|
gfx = new List<IResourceBlock>();
|
||||||
foreach (var s in graphicBlocks)
|
foreach (var s in graphicBlocks)
|
||||||
|
{
|
||||||
gfx.Add(s);
|
gfx.Add(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AssignPositions(IList<IResourceBlock> blocks, uint basePosition, ref int pageSize, out int pageCount)
|
public static void AssignPositions(IList<IResourceBlock> blocks, uint basePosition, ref int pageSize, out int pageCount)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
IResourceBlock getFirstBlock()
|
||||||
|
{
|
||||||
|
if (blocks.Count > 0)
|
||||||
|
{
|
||||||
|
return blocks[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HashSet<IResourceBlock> getBlockSet()
|
||||||
|
{
|
||||||
|
var blockset = new HashSet<IResourceBlock>();
|
||||||
|
for (int i = 1; i < blocks.Count; i++)
|
||||||
|
{
|
||||||
|
blockset.Add(blocks[i]);
|
||||||
|
}
|
||||||
|
return blockset;
|
||||||
|
}
|
||||||
|
IResourceBlock takeBestBlock(long maxSize, HashSet<IResourceBlock> blockset)
|
||||||
|
{
|
||||||
|
if (maxSize <= 0) return null;
|
||||||
|
IResourceBlock r = null;
|
||||||
|
long rlen = 0;
|
||||||
|
foreach (var block in blockset)
|
||||||
|
{
|
||||||
|
var blockLength = block.BlockLength;
|
||||||
|
if ((blockLength <= maxSize) && (blockLength > rlen))
|
||||||
|
{
|
||||||
|
r = block;
|
||||||
|
rlen = blockLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r != null)
|
||||||
|
{
|
||||||
|
blockset.Remove(r);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// find largest structure
|
// find largest structure
|
||||||
long largestBlockSize = 0;
|
long largestBlockSize = 0;
|
||||||
foreach (var block in blocks)
|
foreach (var block in blocks)
|
||||||
@ -113,42 +193,77 @@ namespace CodeWalker.GameFiles
|
|||||||
while (currentPageSize < largestBlockSize)
|
while (currentPageSize < largestBlockSize)
|
||||||
currentPageSize *= 2;
|
currentPageSize *= 2;
|
||||||
|
|
||||||
long currentPageCount;
|
long currentPageCount = 0;
|
||||||
long currentPosition;
|
long currentPosition = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
currentPageCount = 0;
|
if (blocks.Count == 0) break;
|
||||||
currentPosition = 0;
|
|
||||||
|
|
||||||
// reset all positions
|
// reset all positions
|
||||||
foreach (var block in blocks)
|
foreach (var block in blocks)
|
||||||
block.FilePosition = -1;
|
block.FilePosition = -1;
|
||||||
|
|
||||||
foreach (var block in blocks)
|
//currentPageCount = 0;
|
||||||
|
//currentPosition = 0;
|
||||||
|
//foreach (var block in blocks)
|
||||||
|
//{
|
||||||
|
// //if (block.FilePosition != -1)
|
||||||
|
// // throw new Exception("Block was already assigned a position!");
|
||||||
|
// //if (block.Length == 0)
|
||||||
|
// // throw new Exception("A length of 0 is not allowed!");
|
||||||
|
//
|
||||||
|
// // check if new page is necessary...
|
||||||
|
// // if yes, add a new page and align to it
|
||||||
|
// long maxSpace = currentPageCount * currentPageSize - currentPosition;
|
||||||
|
// if (maxSpace < (block.BlockLength + SKIP_SIZE))
|
||||||
|
// {
|
||||||
|
// currentPageCount++;
|
||||||
|
// currentPosition = currentPageSize * (currentPageCount - 1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // set position
|
||||||
|
// block.FilePosition = basePosition + currentPosition;
|
||||||
|
// currentPosition += block.BlockLength + SKIP_SIZE;
|
||||||
|
//
|
||||||
|
// // align...
|
||||||
|
// if ((currentPosition % ALIGN_SIZE) != 0)
|
||||||
|
// currentPosition += (ALIGN_SIZE - (currentPosition % ALIGN_SIZE));
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
currentPageCount = 1;
|
||||||
|
currentPosition = 0;
|
||||||
|
var blockset = getBlockSet();
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
if (block.FilePosition != -1)
|
var maxSize = currentPageCount * currentPageSize - currentPosition;
|
||||||
throw new Exception("Block was already assigned a position!");
|
var isroot = (currentPosition == 0);
|
||||||
//if (block.Length == 0)
|
var block = isroot ? getFirstBlock() : takeBestBlock(maxSize, blockset);
|
||||||
// throw new Exception("A length of 0 is not allowed!");
|
if (block != null)
|
||||||
|
|
||||||
// check if new page is necessary...
|
|
||||||
// if yes, add a new page and align to it
|
|
||||||
long maxSpace = currentPageCount * currentPageSize - currentPosition;
|
|
||||||
if (maxSpace < (block.BlockLength + SKIP_SIZE))
|
|
||||||
{
|
{
|
||||||
currentPageCount++;
|
block.FilePosition = basePosition + currentPosition;
|
||||||
currentPosition = currentPageSize * (currentPageCount - 1);
|
|
||||||
|
currentPosition += block.BlockLength;
|
||||||
|
|
||||||
|
if ((currentPosition % ALIGN_SIZE) != 0)
|
||||||
|
{
|
||||||
|
currentPosition += (ALIGN_SIZE - (currentPosition % ALIGN_SIZE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (blockset.Count > 0)
|
||||||
|
{
|
||||||
|
currentPosition = currentPageSize * currentPageCount;
|
||||||
|
currentPageCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set position
|
|
||||||
block.FilePosition = basePosition + currentPosition;
|
|
||||||
currentPosition += block.BlockLength + SKIP_SIZE;
|
|
||||||
|
|
||||||
// align...
|
|
||||||
if ((currentPosition % ALIGN_SIZE) != 0)
|
|
||||||
currentPosition += (ALIGN_SIZE - (currentPosition % ALIGN_SIZE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// break if everything fits...
|
// break if everything fits...
|
||||||
if (currentPageCount < 128)
|
if (currentPageCount < 128)
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user