the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 1362 lines 44 kB view raw
1#include "stdafx.h" 2#include "CompressedTileStorage.h" 3 4#ifdef __PSVITA__ 5#define PSVITA_PRECOMPUTED_TABLE 6#endif 7 8#ifdef __PS3__ 9#include "..\SPU_Tasks\CompressedTileStorage_compress\CompressedTileStorage_compress.h" 10#include "C4JSpursJob.h" 11static const int sc_maxCompressTiles = 64; 12static CompressedTileStorage_compress_dataIn g_compressTileDataIn[sc_maxCompressTiles] __attribute__((__aligned__(16))); 13static int g_currentCompressTiles = 0; 14//#define DISABLE_SPU_CODE 15#endif //__PS3__ 16 17// Note: See header for an overview of this class 18 19int CompressedTileStorage::deleteQueueIndex; 20XLockFreeStack <unsigned char> CompressedTileStorage::deleteQueue[3]; 21 22CRITICAL_SECTION CompressedTileStorage::cs_write; 23 24#ifdef PSVITA_PRECOMPUTED_TABLE 25// AP - this will create a precomputed table to speed up getData 26static int *CompressedTile_StorageIndexTable = NULL; 27 28void CompressedTileStorage_InitTable() 29{ 30 if( CompressedTile_StorageIndexTable == NULL ) 31 { 32 CompressedTile_StorageIndexTable = (int*) malloc(sizeof(int) * 64); 33 for(int j = 0;j < 64;j += 1 ) 34 { 35 int index = ( ( j & 0x30 ) << 7) | ( ( j & 0x0c ) << 5 ) | ( j & 0x03 ); 36 CompressedTile_StorageIndexTable[j] = index; 37 } 38 } 39} 40#endif 41 42CompressedTileStorage::CompressedTileStorage() 43{ 44 indicesAndData = NULL; 45 allocatedSize = 0; 46 47#ifdef PSVITA_PRECOMPUTED_TABLE 48 CompressedTileStorage_InitTable(); 49#endif 50} 51 52CompressedTileStorage::CompressedTileStorage(CompressedTileStorage *copyFrom) 53{ 54 EnterCriticalSection(&cs_write); 55 allocatedSize = copyFrom->allocatedSize; 56 if(allocatedSize > 0) 57 { 58 indicesAndData = (unsigned char *)XPhysicalAlloc(allocatedSize, MAXULONG_PTR, 4096, PAGE_READWRITE);//(unsigned char *)malloc(allocatedSize); 59 XMemCpy(indicesAndData, copyFrom->indicesAndData, allocatedSize); 60 } 61 else 62 { 63 indicesAndData = NULL; 64 } 65 LeaveCriticalSection(&cs_write); 66 67#ifdef PSVITA_PRECOMPUTED_TABLE 68 CompressedTileStorage_InitTable(); 69#endif 70} 71 72CompressedTileStorage::CompressedTileStorage(byteArray initFrom, unsigned int initOffset) 73{ 74 indicesAndData = NULL; 75 allocatedSize = 0; 76 77 // We need 32768 bytes for a fully uncompressed chunk, plus 1024 for the index. Rounding up to nearest 4096 bytes for allocation 78 indicesAndData = (unsigned char *)XPhysicalAlloc(32768+4096, MAXULONG_PTR, 4096, PAGE_READWRITE); 79 80 unsigned short *indices = (unsigned short *)indicesAndData; 81 unsigned char *data = indicesAndData + 1024; 82 83 int offset = 0; 84 for( int i = 0; i < 512; i++ ) 85 { 86 indices[i] = INDEX_TYPE_0_OR_8_BIT | ( offset << 1 ); 87 88 if( initFrom.data ) 89 { 90 for( int j = 0; j < 64; j++ ) 91 { 92 *data++ = initFrom[getIndex(i,j) + initOffset]; 93 } 94 } 95 else 96 { 97 for( int j = 0; j < 64; j++ ) 98 { 99 *data++ = 0; 100 } 101 } 102 103 offset += 64; 104 } 105 106 allocatedSize = 32768 + 1024; // This is used for copying (see previous ctor), and as such it only needs to be the actual size of the data used rather than the one rounded up to a page size actually allocated 107 108#ifdef PSVITA_PRECOMPUTED_TABLE 109 CompressedTileStorage_InitTable(); 110#endif 111} 112 113bool CompressedTileStorage::isCompressed() 114{ 115 return allocatedSize != 32768 + 1024; 116} 117 118CompressedTileStorage::CompressedTileStorage(bool isEmpty) 119{ 120 indicesAndData = NULL; 121 allocatedSize = 0; 122 123 // Empty and already compressed, so we only need 1K. Rounding up to nearest 4096 bytes for allocation 124#ifdef __PS3__ 125 // XPhysicalAlloc just maps to malloc on PS3, so allocate the smallest amount 126 indicesAndData = (unsigned char *)XPhysicalAlloc(1024, MAXULONG_PTR, 4096, PAGE_READWRITE); 127#else 128 indicesAndData = (unsigned char *)XPhysicalAlloc(4096, MAXULONG_PTR, 4096, PAGE_READWRITE); 129#endif //__PS3__ 130 unsigned short *indices = (unsigned short *)indicesAndData; 131 //unsigned char *data = indicesAndData + 1024; 132 133 //int offset = 0; 134 for( int i = 0; i < 512; i++ ) 135 { 136 indices[i] = INDEX_TYPE_0_OR_8_BIT | INDEX_TYPE_0_BIT_FLAG; 137 } 138 139 allocatedSize = 1024; // This is used for copying (see previous ctor), and as such it only needs to be the actual size of the data used rather than the one rounded up to a page size actually allocated 140 141#ifdef PSVITA_PRECOMPUTED_TABLE 142 CompressedTileStorage_InitTable(); 143#endif 144} 145 146bool CompressedTileStorage::isRenderChunkEmpty(int y) // y == 0, 16, 32... 112 (representing a 16 byte range) 147{ 148 int block; 149 unsigned short *blockIndices = (unsigned short *)indicesAndData; 150 151 for( int x = 0; x < 16; x += 4 ) 152 for( int z = 0; z < 16; z += 4 ) 153 { 154 getBlock(&block, x, y, z); 155 __uint64 *comp = (__uint64 *)&blockIndices[block]; 156 // Are the 4 y regions stored here all zero? (INDEX_TYPE_0_OR_8_BIT | INDEX_TYPE_0_BIT_FLAG ) 157 if( ( *comp ) != 0x0007000700070007L ) return false; 158 } 159 return true; 160} 161 162bool CompressedTileStorage::isSameAs(CompressedTileStorage *other) 163{ 164 EnterCriticalSection(&cs_write); 165 if( allocatedSize != other->allocatedSize ) 166 { 167 LeaveCriticalSection(&cs_write); 168 return false; 169 } 170 171 // Attempt to compare as much as we can in 64-byte chunks (8 groups of 8 bytes) 172 int quickCount = allocatedSize / 64; 173 __int64 *pOld = (__int64 *)indicesAndData; 174 __int64 *pNew = (__int64 *)other->indicesAndData; 175 for( int i = 0; i < quickCount; i++ ) 176 { 177 __int64 d0 = pOld[0] ^ pNew[0]; 178 __int64 d1 = pOld[1] ^ pNew[1]; 179 __int64 d2 = pOld[2] ^ pNew[2]; 180 __int64 d3 = pOld[3] ^ pNew[3]; 181 __int64 d4 = pOld[4] ^ pNew[4]; 182 __int64 d5 = pOld[5] ^ pNew[5]; 183 __int64 d6 = pOld[6] ^ pNew[6]; 184 __int64 d7 = pOld[7] ^ pNew[7]; 185 d0 |= d1; 186 d2 |= d3; 187 d4 |= d5; 188 d6 |= d7; 189 d0 |= d2; 190 d4 |= d6; 191 if( d0 | d4 ) 192 { 193 LeaveCriticalSection(&cs_write); 194 return false; 195 } 196 pOld += 8; 197 pNew += 8; 198 } 199 200 // Now test anything remaining just byte at a time 201 unsigned char *pucOld = (unsigned char *)pOld; 202 unsigned char *pucNew = (unsigned char *)pNew; 203 for( int i = 0; i < allocatedSize - (quickCount * 64); i++ ) 204 { 205 if( *pucOld++ != *pucNew++ ) 206 { 207 LeaveCriticalSection(&cs_write); 208 return false; 209 } 210 } 211 212 LeaveCriticalSection(&cs_write); 213 return true; 214} 215 216CompressedTileStorage::~CompressedTileStorage() 217{ 218#if 1 219 if(indicesAndData) XPhysicalFree(indicesAndData); 220#else 221 if( (unsigned int)indicesAndData >= MM_PHYSICAL_4KB_BASE ) 222 { 223 if(indicesAndData) XPhysicalFree(indicesAndData); 224 } 225 else 226 { 227 if(indicesAndData) free(indicesAndData); 228 } 229#endif 230} 231 232// Get an index into the normal ordering of tiles for the java game, given a block index (0 to 511) and a tile index (0 to 63) 233inline int CompressedTileStorage::getIndex(int block, int tile) 234{ 235 // bits for index into data is: xxxxzzzzyyyyyyy 236 // we want block(b) & tile(t) spread out as: 237 // from: ______bbbbbbbbb 238 // to: bb__bb__bbbbb__ 239 // 240 // from: _________tttttt 241 // to: __tt__tt_____tt 242 243 int index = ( ( block & 0x180) << 6 ) | ( ( block & 0x060 ) << 4 ) | ( ( block & 0x01f ) << 2 ); 244 index |= ( ( tile & 0x30 ) << 7) | ( ( tile & 0x0c ) << 5 ) | ( tile & 0x03 ); 245 246 return index; 247} 248 249// Get the block and tile (reversing getIndex above) for a given x, y, z coordinate 250// 251// bits for index into data is: xxxxzzzzyyyyyyy 252// bbttbbttbbbbbtt 253// 254// so x is: ___________xxxx 255// and maps to this bit of b ______bb_______ 256// and this bit of t _________tt____ 257// 258// y is: ________yyyyyyy 259// and maps to this bit of b __________bbbbb 260// and this bit of t _____________tt 261// 262// and z is: ___________zzzz 263// and maps to this bit of b ________bb_____ 264// and this bit of t ___________tt__ 265// 266 267inline void CompressedTileStorage::getBlockAndTile(int *block, int *tile, int x, int y, int z) 268{ 269 *block = ( ( x & 0x0c ) << 5 ) | ( ( z & 0x0c ) << 3 ) | ( y >> 2 ); 270 *tile = ( ( x & 0x03 ) << 4 ) | ( ( z & 0x03 ) << 2 ) | ( y & 0x03 ); 271} 272 273inline void CompressedTileStorage::getBlock(int *block, int x, int y, int z) 274{ 275 *block = ( ( x & 0x0c ) << 5 ) | ( ( z & 0x0c ) << 3 ) | ( y >> 2 ); 276} 277 278// Set all tile values from a data array of length 32768 (128 x 16 x 16). 279void CompressedTileStorage::setData(byteArray dataIn, unsigned int inOffset) 280{ 281 unsigned short _blockIndices[512]; 282 283 EnterCriticalSection(&cs_write); 284 unsigned char *data = dataIn.data + inOffset; 285 286 // Is the destination fully uncompressed? If so just write our data in - this happens when writing schematics and we don't want this setting of data to trigger compression 287 if( allocatedSize == ( 32768 + 1024 ) ) 288 { 289 //unsigned short *indices = (unsigned short *)indicesAndData; 290 unsigned char *dataOut = indicesAndData + 1024; 291 292 for( int i = 0; i < 512; i++ ) 293 { 294 for( int j = 0; j < 64; j++ ) 295 { 296 *dataOut++ = data[getIndex(i,j)]; 297 } 298 } 299 LeaveCriticalSection(&cs_write); 300 return; 301 } 302 303 int offsets[512]; 304 int memToAlloc = 0; 305// static int type0 = 0, type1 = 0, type2 = 0, type4 = 0, type8 = 0, chunkTotal = 0; 306 307 // Loop round all blocks 308 for( int i = 0; i < 512; i++ ) 309 { 310 offsets[i] = memToAlloc; 311 // Count how many unique tile types are in the block - if unpacked_data isn't set then there isn't any data so we can't compress any further and require no storage. 312 // Store flags for each tile type used in an array of 4 64-bit flags. 313 314#ifdef __PSVITA__ 315 // AP - Vita isn't so great at shifting 64bits. The top biggest CPU time sink after profiling is __ashldi3 (64bit shift) at 3% 316 // Let's use 32bit instead 317 unsigned int usedFlags[8] = {0,0,0,0,0,0,0,0}; 318 __int32 i32_1 = 1; 319 for( int j = 0; j < 64; j++ ) // This loop of 64 is to go round the 4 x 4 tiles in the block 320 { 321 int tile = data[getIndex(i,j)]; 322 if( tile < (64<<2) ) 323 { 324 usedFlags[tile & 7] |= ( i32_1 << ( tile >> 3 ) ); 325 } 326 } 327 int count = 0; 328 for( int tile = 0; tile < 256; tile++ ) // This loop of 256 is to go round the 256 possible values that the tiles might have had to find how many are actually used 329 { 330 if( usedFlags[tile & 7] & ( i32_1 << ( tile >> 3 ) ) ) 331 { 332 count++; 333 } 334 } 335#else 336 __uint64 usedFlags[4] = {0,0,0,0}; 337 __int64 i64_1 = 1; // MGH - instead of 1i64, which is MS specific 338 for( int j = 0; j < 64; j++ ) // This loop of 64 is to go round the 4 x 4 tiles in the block 339 { 340 int tile = data[getIndex(i,j)]; 341 342 usedFlags[tile & 3] |= ( i64_1 << ( tile >> 2 ) ); 343 } 344 int count = 0; 345 for( int tile = 0; tile < 256; tile++ ) // This loop of 256 is to go round the 256 possible values that the tiles might have had to find how many are actually used 346 { 347 if( usedFlags[tile & 3] & ( i64_1 << ( tile >> 2 ) ) ) 348 { 349 count++; 350 } 351 } 352#endif 353 if( count == 1 ) 354 { 355 _blockIndices[i] = INDEX_TYPE_0_OR_8_BIT | INDEX_TYPE_0_BIT_FLAG; 356// type0++; 357 } 358 else if( count == 2 ) 359 { 360 _blockIndices[i] = INDEX_TYPE_1_BIT; 361 memToAlloc += 10; // 8 bytes + 2 tile index 362// type1++; 363 } 364 else if ( count <= 4 ) 365 { 366 _blockIndices[i] = INDEX_TYPE_2_BIT; 367 memToAlloc += 20; // 16 bytes + 4 tile index 368// type2++; 369 } 370 else if ( count <= 16 ) 371 { 372 _blockIndices[i] = INDEX_TYPE_4_BIT; 373 memToAlloc += 48; // 32 bytes + 16 tile index 374// type4++; 375 } 376 else 377 { 378 _blockIndices[i] = INDEX_TYPE_0_OR_8_BIT; 379 memToAlloc = ( memToAlloc + 3 ) & 0xfffc; // Make sure we are 4-byte aligned for 8-bit storage 380 memToAlloc += 64; 381// type8++; 382 } 383 } 384 385// chunkTotal++; 386// printf("%d: %d (0) %d (1) %d (2) %d (4) %d (8)\n", chunkTotal, type0 / chunkTotal, type1 / chunkTotal, type2 / chunkTotal, type4 / chunkTotal, type8 / chunkTotal); 387 388 memToAlloc += 1024; // For the indices 389 unsigned char *newIndicesAndData = (unsigned char *)XPhysicalAlloc(memToAlloc, MAXULONG_PTR, 4096, PAGE_READWRITE);//(unsigned char *)malloc( memToAlloc ); 390 unsigned char *pucData = newIndicesAndData + 1024; 391 unsigned short usDataOffset = 0; 392 unsigned short *newIndices = (unsigned short *) newIndicesAndData; 393 394 // Now pass through again actually making the final compressed data 395 for( int i = 0; i < 512; i++ ) 396 { 397 unsigned short indexTypeNew = _blockIndices[i] & INDEX_TYPE_MASK; 398 newIndices[i] = indexTypeNew; 399 400 if( indexTypeNew == INDEX_TYPE_0_OR_8_BIT ) 401 { 402 if( _blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 403 { 404 newIndices[i] = INDEX_TYPE_0_OR_8_BIT | INDEX_TYPE_0_BIT_FLAG | (((unsigned short)data[getIndex(i,0)]) << INDEX_TILE_SHIFT); 405 } 406 else 407 { 408 usDataOffset = (usDataOffset + 3 ) & 0xfffc; 409 for( int j = 0; j < 64; j++ ) // This loop of 64 is to go round the 4 x 4 x 4 tiles in the block 410 { 411 pucData[usDataOffset + j] = data[getIndex(i,j)]; 412 } 413 newIndices[i] |= ( usDataOffset & INDEX_OFFSET_MASK) << INDEX_OFFSET_SHIFT; 414 usDataOffset += 64; 415 } 416 } 417 else 418 { 419 // Need to repack - TODO - from here onwards! 420 unsigned char ucMappings[256] = {0}; 421 for( int j = 0; j < 256; j++ ) 422 { 423 ucMappings[j] = 255; 424 } 425 426 unsigned char *repacked = NULL; 427 428 int bitspertile = 1 << indexTypeNew; // will be 1, 2 or 4 (from index values of 0, 1, 2) 429 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 (from index values of 0, 1, 2) 430 //int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 (from index values of 0, 1, 2) 431 int tiledatasize = 8 << indexTypeNew; // will be 8, 16 or 32 (from index values of 0, 1, 2) 432 int indexshift = 3 - indexTypeNew; // will be 3, 2 or 1 (from index values of 0, 1, 2) 433 int indexmask_bits = 7 >> indexTypeNew; // will be 7, 3 or 1 (from index values of 0, 1, 2) 434 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 435 436 unsigned char *tile_types = pucData + usDataOffset; 437 repacked = tile_types + tiletypecount; 438 XMemSet(tile_types, 255, tiletypecount); 439 XMemSet(repacked, 0,tiledatasize); 440 newIndices[i] |= ( usDataOffset & INDEX_OFFSET_MASK) << INDEX_OFFSET_SHIFT; 441 usDataOffset += tiletypecount + tiledatasize; 442 int count = 0; 443 for( int j = 0; j < 64; j++ ) 444 { 445 int tile = data[getIndex(i,j)]; 446 if( ucMappings[tile] == 255 ) 447 { 448 ucMappings[tile] = count; 449 tile_types[count++] = tile; 450 } 451 int idx = (j >> indexshift) & indexmask_bytes; 452 int bit = ( j & indexmask_bits ) * bitspertile; 453 repacked[idx] |= ucMappings[tile] << bit; 454 } 455 } 456 } 457 458 if( indicesAndData ) 459 { 460 queueForDelete( indicesAndData ); 461 } 462 indicesAndData = newIndicesAndData; 463 allocatedSize = memToAlloc; 464 LeaveCriticalSection(&cs_write); 465} 466 467#ifdef PSVITA_PRECOMPUTED_TABLE 468 469// AP - When called in pairs from LevelChunk::getBlockData this version of getData reduces the time from ~5.2ms to ~1.6ms on the Vita 470// Gets all tile values into an array of length 32768. 471void CompressedTileStorage::getData(byteArray retArray, unsigned int retOffset) 472{ 473 unsigned short *blockIndices = (unsigned short *)indicesAndData; 474 unsigned char *data = indicesAndData + 1024; 475 476 int k = 0; 477 unsigned char *Array = &retArray.data[retOffset]; 478 int *Table = CompressedTile_StorageIndexTable; 479 for( int i = 0; i < 512; i++ ) 480 { 481 int indexType = blockIndices[i] & INDEX_TYPE_MASK; 482 483 int index = ( ( i & 0x180) << 6 ) | ( ( i & 0x060 ) << 4 ) | ( ( i & 0x01f ) << 2 ); 484 unsigned char *NewArray = &Array[index]; 485 486 if( indexType == INDEX_TYPE_0_OR_8_BIT ) 487 { 488 if( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 489 { 490 unsigned char val = ( blockIndices[i] >> INDEX_TILE_SHIFT ) & INDEX_TILE_MASK; 491 for( int j = 0; j < 64; j++ ) 492 { 493 NewArray[Table[j]] = val; 494 } 495 } 496 else 497 { 498 // 8-bit reads are just directly read from the 64 long array of values stored for the block 499 unsigned char *packed = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 500 501 for( int j = 0; j < 64; j++ ) 502 { 503 NewArray[Table[j]] = packed[j]; 504 } 505 } 506 } 507 else 508 { 509 // 1, 2, or 4 bits per block packed format 510 511 int bitspertile = 1 << indexType; // will be 1, 2 or 4 (from index values of 0, 1, 2) 512 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 (from index values of 0, 1, 2) 513 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 (from index values of 0, 1, 2) 514 int indexshift = 3 - indexType; // will be 3, 2 or 1 (from index values of 0, 1, 2) 515 int indexmask_bits = 7 >> indexType; // will be 7, 3 or 1 (from index values of 0, 1, 2) 516 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 517 518 unsigned char *tile_types = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 519 unsigned char *packed = tile_types + tiletypecount; 520 521 for( int j = 0; j < 64; j++ ) 522 { 523 int idx = ( j >> indexshift ) & indexmask_bytes; 524 int bit = ( j & indexmask_bits ) << indexType; 525 NewArray[Table[j]] = tile_types[( packed[idx] >> bit ) & tiletypemask]; 526 } 527 } 528 } 529} 530 531#else 532 533// Gets all tile values into an array of length 32768. 534void CompressedTileStorage::getData(byteArray retArray, unsigned int retOffset) 535{ 536 unsigned short *blockIndices = (unsigned short *)indicesAndData; 537 unsigned char *data = indicesAndData + 1024; 538 539 for( int i = 0; i < 512; i++ ) 540 { 541 int indexType = blockIndices[i] & INDEX_TYPE_MASK; 542 if( indexType == INDEX_TYPE_0_OR_8_BIT ) 543 { 544 if( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 545 { 546 for( int j = 0; j < 64; j++ ) 547 { 548 retArray[getIndex(i,j) + retOffset] = ( blockIndices[i] >> INDEX_TILE_SHIFT ) & INDEX_TILE_MASK; 549 } 550 } 551 else 552 { 553 // 8-bit reads are just directly read from the 64 long array of values stored for the block 554 unsigned char *packed = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 555 556 for( int j = 0; j < 64; j++ ) 557 { 558 retArray[getIndex(i,j) + retOffset] = packed[j]; 559 } 560 } 561 } 562 else 563 { 564 // 1, 2, or 4 bits per block packed format 565 566 int bitspertile = 1 << indexType; // will be 1, 2 or 4 (from index values of 0, 1, 2) 567 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 (from index values of 0, 1, 2) 568 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 (from index values of 0, 1, 2) 569 int indexshift = 3 - indexType; // will be 3, 2 or 1 (from index values of 0, 1, 2) 570 int indexmask_bits = 7 >> indexType; // will be 7, 3 or 1 (from index values of 0, 1, 2) 571 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 572 573 unsigned char *tile_types = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 574 unsigned char *packed = tile_types + tiletypecount; 575 576 for( int j = 0; j < 64; j++ ) 577 { 578 int idx = ( j >> indexshift ) & indexmask_bytes; 579 int bit = ( j & indexmask_bits ) * bitspertile; 580 retArray[getIndex(i,j) + retOffset] = tile_types[( packed[idx] >> bit ) & tiletypemask]; 581 } 582 } 583 } 584} 585 586#endif 587 588// Get an individual tile value 589int CompressedTileStorage::get(int x, int y, int z) 590{ 591 if(!indicesAndData) return 0; 592 593 unsigned short *blockIndices = (unsigned short *)indicesAndData; 594 unsigned char *data = indicesAndData + 1024; 595 596 int block, tile; 597 getBlockAndTile( &block, &tile, x, y, z ); 598 int indexType = blockIndices[block] & INDEX_TYPE_MASK; 599 600 if( indexType == INDEX_TYPE_0_OR_8_BIT ) 601 { 602 if( blockIndices[block] & INDEX_TYPE_0_BIT_FLAG ) 603 { 604 // 0 bit reads are easy - the value is packed in the index 605 return ( blockIndices[block] >> INDEX_TILE_SHIFT ) & INDEX_TILE_MASK; 606 } 607 else 608 { 609 // 8-bit reads are just directly read from the 64 long array of values stored for the block 610 unsigned char *packed = data + ( ( blockIndices[block] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 611 return packed[tile]; 612 } 613 } 614 else 615 { 616 int bitspertile = 1 << indexType; // will be 1, 2 or 4 (from index values of 0, 1, 2) 617 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 (from index values of 0, 1, 2) 618 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 (from index values of 0, 1, 2) 619 int indexshift = 3 - indexType; // will be 3, 2 or 1 (from index values of 0, 1, 2) 620 int indexmask_bits = 7 >> indexType; // will be 7, 3 or 1 (from index values of 0, 1, 2) 621 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 622 623 unsigned char *tile_types = data + ( ( blockIndices[block] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 624 unsigned char *packed = tile_types + tiletypecount; 625 int idx = ( tile >> indexshift ) & indexmask_bytes; 626 int bit = ( tile & indexmask_bits ) * bitspertile; 627 return tile_types[( packed[idx] >> bit ) & tiletypemask]; 628 } 629 return 0; 630} 631 632// Set an individual tile value 633void CompressedTileStorage::set(int x, int y, int z, int val) 634{ 635 EnterCriticalSection(&cs_write); 636 assert(val !=255 ); 637 int block, tile; 638 getBlockAndTile( &block, &tile, x, y, z ); 639 640 // 2 passes - first pass will try and store within the current levels of compression, then if that fails will 641 // upgrade the block we are writing to (so more bits can be stored) to achieve the storage required 642 for( int pass = 0; pass < 2; pass++ ) 643 { 644 unsigned short *blockIndices = (unsigned short *)indicesAndData; 645 unsigned char *data = indicesAndData + 1024; 646 647 int indexType = blockIndices[block] & INDEX_TYPE_MASK; 648 649 if( indexType == INDEX_TYPE_0_OR_8_BIT ) 650 { 651 if( blockIndices[block] & INDEX_TYPE_0_BIT_FLAG ) 652 { 653 // 0 bits - if its the value already, we're done, otherwise continue on to upgrade storage 654 if ( val == ( ( blockIndices[block] >> INDEX_TILE_SHIFT ) & INDEX_TILE_MASK ) ) 655 { 656 LeaveCriticalSection(&cs_write); 657 return; 658 } 659 } 660 else 661 { 662 // 8 bits - just store directly and we're done 663 unsigned char *packed = data + ( ( blockIndices[block] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 664 packed[ tile ] = val; 665 LeaveCriticalSection(&cs_write); 666 return; 667 } 668 } 669 else 670 { 671 int bitspertile = 1 << indexType; // will be 1, 2 or 4 (from index values of 0, 1, 2) 672 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 (from index values of 0, 1, 2) 673 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 (from index values of 0, 1, 2) 674 int indexshift = 3 - indexType; // will be 3, 2 or 1 (from index values of 0, 1, 2) 675 int indexmask_bits = 7 >> indexType; // will be 7, 3 or 1 (from index values of 0, 1, 2) 676 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 677 678 unsigned char *tile_types = data + ( ( blockIndices[block] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 679 680 for( int i = 0; i < tiletypecount; i++ ) 681 { 682 if( ( tile_types[i] == val ) || ( tile_types[i] == 255 ) ) 683 { 684 tile_types[i] = val; 685 unsigned char *packed = tile_types + tiletypecount; 686 int idx = ( tile >> indexshift ) & indexmask_bytes; 687 int bit = ( tile & indexmask_bits ) * bitspertile; 688 packed[idx] &= ~( tiletypemask << bit ); 689 packed[idx] |= i << bit; 690 LeaveCriticalSection(&cs_write); 691 return; 692 } 693 } 694 } 695 if( pass == 0 ) 696 { 697 compress(block); 698 } 699 }; 700 LeaveCriticalSection(&cs_write); 701} 702 703// Sets a region of tile values with the data at offset position in the array dataIn - external ordering compatible with java DataLayer 704int CompressedTileStorage::setDataRegion(byteArray dataIn, int x0, int y0, int z0, int x1, int y1, int z1, int offset, tileUpdatedCallback callback, void *param, int yparam) 705{ 706 unsigned char *pucIn = &dataIn.data[offset]; 707 708 if( callback ) 709 { 710 for( int x = x0; x < x1; x++ ) 711 { 712 for( int z = z0; z < z1; z++ ) 713 { 714 for( int y = y0; y < y1; y++ ) 715 { 716 if(get(x, y, z) != *pucIn) 717 { 718 set(x, y, z, *pucIn); 719 callback(x, y, z, param, yparam); 720 } 721 pucIn++; 722 } 723 } 724 } 725 } 726 else 727 { 728 for( int x = x0; x < x1; x++ ) 729 { 730 for( int z = z0; z < z1; z++ ) 731 { 732 for( int y = y0; y < y1; y++ ) 733 { 734 set(x, y, z, *pucIn++); 735 } 736 } 737 } 738 } 739 ptrdiff_t count = pucIn - &dataIn.data[offset]; 740 741 return (int)count; 742} 743 744// Tests whether setting data would actually change anything 745bool CompressedTileStorage::testSetDataRegion(byteArray dataIn, int x0, int y0, int z0, int x1, int y1, int z1, int offset) 746{ 747 unsigned char *pucIn = &dataIn.data[offset]; 748 for( int x = x0; x < x1; x++ ) 749 { 750 for( int z = z0; z < z1; z++ ) 751 { 752 for( int y = y0; y < y1; y++ ) 753 { 754 if(get(x, y, z) != *pucIn++) 755 { 756 return true; 757 } 758 } 759 } 760 } 761 return false; 762} 763 764// Updates the data at offset position dataInOut with a region of tile information - external ordering compatible with java DataLayer 765int CompressedTileStorage::getDataRegion(byteArray dataInOut, int x0, int y0, int z0, int x1, int y1, int z1, int offset) 766{ 767 unsigned char *pucOut = &dataInOut.data[offset]; 768 for( int x = x0; x < x1; x++ ) 769 { 770 for( int z = z0; z < z1; z++ ) 771 { 772 for( int y = y0; y < y1; y++ ) 773 { 774 *pucOut++ = get(x, y, z); 775 } 776 } 777 } 778 ptrdiff_t count = pucOut - &dataInOut.data[offset]; 779 780 return (int)count; 781} 782 783void CompressedTileStorage::staticCtor() 784{ 785 InitializeCriticalSectionAndSpinCount(&cs_write, 5120); 786 for( int i = 0; i < 3; i++ ) 787 { 788 deleteQueue[i].Initialize(); 789 } 790} 791 792void CompressedTileStorage::queueForDelete(unsigned char *data) 793{ 794 // Add this into a queue for deleting. This shouldn't be actually deleted until tick has been called twice from when 795 // the data went into the queue. 796 if( data ) 797 { 798 deleteQueue[deleteQueueIndex].Push( data ); 799 } 800} 801 802void CompressedTileStorage::tick() 803{ 804 // We have 3 queues for deleting. Always delete from the next one after where we are writing to, so it should take 2 ticks 805 // before we ever delete something, from when the request to delete it came in 806 int freeIndex = ( deleteQueueIndex + 1 ) % 3; 807 808// printf("Free queue: %d, %d\n",deleteQueue[freeIndex].GetEntryCount(),deleteQueue[freeIndex].GetAllocated()); 809 unsigned char *toFree = NULL; 810 do 811 { 812 toFree = deleteQueue[freeIndex].Pop(); 813// if( toFree ) printf("Deleting 0x%x\n", toFree); 814#if 1 815 if( toFree ) XPhysicalFree(toFree); 816#else 817 // Determine correct means to free this data - could have been allocated either with XPhysicalAlloc or malloc 818 if( (unsigned int)toFree >= MM_PHYSICAL_4KB_BASE ) 819 { 820 XPhysicalFree(toFree); 821 } 822 else 823 { 824 free(toFree); 825 } 826#endif 827 } while( toFree ); 828 829 deleteQueueIndex = ( deleteQueueIndex + 1 ) % 3; 830} 831 832#ifdef __PS3__ 833void CompressedTileStorage::compress_SPU(int upgradeBlock/*=-1*/) 834{ 835 EnterCriticalSection(&cs_write); 836 static unsigned char compBuffer[32768+4096] __attribute__((__aligned__(16))); 837 CompressedTileStorage_compress_dataIn& dataIn = g_compressTileDataIn[0]; 838 dataIn.allocatedSize = allocatedSize; 839 dataIn.indicesAndData = indicesAndData; 840 dataIn.newIndicesAndData = compBuffer; 841 dataIn.upgradeBlock = upgradeBlock; 842 843 static C4JSpursJobQueue::Port p("CompressedTileStorage::compress_SPU"); 844 C4JSpursJob_CompressedTileStorage_compress compressJob(&dataIn); 845 p.submitJob(&compressJob); 846 p.waitForCompletion(); 847 848 if(dataIn.neededCompressed) 849 { 850 unsigned char *newIndicesAndData = (unsigned char *)XPhysicalAlloc(dataIn.newAllocatedSize, MAXULONG_PTR, 4096, PAGE_READWRITE);//(unsigned char *)malloc( memToAlloc ); 851 memcpy(newIndicesAndData, compBuffer, dataIn.newAllocatedSize); 852 queueForDelete( indicesAndData ); 853 indicesAndData = newIndicesAndData; 854 allocatedSize = dataIn.newAllocatedSize; 855 } 856 857 LeaveCriticalSection(&cs_write); 858 859} 860#endif 861 862// Compresses the data currently stored in one of two ways: 863// (1) Attempt to compresses every block as much as possible (if upgradeBlock is -1) 864// (2) Copy all blocks as-is apart from the block specified by upgradeBlock ( if > -1 ), which is changed to be the next-most-accomodating storage from its current state 865void CompressedTileStorage::compress(int upgradeBlock/*=-1*/) 866{ 867#if defined __PS3__ && !defined DISABLE_SPU_CODE 868 compress_SPU(upgradeBlock); 869 return; 870#endif 871 872 unsigned char tempdata[64]; 873 unsigned short _blockIndices[512]; 874 875 // If this is already fully compressed, early out 876 if( ( allocatedSize == 1024 ) && ( upgradeBlock == -1 ) ) return; 877 878 bool needsCompressed = ( upgradeBlock > -1 ); // If an upgrade block is specified, we'll always need to recompress - otherwise default to false 879 880 EnterCriticalSection(&cs_write); 881 882 unsigned short *blockIndices = (unsigned short *)indicesAndData; 883 unsigned char *data = indicesAndData + 1024; 884 885 int memToAlloc = 0; 886 for( int i = 0; i < 512; i++ ) 887 { 888 unsigned short indexType = blockIndices[i] & INDEX_TYPE_MASK; 889 890 unsigned char *unpacked_data = NULL; 891 unsigned char *packed_data; 892 893 // First task is to find out what type of storage each block needs. Need to unpack each where required. 894 // Note that we don't need to fully unpack the data at this stage since we are only interested in working out how many unique types of tiles are in each block, not 895 // what those actual tile ids are. 896 if( upgradeBlock == -1 ) 897 { 898 if( indexType == INDEX_TYPE_0_OR_8_BIT ) 899 { 900 // Note that we are only interested in data that can be packed further, so we don't need to consider things that are already at their most compressed 901 // (ie with INDEX_TYPE_0_BIT_FLAG set) 902 if( ( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) == 0 ) 903 { 904 unpacked_data = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 905 } 906 } 907 else 908 { 909 int bitspertile = 1 << indexType; // will be 1, 2 or 4 (from index values of 0, 1, 2) 910 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 911 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 912 int indexshift = 3 - indexType; // will be 3, 2 or 1 (from index values of 0, 1, 2) 913 int indexmask_bits = 7 >> indexType; // will be 7, 3 or 1 (from index values of 0, 1, 2) 914 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 915 916 unpacked_data = tempdata; 917 packed_data = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ) + tiletypecount; 918 919 for( int j = 0; j < 64; j++ ) 920 { 921 int idx = (j >> indexshift) & indexmask_bytes; 922 int bit = ( j & indexmask_bits ) * bitspertile; 923 924 unpacked_data[j] = ( packed_data[idx] >> bit ) & tiletypemask; // Doesn't need the actual data for each tile, just unique values 925 } 926 } 927 928 if( unpacked_data ) 929 { 930 // Now count how many unique tile types are in the block - if unpacked_data isn't set then there isn't any data so we can't compress any further and require no storage. 931 // Store flags for each tile type used in an array of 4 64-bit flags. 932 933#ifdef __PSVITA__ 934 // AP - Vita isn't so great at shifting 64bits. The top biggest CPU time sink after profiling is __ashldi3 (64bit shift) at 3% 935 // lets use 32bit values instead 936 unsigned int usedFlags[8] = {0,0,0,0,0,0,0,0}; 937 __int32 i32_1 = 1; 938 for( int j = 0; j < 64; j++ ) // This loop of 64 is to go round the 4x4x4 tiles in the block 939 { 940 int tiletype = unpacked_data[j]; 941 usedFlags[tiletype & 7] |= ( i32_1 << ( tiletype >> 3 ) ); 942 } 943 // count the number of bits set using the 'Hammering Weight' method. This reduces ::compress total thread cpu consumption from 10% to 4% 944 unsigned int count = 0; 945 for( int Index = 0;Index < 8;Index += 1 ) 946 { 947 unsigned int i = usedFlags[Index]; 948 i = i - ((i >> 1) & 0x55555555); 949 i = (i & 0x33333333) + ((i >> 2) & 0x33333333); 950 count += (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; 951 } 952#else 953 954 __uint64 usedFlags[4] = {0,0,0,0}; 955 __int64 i64_1 = 1; // MGH - instead of 1i64, which is MS specific 956 for( int j = 0; j < 64; j++ ) // This loop of 64 is to go round the 4x4x4 tiles in the block 957 { 958 int tiletype = unpacked_data[j]; 959 usedFlags[tiletype & 3] |= ( i64_1 << ( tiletype >> 2 ) ); 960 } 961 int count = 0; 962 for( int tiletype = 0; tiletype < 256; tiletype++ ) // This loop of 256 is to go round the 256 possible values that the tiles might have had to find how many are actually used 963 { 964 if( usedFlags[tiletype & 3] & ( i64_1 << ( tiletype >> 2 ) ) ) 965 { 966 count++; 967 } 968 } 969#endif 970 971 if( count == 1 ) 972 { 973 _blockIndices[i] = INDEX_TYPE_0_OR_8_BIT | INDEX_TYPE_0_BIT_FLAG; 974 975 // We'll need to compress if this isn't the same type as before. If it *was* a 0-bit one though, then unpacked_data wouldn't have been set and we wouldn't be here 976 needsCompressed = true; 977 } 978 else if( count == 2 ) 979 { 980 _blockIndices[i] = INDEX_TYPE_1_BIT; 981 if( indexType != INDEX_TYPE_1_BIT ) needsCompressed = true; 982 memToAlloc += 10; // 8 bytes + 2 tile index 983 } 984 else if ( count <= 4 ) 985 { 986 _blockIndices[i] = INDEX_TYPE_2_BIT; 987 if( indexType != INDEX_TYPE_2_BIT ) needsCompressed = true; 988 memToAlloc += 20; // 16 bytes + 4 tile index 989 } 990 else if ( count <= 16 ) 991 { 992 _blockIndices[i] = INDEX_TYPE_4_BIT; 993 if( indexType != INDEX_TYPE_4_BIT ) needsCompressed = true; 994 memToAlloc += 48; // 32 bytes + 16 tile index 995 } 996 else 997 { 998 _blockIndices[i] = INDEX_TYPE_0_OR_8_BIT; 999 memToAlloc = ( memToAlloc + 3 ) & 0xfffc; // Make sure we are 4-byte aligned for 8-bit storage 1000 memToAlloc += 64; 1001 } 1002 } 1003 else 1004 { 1005 // Already will be 0 bits, so we can't do any further compression - just copy the index over. 1006 _blockIndices[i] = blockIndices[i]; 1007 } 1008 } 1009 else 1010 { 1011 if( i == upgradeBlock ) 1012 { 1013 // INDEX_TYPE_1_BIT (0) -> INDEX_TYPE_2_BIT (1) 1014 // INDEX_TYPE_2_BIT (1) -> INDEX_TYPE_4_BIT (2) 1015 // INDEX_TYPE_4_BIT (2) -> INDEX_TYPE_0_OR_8_BIT (3) (new will be 8-bit) 1016 // INDEX_TYPE_0_OR_8_BIT (3) -> INDEX_TYPE_1_BIT (0) (assuming old was 0-bit) 1017 _blockIndices[i] = ( ( blockIndices[i] & INDEX_TYPE_MASK ) + 1 ) & INDEX_TYPE_MASK; 1018 } 1019 else 1020 { 1021 // Copy over the index, without the offset. 1022 _blockIndices[i] = blockIndices[i] & INDEX_TYPE_MASK; 1023 if( _blockIndices[i] == INDEX_TYPE_0_OR_8_BIT ) 1024 { 1025 _blockIndices[i] |= ( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ); 1026 } 1027 } 1028 switch(_blockIndices[i]) 1029 { 1030 case INDEX_TYPE_1_BIT: 1031 memToAlloc += 10; 1032 break; 1033 case INDEX_TYPE_2_BIT: 1034 memToAlloc += 20; 1035 break; 1036 case INDEX_TYPE_4_BIT: 1037 memToAlloc += 48; 1038 break; 1039 case INDEX_TYPE_0_OR_8_BIT: 1040 memToAlloc = ( memToAlloc + 3 ) & 0xfffc; // Make sure we are 4-byte aligned for 8-bit storage 1041 memToAlloc += 64; 1042 break; 1043 // Note that INDEX_TYPE_8_BIT|INDEX_TYPE_0_BIT_FLAG not in here as it doesn't need any further allocation 1044 } 1045 } 1046 } 1047 1048 // If we need to do something here, then lets allocate some memory 1049 if( needsCompressed ) 1050 { 1051 memToAlloc += 1024; // For the indices 1052 unsigned char *newIndicesAndData = (unsigned char *)XPhysicalAlloc(memToAlloc, MAXULONG_PTR, 4096, PAGE_READWRITE);//(unsigned char *)malloc( memToAlloc ); 1053 if( newIndicesAndData == NULL ) 1054 { 1055 DWORD lastError = GetLastError(); 1056#ifndef _DURANGO 1057 MEMORYSTATUS memStatus; 1058 GlobalMemoryStatus(&memStatus); 1059 __debugbreak(); 1060#endif 1061 } 1062 unsigned char *pucData = newIndicesAndData + 1024; 1063 unsigned short usDataOffset = 0; 1064 unsigned short *newIndices = (unsigned short *) newIndicesAndData; 1065 1066 // Now pass through again actually making the final compressed data 1067 for( int i = 0; i < 512; i++ ) 1068 { 1069 unsigned short indexTypeNew = _blockIndices[i] & INDEX_TYPE_MASK; 1070 unsigned short indexTypeOld = blockIndices[i] & INDEX_TYPE_MASK; 1071 newIndices[i] = indexTypeNew; 1072 1073 // Is the type unmodifed? Then can just copy over 1074 bool done = false; 1075 if( indexTypeOld == indexTypeNew ) 1076 { 1077 unsigned char *packed_data; 1078 if( indexTypeOld == INDEX_TYPE_0_OR_8_BIT ) 1079 { 1080 if( ( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) == ( _blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) ) 1081 { 1082 if( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 1083 { 1084 newIndices[i] = blockIndices[i]; 1085 } 1086 else 1087 { 1088 packed_data = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK); 1089 usDataOffset = (usDataOffset + 3 ) & 0xfffc; 1090 XMemCpy( pucData + usDataOffset, packed_data, 64 ); 1091 newIndices[i] |= ( usDataOffset & INDEX_OFFSET_MASK) << INDEX_OFFSET_SHIFT; 1092 usDataOffset += 64; 1093 } 1094 done = true; 1095 } 1096 } 1097 else 1098 { 1099 packed_data = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK); 1100 1101 int dataSize = 8 << indexTypeOld; // 8, 16 or 32 bytes of per-tile storage 1102 dataSize += 1 << ( 1 << indexTypeOld ); // 2, 4 or 16 bytes to store each tile type 1103 newIndices[i] |= ( usDataOffset & INDEX_OFFSET_MASK) << INDEX_OFFSET_SHIFT; 1104 XMemCpy( pucData + usDataOffset, packed_data, dataSize ); 1105 usDataOffset += dataSize; 1106 done = true; 1107 } 1108 } 1109 1110 1111 // If we're not done, then we actually need to recompress this block. First of all decompress from its current format. 1112 if( !done ) 1113 { 1114 unsigned char *unpacked_data = NULL; 1115 unsigned char *tile_types = NULL; 1116 unsigned char *packed_data = NULL; 1117 if( indexTypeOld == INDEX_TYPE_0_OR_8_BIT ) 1118 { 1119 if( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 1120 { 1121 unpacked_data = tempdata; 1122 int value = ( blockIndices[i] >> INDEX_TILE_SHIFT ) & INDEX_TILE_MASK; 1123 XMemSet( tempdata, value, 64 ); 1124 } 1125 else 1126 { 1127 unpacked_data = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 1128 } 1129 } 1130 else 1131 { 1132 int bitspertile = 1 << indexTypeOld; // will be 1, 2 or 4 (from index values of 0, 1, 2) 1133 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 1134 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 1135 int indexshift = 3 - indexTypeOld; // will be 3, 2 or 1 (from index values of 0, 1, 2) 1136 int indexmask_bits = 7 >> indexTypeOld; // will be 7, 3 or 1 (from index values of 0, 1, 2) 1137 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 1138 1139 unpacked_data = tempdata; 1140 tile_types = data + ( ( blockIndices[i] >> INDEX_OFFSET_SHIFT ) & INDEX_OFFSET_MASK ); 1141 packed_data = tile_types + tiletypecount; 1142 for( int j = 0; j < 64; j++ ) 1143 { 1144 int idx = ( j >> indexshift ) & indexmask_bytes; 1145 int bit = ( j & indexmask_bits ) * bitspertile; 1146 1147 unpacked_data[j] = tile_types[(packed_data[idx] >> bit) & tiletypemask]; 1148 } 1149 } 1150 1151 // And finally repack 1152 unsigned char ucMappings[256] = {0}; 1153#ifdef __PSVITA__ 1154 memset(ucMappings, 255, 256); 1155#else 1156 for( int j = 0; j < 256; j++ ) 1157 { 1158 ucMappings[j] = 255; 1159 } 1160#endif 1161 1162 unsigned char *repacked = NULL; 1163 1164 if( indexTypeNew == INDEX_TYPE_0_OR_8_BIT ) 1165 { 1166 if( _blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 1167 { 1168 newIndices[i] = INDEX_TYPE_0_OR_8_BIT | INDEX_TYPE_0_BIT_FLAG | (((unsigned short)unpacked_data[0]) << INDEX_TILE_SHIFT); 1169 } 1170 else 1171 { 1172 usDataOffset = (usDataOffset + 3 ) & 0xfffc; // Make sure offset is 4 byte aligned 1173 XMemCpy( pucData + usDataOffset, unpacked_data, 64 ); 1174 newIndices[i] |= ( usDataOffset & INDEX_OFFSET_MASK) << INDEX_OFFSET_SHIFT; 1175 usDataOffset += 64; 1176 } 1177 } 1178 else 1179 { 1180 int bitspertile = 1 << indexTypeNew; // will be 1, 2 or 4 (from index values of 0, 1, 2) 1181 int tiletypecount = 1 << bitspertile; // will be 2, 4 or 16 (from index values of 0, 1, 2) 1182 int tiletypemask = tiletypecount - 1; // will be 1, 3 or 15 (from index values of 0, 1, 2) 1183 int tiledatasize = 8 << indexTypeNew; // will be 8, 16 or 32 (from index values of 0, 1, 2) 1184 int indexshift = 3 - indexTypeNew; // will be 3, 2 or 1 (from index values of 0, 1, 2) 1185 int indexmask_bits = 7 >> indexTypeNew; // will be 7, 3 or 1 (from index values of 0, 1, 2) 1186 int indexmask_bytes = 62 >> indexshift; // will be 7, 15 or 31 (from index values of 0, 1, 2) 1187 1188 tile_types = pucData + usDataOffset; 1189 repacked = tile_types + tiletypecount; 1190 XMemSet(tile_types, 255, tiletypecount); 1191 XMemSet(repacked, 0,tiledatasize); 1192 newIndices[i] |= ( usDataOffset & INDEX_OFFSET_MASK) << INDEX_OFFSET_SHIFT; 1193 usDataOffset += tiletypecount + tiledatasize; 1194 int count = 0; 1195 for( int j = 0; j < 64; j++ ) 1196 { 1197 int tile = unpacked_data[j]; 1198 if( ucMappings[tile] == 255 ) 1199 { 1200 ucMappings[tile] = count; 1201 tile_types[count++] = tile; 1202 } 1203 int idx = (j >> indexshift) & indexmask_bytes; 1204 int bit = ( j & indexmask_bits ) * bitspertile; 1205 repacked[idx] |= ucMappings[tile] << bit; 1206 } 1207 } 1208 } 1209 } 1210 1211 queueForDelete( indicesAndData ); 1212 indicesAndData = newIndicesAndData; 1213 allocatedSize = memToAlloc; 1214 } 1215 LeaveCriticalSection(&cs_write); 1216} 1217 1218int CompressedTileStorage::getAllocatedSize(int *count0, int *count1, int *count2, int *count4, int *count8) 1219{ 1220 *count0 = 0; 1221 *count1 = 0; 1222 *count2 = 0; 1223 *count4 = 0; 1224 *count8 = 0; 1225 1226 unsigned short *blockIndices = (unsigned short *)indicesAndData; 1227 for(int i = 0; i < 512; i++ ) 1228 { 1229 unsigned short idxType = blockIndices[i] & INDEX_TYPE_MASK; 1230 if( idxType == INDEX_TYPE_1_BIT ) 1231 { 1232 (*count1)++; 1233 } 1234 else if( idxType == INDEX_TYPE_2_BIT ) 1235 { 1236 (*count2)++; 1237 } 1238 else if( idxType == INDEX_TYPE_4_BIT ) 1239 { 1240 (*count4)++; 1241 } 1242 else if( idxType == INDEX_TYPE_0_OR_8_BIT ) 1243 { 1244 if( blockIndices[i] & INDEX_TYPE_0_BIT_FLAG ) 1245 { 1246 (*count0)++; 1247 } 1248 else 1249 { 1250 (*count8)++; 1251 } 1252 } 1253 } 1254 return allocatedSize; 1255} 1256 1257int CompressedTileStorage::getHighestNonEmptyY() 1258{ 1259 unsigned short *blockIndices = (unsigned short *)indicesAndData; 1260 unsigned int highestYBlock = 0; 1261 bool found = false; 1262 1263 // The 512 "blocks" (4x4x4 tiles) are arranged in 32 layers 1264 for(int yBlock = 31; yBlock >= 0; --yBlock) 1265 { 1266 // Each layer has 16 blocks 1267 for(unsigned int xzBlock = 0; xzBlock < 16; ++xzBlock) 1268 { 1269 // Blocks are ordered in columns 1270 int index = yBlock + (xzBlock * 32); 1271 1272 int indexType = blockIndices[index] & INDEX_TYPE_MASK; 1273 if( indexType == INDEX_TYPE_0_OR_8_BIT && blockIndices[index] & INDEX_TYPE_0_BIT_FLAG ) 1274 { 1275 int val = ( blockIndices[index] >> INDEX_TILE_SHIFT ) & INDEX_TILE_MASK; 1276 if(val != 0) 1277 { 1278 highestYBlock = yBlock; 1279 found = true; 1280 break; 1281 } 1282 } 1283 else 1284 { 1285 highestYBlock = yBlock; 1286 found = true; 1287 break; 1288 } 1289 } 1290 1291 if(found) break; 1292 } 1293 1294 int highestNonEmptyY = -1; 1295 if(found) 1296 { 1297 // Multiply by the number of vertical tiles in a block, and then add that again to be at the top of the block 1298 highestNonEmptyY = (highestYBlock * 4) + 4; 1299 } 1300 return highestNonEmptyY; 1301} 1302 1303void CompressedTileStorage::write(DataOutputStream *dos) 1304{ 1305 dos->writeInt(allocatedSize); 1306 if(indicesAndData) 1307 { 1308 if(LOCALSYTEM_ENDIAN == BIGENDIAN) 1309 { 1310 // The first 1024 bytes are an array of shorts, so we need to reverse the endianness 1311 byteArray indicesCopy(1024); 1312 memcpy(indicesCopy.data, indicesAndData, 1024); 1313 reverseIndices(indicesCopy.data); 1314 dos->write(indicesCopy); 1315 delete [] indicesCopy.data; 1316 1317 // Write the rest of the data 1318 if(allocatedSize > 1024) 1319 { 1320 byteArray dataWrapper(indicesAndData + 1024, allocatedSize - 1024); 1321 dos->write(dataWrapper); 1322 } 1323 } 1324 else 1325 { 1326 byteArray wrapper(indicesAndData, allocatedSize); 1327 dos->write(wrapper); 1328 } 1329 } 1330} 1331 1332void CompressedTileStorage::read(DataInputStream *dis) 1333{ 1334 allocatedSize = dis->readInt(); 1335 if(allocatedSize > 0) 1336 { 1337 // This delete should be safe to do in a non-thread safe way as the chunk is fully read before any external reference is available to it from another thread 1338 if( indicesAndData ) 1339 { 1340 XPhysicalFree(indicesAndData); 1341 } 1342 indicesAndData = (unsigned char *)XPhysicalAlloc(allocatedSize, MAXULONG_PTR, 4096, PAGE_READWRITE); 1343 1344 byteArray wrapper(indicesAndData, allocatedSize); 1345 dis->readFully(wrapper); 1346 if(LOCALSYTEM_ENDIAN == BIGENDIAN) 1347 { 1348 reverseIndices(indicesAndData); 1349 } 1350 1351 compress(); 1352 } 1353} 1354 1355void CompressedTileStorage::reverseIndices(unsigned char *indices) 1356{ 1357 unsigned short *blockIndices = (unsigned short *)indices; 1358 for( int i = 0; i < 512; i++ ) 1359 { 1360 System::ReverseUSHORT(&blockIndices[i]); 1361 } 1362}