the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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}