Skip to content

Commit be73ea2

Browse files
committed
Experimental resource packing improvements
1 parent 213f734 commit be73ea2

File tree

1 file changed

+184
-12
lines changed

1 file changed

+184
-12
lines changed

CodeWalker.Core/GameFiles/Resources/ResourceBuilder.cs

+184-12
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,169 @@ IResourceBlock takeBestBlock(long maxSize, HashSet<IResourceBlock> blockset)
275275
pageCount = (int)currentPageCount;
276276
}
277277

278+
public static void AssignPositions(IList<IResourceBlock> blocks, uint basePosition, out RpfResourcePageFlags pageFlags)
279+
{
280+
var sys = (basePosition == 0x50000000);
281+
282+
IResourceBlock getRootBlock()
283+
{
284+
if (sys && (blocks.Count > 0))
285+
{
286+
return blocks[0];
287+
}
288+
return null;
289+
}
290+
HashSet<IResourceBlock> getBlockSet()
291+
{
292+
var blockset = new HashSet<IResourceBlock>();
293+
int start = sys ? 1 : 0;
294+
for (int i = start; i < blocks.Count; i++)
295+
{
296+
blockset.Add(blocks[i]);
297+
}
298+
return blockset;
299+
}
300+
IResourceBlock findBestBlock(long maxSize, HashSet<IResourceBlock> blockset)
301+
{
302+
if (maxSize <= 0) return null;
303+
IResourceBlock r = null;
304+
long rlen = 0;
305+
foreach (var block in blockset)
306+
{
307+
var blockLength = block.BlockLength;
308+
if ((blockLength <= maxSize) && (blockLength > rlen))
309+
{
310+
r = block;
311+
rlen = blockLength;
312+
}
313+
}
314+
return r;
315+
}
316+
IResourceBlock takeBestBlock(long maxSize, HashSet<IResourceBlock> blockset)
317+
{
318+
var r = findBestBlock(maxSize, blockset);
319+
if (r != null)
320+
{
321+
blockset.Remove(r);
322+
}
323+
return r;
324+
}
325+
long pad(long p)
326+
{
327+
return ((ALIGN_SIZE - (p % ALIGN_SIZE)) % ALIGN_SIZE);
328+
}
329+
330+
331+
long largestBlockSize = 0; // find largest structure
332+
long startPageSize = BASE_SIZE;// 0x2000; // find starting page size
333+
long totalBlockSize = 0;
334+
foreach (var block in blocks)
335+
{
336+
var blockLength = block.BlockLength;
337+
totalBlockSize += blockLength;
338+
totalBlockSize += pad(totalBlockSize);
339+
if (largestBlockSize < blockLength)
340+
{
341+
largestBlockSize = blockLength;
342+
}
343+
}
344+
while (startPageSize < largestBlockSize)
345+
{
346+
startPageSize *= 2;
347+
}
348+
349+
350+
pageFlags = new RpfResourcePageFlags();
351+
352+
while (true)
353+
{
354+
if (blocks.Count == 0) break;
355+
356+
var currentPosition = 0L;
357+
var currentPageSize = startPageSize;
358+
var currentPageStart = 0L;
359+
var currentPageSpace = startPageSize;
360+
var currentRemainder = totalBlockSize;
361+
var rootblock = getRootBlock();
362+
var blockset = getBlockSet();
363+
364+
var pageCount = 1;
365+
var pageCounts = new uint[9];
366+
var pageCountIndex = 0;
367+
var targetPageSize = Math.Max(65536, startPageSize >> 5);
368+
var minPageSize = Math.Max(512, Math.Min(targetPageSize, startPageSize) >> 4);
369+
var baseShift = 0u;
370+
var baseSize = 512;
371+
while (baseSize < minPageSize)
372+
{
373+
baseShift++;
374+
baseSize *= 2;
375+
if (baseShift >= 0xF) break;
376+
}
377+
var baseSizeMax = baseSize << 8;
378+
var baseSizeMaxTest = startPageSize;
379+
while (baseSizeMaxTest < baseSizeMax)
380+
{
381+
pageCountIndex++;
382+
baseSizeMaxTest *= 2;
383+
}
384+
pageCounts[pageCountIndex] = 1;
385+
386+
while (true)
387+
{
388+
var isroot = sys && (currentPosition == 0);
389+
var block = isroot ? rootblock : takeBestBlock(currentPageSpace, blockset);
390+
var blockLength = block?.BlockLength ?? 0;
391+
if (block != null)
392+
{
393+
//add this block to the current page.
394+
block.FilePosition = basePosition + currentPosition;
395+
var opos = currentPosition;
396+
currentPosition += blockLength;
397+
currentPosition += pad(currentPosition);
398+
var usedspace = currentPosition - opos;
399+
currentPageSpace -= usedspace;
400+
currentRemainder -= usedspace;//blockLength;//
401+
402+
}
403+
else if (blockset.Count > 0)
404+
{
405+
//allocate a new page
406+
currentPageStart += currentPageSize;
407+
currentPosition = currentPageStart;
408+
block = findBestBlock(long.MaxValue, blockset);//just find the biggest block
409+
blockLength = block?.BlockLength ?? 0;
410+
while (blockLength <= (currentPageSize >> 1))//determine best new page size
411+
{
412+
if (currentPageSize <= minPageSize) break;
413+
if (pageCountIndex >= 8) break;
414+
if ((currentPageSize <= targetPageSize) && (currentRemainder >= (currentPageSize - minPageSize))) break;
415+
416+
currentPageSize = currentPageSize >> 1;
417+
pageCountIndex++;
418+
}
419+
currentPageSpace = currentPageSize;
420+
pageCounts[pageCountIndex]++;
421+
pageCount++;
422+
}
423+
else
424+
{
425+
break;
426+
}
427+
}
428+
429+
430+
pageFlags = new RpfResourcePageFlags(pageCounts, baseShift);
431+
432+
if ((pageCount == pageFlags.Count) && (pageFlags.Size >= currentPosition)) //make sure page counts fit in the flags value
433+
{
434+
break;
435+
}
436+
437+
startPageSize *= 2;
438+
}
439+
440+
}
278441

