the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 642 lines 22 kB view raw
1#include "stdafx.h" 2#include "SparseLightStorage.h" 3 4// Note: See header for an overview of this class 5 6int SparseLightStorage::deleteQueueIndex; 7XLockFreeStack <unsigned char> SparseLightStorage::deleteQueue[3]; 8 9void SparseLightStorage::staticCtor() 10{ 11 for( int i = 0; i < 3; i++ ) 12 { 13 deleteQueue[i].Initialize(); 14 } 15} 16 17// Initialise lighting storage, with very limited compression - the very first plane is stored as either compressed to be "all 15" or "all 0" depending on whether this 18// will store sky or not, and the rest of the planes aren't compressed at all. The reason behind this is to keep the total allocation as a round number of 4K (small) pages, ie 16K. 19// By doing this, and doing this "special" allocation as a XPhysicalAlloc rather than a malloc, we can help ensure that this full allocation gets cleaned up properly when the first 20// proper compression is done on this storage. If it were just allocated with malloc, then the memory management system would have a large number of 16512 allocations to free, and 21// it seems from experimentation that these basically don't make it back to the system as free pages. 22// Note - the other approach here would be to allocate *no* actual storage for the lights at the ctor stage. However, as chunks are created then this creates an awful lot of intermediate 23// stages as each line of lighting is added, so it is actually much cleaner to just allocate almost fully here & then attempt to do a single compression pass over the data later on. 24SparseLightStorage::SparseLightStorage(bool sky) 25{ 26 // Allocate using physical alloc. As this will (by default) return memory from the pool of 4KB pages, the address will in the range of MM_PHYSICAL_4KB_BASE upwards. We can use 27 // this fact to identify the allocation later, and so free it with the corresponding call to XPhysicalFree. 28#ifdef _XBOX 29 unsigned char *planeIndices = (unsigned char *)XPhysicalAlloc(128 * 128, MAXULONG_PTR, 4096, PAGE_READWRITE); 30#else 31 unsigned char *planeIndices = (unsigned char *)malloc(128 * 128); 32#endif 33 unsigned char *data = planeIndices + 128; 34 planeIndices[127] = sky ? ALL_15_INDEX : ALL_0_INDEX; 35 for( int i = 0; i < 127; i++ ) 36 { 37 planeIndices[i] = i; 38 } 39 XMemSet(data, 0, 128 * 127); 40 41 // Data and count packs together the pointer to our data and the count of planes allocated - 127 planes allocated in this case 42#pragma warning ( disable : 4826 ) 43 dataAndCount = 0x007F000000000000L | (( (__int64) planeIndices ) & 0x0000ffffffffffffL); 44#pragma warning ( default : 4826 ) 45#ifdef LIGHT_COMPRESSION_STATS 46 count = 127; 47#endif 48} 49 50SparseLightStorage::SparseLightStorage(bool sky, bool isUpper) 51{ 52 // Allocate using physical alloc. As this will (by default) return memory from the pool of 4KB pages, the address will in the range of MM_PHYSICAL_4KB_BASE upwards. We can use 53 // this fact to identify the allocation later, and so free it with the corresponding call to XPhysicalFree. 54 unsigned char *planeIndices = (unsigned char *)malloc(128); 55 for( int i = 0; i < 128; i++ ) 56 { 57 planeIndices[i] = sky ? ALL_15_INDEX : ALL_0_INDEX; 58 } 59 60 // Data and count packs together the pointer to our data and the count of planes allocated - 0 planes allocated in this case 61#pragma warning ( disable : 4826 ) 62 dataAndCount = 0x0000000000000000L | (( (__int64) planeIndices ) & 0x0000ffffffffffffL); 63#pragma warning ( default : 4826 ) 64#ifdef LIGHT_COMPRESSION_STATS 65 count = 0; 66#endif 67} 68 69SparseLightStorage::~SparseLightStorage() 70{ 71 unsigned char *indicesAndData = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); 72 // Determine correct means to free this data - could have been allocated either with XPhysicalAlloc or malloc 73 74#ifdef _XBOX 75 if( (unsigned int)indicesAndData >= MM_PHYSICAL_4KB_BASE ) 76 { 77 XPhysicalFree(indicesAndData); 78 } 79 else 80#endif 81 { 82 free(indicesAndData); 83 } 84// printf("Free (in dtor) 0x%x\n", indicesAndData); 85} 86 87SparseLightStorage::SparseLightStorage(SparseLightStorage *copyFrom) 88{ 89 // Extra details of source storage 90 __int64 sourceDataAndCount = copyFrom->dataAndCount; 91 unsigned char *sourceIndicesAndData = (unsigned char *)(sourceDataAndCount & 0x0000ffffffffffff); 92 int sourceCount = (sourceDataAndCount >> 48 ) & 0xffff; 93 94 // Allocate & copy indices ( 128 bytes ) and any allocated planes (128 * count) 95 unsigned char *destIndicesAndData = (unsigned char *)malloc( sourceCount * 128 + 128 ); 96 97 // AP - I've moved this to be before the memcpy because of a very strange bug on vita. Sometimes dataAndCount wasn't valid in time when ::get was called. 98 // This should never happen and this isn't a proper solution but fixes it for now. 99#pragma warning ( disable : 4826 ) 100 dataAndCount = ( sourceDataAndCount & 0xffff000000000000L ) | ( ((__int64) destIndicesAndData ) & 0x0000ffffffffffffL ); 101#pragma warning ( default : 4826 ) 102 103 XMemCpy( destIndicesAndData, sourceIndicesAndData, sourceCount * 128 + 128 ); 104 105#ifdef LIGHT_COMPRESSION_STATS 106 count = sourceCount; 107#endif 108} 109 110// Set all lighting values from a data array of length 16384 (128 x 16 x 16 x 0.5). Source data must have same order as original java game 111void SparseLightStorage::setData(byteArray dataIn, unsigned int inOffset) 112{ 113 // Original order is defined as: 114 // pos = (x << 11 | z << 7 | y); 115 // slot = pos >> 1; 116 // part = pos & 1; 117 // if ( part == 0 ) value = data[slot] & 0xf 118 // else value = (data[slot] >> 4) & 0xf 119 120 // Two passed through the data. First pass sets up plane indices, and counts number of planes that we actually need to allocate 121 int allocatedPlaneCount = 0; 122 unsigned char _planeIndices[128]; 123 124 for( int y = 0; y < 128; y++ ) 125 { 126 bool all0 = true; 127 bool all15 = true; 128 129 for( int xz = 0; xz < 256; xz++ ) // 256 in loop as 16 x 16 separate bytes need checked 130 { 131 int pos = ( xz << 7 ) | y; 132 int slot = pos >> 1; 133 int part = pos & 1; 134 unsigned char value = ( dataIn[slot + inOffset] >> (part * 4) ) & 15; 135 if( value != 0 ) all0 = false; 136 if( value != 15 ) all15 = false; 137 } 138 if( all0 ) 139 { 140 _planeIndices[y] = ALL_0_INDEX; 141 } 142 else if( all15 ) 143 { 144 _planeIndices[y] = ALL_15_INDEX; 145 } 146 else 147 { 148 _planeIndices[y] = allocatedPlaneCount++; 149 } 150 } 151 152 // Allocate required storage 153 unsigned char *planeIndices = (unsigned char *)malloc(128 * allocatedPlaneCount + 128); 154 unsigned char *data = planeIndices + 128; 155 XMemCpy(planeIndices, _planeIndices, 128); 156 157 // Second pass through to actually copy the data in to the storage allocated for the required planes 158 unsigned char *pucOut = data; 159 for( int y = 0; y < 128 ; y++ ) 160 { 161 // Index will be < 128 if we allocated storage for it and it has a valid index. No need to actually check the index as 162 // we know they were sequentially allocated above. 163 if( planeIndices[y] < 128 ) 164 { 165 int part = y & 1; 166 //int shift = 4 * part; 167 unsigned char *pucIn = &dataIn[ (y >> 1) + inOffset]; 168 169 for( int xz = 0; xz < 128; xz++ ) // 128 ( 16 x 16 x 0.5 ) in loop as packing 2 values into each destination byte 170 { 171 *pucOut = ( ( *pucIn ) >> ( part * 4 ) ) & 15; 172 pucIn += 64; 173 174 *pucOut |= ( ( ( *pucIn ) >> ( part * 4 ) ) & 15 ) << 4; 175 pucIn += 64; 176 pucOut++; 177 } 178 } 179 } 180 181 // Get new data and count packed info 182#pragma warning ( disable : 4826 ) 183 __int64 newDataAndCount = ((__int64) planeIndices) & 0x0000ffffffffffffL; 184#pragma warning ( default : 4826 ) 185 newDataAndCount |= ((__int64)allocatedPlaneCount) << 48; 186 187 updateDataAndCount( newDataAndCount ); 188} 189 190// Gets all lighting values into an array of length 16384. Destination data will have same order as original java game. 191void SparseLightStorage::getData(byteArray retArray, unsigned int retOffset) 192{ 193 XMemSet(retArray.data + retOffset, 0, 16384); 194 unsigned char *planeIndices, *data; 195 getPlaneIndicesAndData(&planeIndices, &data); 196 197 // Original order is defined as: 198 // pos = (x << 11 | z << 7 | y); 199 // slot = pos >> 1; 200 // part = pos & 1; 201 // if ( part == 0 ) value = data[slot] & 0xf 202 // else value = (data[slot] >> 4) & 0xf 203 204 for( int y = 0; y < 128; y++ ) 205 { 206 if( planeIndices[y] == ALL_0_INDEX ) 207 { 208 // No need to do anything in this case as retArray is initialised to zero 209 } 210 else if( planeIndices[y] == ALL_15_INDEX ) 211 { 212 int part = y & 1; 213 unsigned char value = 15 << ( part * 4 ); 214 unsigned char *pucOut = &retArray.data[ (y >> 1) + retOffset]; 215 for( int xz = 0; xz < 256; xz++ ) 216 { 217 *pucOut |= value; 218 pucOut += 64; 219 } 220 } 221 else 222 { 223 int part = y & 1; 224 int shift = 4 * part; 225 unsigned char *pucOut = &retArray.data[ (y >> 1) + retOffset]; 226 unsigned char *pucIn = &data[ planeIndices[ y ] * 128 ]; 227 for( int xz = 0; xz < 128; xz++ ) // 128 in loop (16 x 16 x 0.5) as input data is being treated in pairs of nybbles that are packed in the same byte 228 { 229 unsigned char value = (*pucIn) & 15; 230 *pucOut |= ( value << shift ); 231 pucOut += 64; 232 233 value = ((*pucIn) >> 4 ) & 15; 234 *pucOut |= ( value << shift ); 235 pucOut += 64; 236 237 pucIn++; 238 } 239 } 240 } 241} 242 243// Get an individual lighting value 244int SparseLightStorage::get(int x, int y, int z) 245{ 246 unsigned char *planeIndices, *data; 247 getPlaneIndicesAndData(&planeIndices, &data); 248 249 if( planeIndices[y] == ALL_0_INDEX ) 250 { 251 return 0; 252 } 253 else if ( planeIndices[y] == ALL_15_INDEX ) 254 { 255 return 15; 256 } 257 else 258 { 259 int planeIndex = x * 16 + z; // Index within this xz plane 260 int byteIndex = planeIndex / 2; // Byte index within the plane (2 tiles stored per byte) 261 int shift = ( planeIndex & 1 ) * 4; // Bit shift within the byte 262 int retval = ( data[ planeIndices[y] * 128 + byteIndex ] >> shift ) & 15; 263 264 return retval; 265 } 266} 267 268// Set an individual lighting value 269void SparseLightStorage::set(int x, int y, int z, int val) 270{ 271 unsigned char *planeIndices, *data; 272 getPlaneIndicesAndData(&planeIndices, &data); 273 274 // If this plane isn't yet allocated, then we might have some extra work to do 275 if( planeIndices[y] >= ALL_0_INDEX ) 276 { 277 // No data allocated. Early out though if we are storing what is already represented by our special index. 278 if( ( val == 0 ) && ( planeIndices[y] == ALL_0_INDEX ) ) 279 { 280 return; 281 } 282 if( ( val == 15 ) && ( planeIndices[y] == ALL_15_INDEX ) ) 283 { 284 return; 285 } 286 287 // Reallocate the storage for planes to accomodate one extra 288 addNewPlane(y); 289 290 // Get pointers again as these may have moved 291 getPlaneIndicesAndData(&planeIndices, &data); 292 } 293 294 // Either data was already allocated, or we've just done that. Now store our value into the right place. 295 296 int planeIndex = x * 16 + z; // Index within this xz plane 297 int byteIndex = planeIndex / 2; // Byte index within the plane (2 tiles stored per byte) 298 int shift = ( planeIndex & 1 ) * 4; // Bit shift within the byte 299 int mask = 0xf0 >> shift; 300 301 int idx = planeIndices[y] * 128 + byteIndex; 302 data[idx] = ( data[idx] & mask ) | ( val << shift ); 303 304} 305 306void SparseLightStorage::setAllBright() 307{ 308 unsigned char *planeIndices = (unsigned char *)malloc(128); 309 for( int i = 0; i < 128; i++ ) 310 { 311 planeIndices[i] = ALL_15_INDEX; 312 } 313 // Data and count packs together the pointer to our data and the count of planes allocated, which is currently zero 314#pragma warning ( disable : 4826 ) 315 __int64 newDataAndCount = ( (__int64) planeIndices ) & 0x0000ffffffffffffL; 316#pragma warning ( default : 4826 ) 317 318 updateDataAndCount( newDataAndCount ); 319} 320 321// Sets a region of lighting values with the data at offset position in the array dataIn - external ordering compatible with java DataLayer 322// Note - when data was extracted from the original data layers by LevelChunk::getBlocksAndData, y0 had to have even alignment and y1 - y0 also 323// needed to be even as data was packed in nyblles in this dimension, and the code didn't make any attempt to unpack it. This behaviour is copied 324// here for compatibility even though our source data isn't packed this way. 325// Returns size of data copied. 326int SparseLightStorage::setDataRegion(byteArray dataIn, int x0, int y0, int z0, int x1, int y1, int z1, int offset) 327{ 328 // Actual setting of data happens when calling set method so no need to lock here 329 unsigned char *pucIn = &dataIn.data[offset]; 330 for( int x = x0; x < x1; x++ ) 331 { 332 for( int z = z0; z < z1; z++ ) 333 { 334 // Emulate how data was extracted from DataLayer... see comment above 335 int yy0 = y0 & 0xfffffffe; 336 int len = ( y1 - y0 ) / 2; 337 for( int i = 0; i < len; i++ ) 338 { 339 int y = yy0 + ( i * 2 ); 340 341 set(x, y, z, (*pucIn) & 15 ); 342 set(x, y + 1, z, ((*pucIn) >> 4 ) & 15 ); 343 pucIn++; 344 } 345 } 346 } 347 ptrdiff_t count = pucIn - &dataIn.data[offset]; 348 349 return (int)count; 350} 351 352// Updates the data at offset position dataInOut with a region of lighting information - external ordering compatible with java DataLayer 353// Note - when data was placed in the original data layers by LevelChunk::setBlocksAndData, y0 had to have even alignment and y1 - y0 also 354// needed to be even as data was packed in nyblles in this dimension, and the code didn't make any attempt to unpack it. This behaviour is copied 355// here for compatibility even though our source data isn't packed this way 356// Returns size of data copied. 357int SparseLightStorage::getDataRegion(byteArray dataInOut, int x0, int y0, int z0, int x1, int y1, int z1, int offset) 358{ 359 unsigned char *pucOut = &dataInOut.data[offset]; 360 for( int x = x0; x < x1; x++ ) 361 { 362 for( int z = z0; z < z1; z++ ) 363 { 364 // Emulate how data was extracted from DataLayer... see comment above 365 int yy0 = y0 & 0xfffffffe; 366 int len = ( y1 - y0 ) / 2; 367 for( int i = 0; i < len; i++ ) 368 { 369 int y = yy0 + ( i * 2 ); 370 371 *pucOut = get( x, y, z); 372 *pucOut |= get( x, y + 1, z) << 4; 373 pucOut++; 374 } 375 } 376 } 377 ptrdiff_t count = pucOut - &dataInOut.data[offset]; 378 379 return (int)count; 380} 381 382void SparseLightStorage::addNewPlane(int y) 383{ 384 bool success = false; 385 do 386 { 387 // Get last packed data pointer & count 388 __int64 lastDataAndCount = dataAndCount; 389 390 // Unpack count & data pointer 391 int lastLinesUsed = (int)(( lastDataAndCount >> 48 ) & 0xffff); 392 unsigned char *lastDataPointer = (unsigned char *)(lastDataAndCount & 0x0000ffffffffffff); 393 394 // Find out what to prefill the newly allocated line with 395 unsigned char planeIndex = lastDataPointer[y]; 396 int prefill = 0; 397 if( planeIndex < ALL_0_INDEX ) return; // Something has already allocated this line - we're done 398 else if( planeIndex == ALL_15_INDEX ) prefill = 255; 399 400 int linesUsed = lastLinesUsed + 1; 401 402 // Allocate new memory storage, copy over anything from old storage, and initialise remainder 403 unsigned char *dataPointer = (unsigned char *)malloc(linesUsed * 128 + 128); 404 XMemCpy( dataPointer, lastDataPointer, 128 * lastLinesUsed + 128); 405 XMemSet( dataPointer + ( 128 * lastLinesUsed ) + 128, prefill, 128 ); 406 dataPointer[y] = lastLinesUsed; 407 408 // Get new data and count packed info 409#pragma warning ( disable : 4826 ) 410 __int64 newDataAndCount = ((__int64) dataPointer) & 0x0000ffffffffffffL; 411#pragma warning ( default : 4826 ) 412 newDataAndCount |= ((__int64)linesUsed) << 48; 413 414 // Attempt to update the data & count atomically. This command will Only succeed if the data stored at 415 // dataAndCount is equal to lastDataAndCount, and will return the value present just before the write took place 416 __int64 lastDataAndCount2 = InterlockedCompareExchangeRelease64( &dataAndCount, newDataAndCount, lastDataAndCount ); 417 418 if( lastDataAndCount2 == lastDataAndCount ) 419 { 420 success = true; 421 // Queue old data to be deleted 422 queueForDelete( lastDataPointer ); 423// printf("Marking for delete 0x%x\n", lastDataPointer); 424#ifdef LIGHT_COMPRESSION_STATS 425 count = linesUsed; 426#endif 427 } 428 else 429 { 430 // If we didn't succeed, queue data that we made to be deleted, and try again 431 queueForDelete( dataPointer ); 432// printf("Marking for delete (fail) 0x%x\n", dataPointer); 433 } 434 } while( !success ); 435} 436 437void SparseLightStorage::getPlaneIndicesAndData(unsigned char **planeIndices, unsigned char **data) 438{ 439 unsigned char *indicesAndData = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); 440 441 *planeIndices = indicesAndData; 442 *data = indicesAndData + 128; 443 444} 445 446void SparseLightStorage::queueForDelete(unsigned char *data) 447{ 448 // Add this into a queue for deleting. This shouldn't be actually deleted until tick has been called twice from when 449 // the data went into the queue. 450 deleteQueue[deleteQueueIndex].Push( data ); 451} 452 453void SparseLightStorage::tick() 454{ 455 // We have 3 queues for deleting. Always delete from the next one after where we are writing to, so it should take 2 ticks 456 // before we ever delete something, from when the request to delete it came in 457 int freeIndex = ( deleteQueueIndex + 1 ) % 3; 458 459// printf("Free queue: %d, %d\n",deleteQueue[freeIndex].GetEntryCount(),deleteQueue[freeIndex].GetAllocated()); 460 unsigned char *toFree = NULL; 461 do 462 { 463 toFree = deleteQueue[freeIndex].Pop(); 464// if( toFree ) printf("Deleting 0x%x\n", toFree); 465 // Determine correct means to free this data - could have been allocated either with XPhysicalAlloc or malloc 466#ifdef _XBOX 467 if( (unsigned int)toFree >= MM_PHYSICAL_4KB_BASE ) 468 { 469 XPhysicalFree(toFree); 470 } 471 else 472#endif 473 { 474 free(toFree); 475 } 476 } while( toFree ); 477 478 deleteQueueIndex = ( deleteQueueIndex + 1 ) % 3; 479} 480 481// Update storage with a new values for dataAndCount, repeating as necessary if other simultaneous writes happen. 482void SparseLightStorage::updateDataAndCount(__int64 newDataAndCount) 483{ 484 // Now actually assign this data to the storage. Just repeat until successful, there isn't any useful really that we can merge the results of this 485 // with any other simultaneous writes that might be happening. 486 bool success = false; 487 do 488 { 489 __int64 lastDataAndCount = dataAndCount; 490 unsigned char *lastDataPointer = (unsigned char *)(lastDataAndCount & 0x0000ffffffffffff); 491 492 // Attempt to update the data & count atomically. This command will Only succeed if the data stored at 493 // dataAndCount is equal to lastDataAndCount, and will return the value present just before the write took place 494 __int64 lastDataAndCount2 = InterlockedCompareExchangeRelease64( &dataAndCount, newDataAndCount, lastDataAndCount ); 495 496 if( lastDataAndCount2 == lastDataAndCount ) 497 { 498 success = true; 499 // Queue old data to be deleted 500// printf("Marking for delete 0x%x (full replace)\n", lastDataPointer); 501 queueForDelete( lastDataPointer ); 502 } 503 } while( !success); 504 505#ifdef LIGHT_COMPRESSION_STATS 506 count = ( newDataAndCount >> 48 ) & 0xffff; 507#endif 508 509} 510 511// Attempt to compress the stored data. This method makes no guarantee of success - if it fails due to something else writing to the storage whilst this is running, then it won't actually do anything. 512int SparseLightStorage::compress() 513{ 514 unsigned char _planeIndices[128]; 515 bool needsCompressed = false; 516 517 __int64 lastDataAndCount = dataAndCount; 518 519 unsigned char *planeIndices = (unsigned char *)(lastDataAndCount & 0x0000ffffffffffff); 520 unsigned char *data = planeIndices + 128; 521 522 int planesToAlloc = 0; 523 for( int i = 0; i < 128; i++ ) 524 { 525 if( planeIndices[i] == ALL_0_INDEX ) 526 { 527 _planeIndices[i] = ALL_0_INDEX; 528 } 529 else if( planeIndices[i] == ALL_15_INDEX ) 530 { 531 _planeIndices[i] = ALL_15_INDEX; 532 } 533 else 534 { 535 unsigned char *pucData = &data[ 128 * planeIndices[i] ]; 536 bool all0 = true; 537 bool all15 = true; 538 for( int j = 0; j < 128; j++ ) // 16 x 16 x 4-bits 539 { 540 if( *pucData != 0 ) all0 = false; 541 if( *pucData != 255 ) all15 = false; 542 pucData++; 543 } 544 if( all0 ) 545 { 546 _planeIndices[i] = ALL_0_INDEX; 547 needsCompressed = true; 548 } 549 else if ( all15 ) 550 { 551 _planeIndices[i] = ALL_15_INDEX; 552 needsCompressed = true; 553 } 554 else 555 { 556 _planeIndices[i] = planesToAlloc++; 557 } 558 } 559 } 560 561 if( needsCompressed ) 562 { 563 unsigned char *newIndicesAndData = (unsigned char *)malloc( 128 + 128 * planesToAlloc ); 564 unsigned char *pucData = newIndicesAndData + 128; 565 XMemCpy( newIndicesAndData, _planeIndices, 128 ); 566 567 for( int i = 0; i < 128; i++ ) 568 { 569 if( newIndicesAndData[i] < ALL_0_INDEX ) 570 { 571 XMemCpy( pucData, &data[ 128 * planeIndices[i] ], 128 ); 572 pucData += 128; 573 } 574 } 575 576 // Get new data and count packed info 577#pragma warning ( disable : 4826 ) 578 __int64 newDataAndCount = ((__int64) newIndicesAndData) & 0x0000ffffffffffffL; 579#pragma warning ( default : 4826 ) 580 newDataAndCount |= ((__int64)planesToAlloc) << 48; 581 582 // Attempt to update the data & count atomically. This command will Only succeed if the data stored at 583 // dataAndCount is equal to lastDataAndCount, and will return the value present just before the write took place 584 __int64 lastDataAndCount2 = InterlockedCompareExchangeRelease64( &dataAndCount, newDataAndCount, lastDataAndCount ); 585 586 if( lastDataAndCount2 != lastDataAndCount ) 587 { 588 // Failed to write. Don't bother trying again... being very conservative here. 589// printf("Marking for delete 0x%x (compress fail)\n", newIndicesAndData); 590 queueForDelete( newIndicesAndData ); 591 } 592 else 593 { 594 // Success 595 queueForDelete( planeIndices ); 596// printf("Successfully compressed to %d planes, to delete 0x%x\n", planesToAlloc, planeIndices); 597#ifdef LIGHT_COMPRESSION_STATS 598 count = planesToAlloc; 599#endif 600 } 601 602 return planesToAlloc; 603 } 604 else 605 { 606 return (int)((lastDataAndCount >> 48 ) & 0xffff); 607 } 608} 609 610 611bool SparseLightStorage::isCompressed() 612{ 613 614 int count = ( dataAndCount >> 48 ) & 0xffff; 615 return (count < 127); 616 617 618} 619 620void SparseLightStorage::write(DataOutputStream *dos) 621{ 622 int count = ( dataAndCount >> 48 ) & 0xffff; 623 dos->writeInt(count); 624 unsigned char *dataPointer = (unsigned char *)(dataAndCount & 0x0000ffffffffffff); 625 byteArray wrapper(dataPointer, count * 128 + 128); 626 dos->write(wrapper); 627} 628 629void SparseLightStorage::read(DataInputStream *dis) 630{ 631 int count = dis->readInt(); 632 unsigned char *dataPointer = (unsigned char *)malloc(count * 128 + 128); 633 byteArray wrapper(dataPointer, count * 128 + 128); 634 dis->readFully(wrapper); 635 636#pragma warning ( disable : 4826 ) 637 __int64 newDataAndCount = ((__int64) dataPointer) & 0x0000ffffffffffffL; 638#pragma warning ( default : 4826 ) 639 newDataAndCount |= ((__int64)count) << 48; 640 641 updateDataAndCount( newDataAndCount ); 642}