279442

280443
public static byte[] Build(ResourceFileBase fileBase, int version, bool compress = true)
@@ -286,22 +449,29 @@ public static byte[] Build(ResourceFileBase fileBase, int version, bool compress
286449
IList<IResourceBlock> graphicBlocks;
287450
GetBlocks(fileBase, out systemBlocks, out graphicBlocks);
288451

289-
int systemPageSize = BASE_SIZE;// *4;
290-
int systemPageCount;
291-
AssignPositions(systemBlocks, 0x50000000, ref systemPageSize, out systemPageCount);
452+
//int systemPageSize = BASE_SIZE;// *4;
453+
//int systemPageCount;
454+
//AssignPositions(systemBlocks, 0x50000000, ref systemPageSize, out systemPageCount);
455+
456+
//int graphicsPageSize = BASE_SIZE;
457+
//int graphicsPageCount;
458+
//AssignPositions(graphicBlocks, 0x60000000, ref graphicsPageSize, out graphicsPageCount);
292459

293-
int graphicsPageSize = BASE_SIZE;
294-
int graphicsPageCount;
295-
AssignPositions(graphicBlocks, 0x60000000, ref graphicsPageSize, out graphicsPageCount);
460+
461+
RpfResourcePageFlags systemPageFlags;
462+
AssignPositions(systemBlocks, 0x50000000, out systemPageFlags);
463+
464+
RpfResourcePageFlags graphicsPageFlags;
465+
AssignPositions(graphicBlocks, 0x60000000, out graphicsPageFlags);
296466

297467

298468

299469

300470
//fileBase.FilePagesInfo.SystemPagesCount = 0;
301471
//if (systemPageCount > 0)
302472
// fileBase.FilePagesInfo.SystemPagesCount = 1; // (byte)systemPageCount; //1
303-
fileBase.FilePagesInfo.SystemPagesCount = (byte)systemPageCount;
304-
fileBase.FilePagesInfo.GraphicsPagesCount = (byte)graphicsPageCount;
473+
fileBase.FilePagesInfo.SystemPagesCount = (byte)systemPageFlags.Count;// systemPageCount;
474+
fileBase.FilePagesInfo.GraphicsPagesCount = (byte)graphicsPageFlags.Count;// graphicsPageCount;
305475

306476

307477

@@ -342,14 +512,14 @@ public static byte[] Build(ResourceFileBase fileBase, int version, bool compress
342512

343513

344514

345-
var sysDataSize = systemPageCount * systemPageSize;
515+
var sysDataSize = (int)systemPageFlags.Size;// systemPageCount * systemPageSize;
346516
var sysData = new byte[sysDataSize];
347517
systemStream.Flush();
348518
systemStream.Position = 0;
349519
systemStream.Read(sysData, 0, (int)systemStream.Length);
350520

351521

352-
var gfxDataSize = graphicsPageCount * graphicsPageSize;
522+
var gfxDataSize = (int)graphicsPageFlags.Size;// graphicsPageCount * graphicsPageSize;
353523
var gfxData = new byte[gfxDataSize];
354524
graphicsStream.Flush();
355525
graphicsStream.Position = 0;
@@ -363,9 +533,11 @@ public static byte[] Build(ResourceFileBase fileBase, int version, bool compress
363533

364534
//uint sf = RpfResourceFileEntry.GetFlagsFromSize(sysDataSize, sv);
365535
//uint gf = RpfResourceFileEntry.GetFlagsFromSize(gfxDataSize, gv); //TODO: might be broken...
536+
//uint sf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)systemPageCount, (uint)systemPageSize, sv);
537+
//uint gf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)graphicsPageCount, (uint)graphicsPageSize, gv);
538+
uint sf = systemPageFlags.Value + (sv << 28);
539+
uint gf = graphicsPageFlags.Value + (gv << 28);
366540

367-
uint sf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)systemPageCount, (uint)systemPageSize, sv);
368-
uint gf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)graphicsPageCount, (uint)graphicsPageSize, gv);
369541

370542
var tdatasize = sysDataSize + gfxDataSize;
371543
var tdata = new byte[tdatasize];

0 commit comments

Comments
 (0)