1 module atlas.pixel_scan;
2 
3 import core.memory: pureCalloc, pureFree;
4 
5 void swap(T)(ref T a, ref T b) nothrow @nogc pure @safe{
6 	auto c = a;
7 	a = b;
8 	b = c;
9 }
10 
11 R[] packPixelScan(R)(scope return ref R[] rects, uint width, uint height) nothrow @nogc pure @safe{
12 	size_t nextFreeLen = width * height;
13 	size_t[] nextFree = (
14 		() @trusted => (
15 			cast(size_t*)pureCalloc(nextFreeLen, size_t.sizeof)
16 		)[0..nextFreeLen]
17 	)();
18 	scope(exit){
19 		() @trusted{
20 			pureFree(nextFree.ptr);
21 		}();
22 	}
23 	
24 	uint y;
25 	size_t i;
26 	size_t unpackedI;
27 	while(true){
28 		uint x;
29 		scanning: while(x+rects[i].w < width){
30 			if(y+rects[i].h >= height){
31 				if(++unpackedI >= rects.length){
32 					return rects[0..i];
33 				}
34 				swap(rects[i], rects[unpackedI]);
35 				x = 0;
36 				y = 0;
37 				continue scanning;
38 			}
39 			size_t scanI = x + (y * width);
40 			foreach(scanY; 0..rects[i].h){
41 				foreach(scanX; 0..rects[i].w){
42 					if(nextFree[scanI] != 0){
43 						x = cast(uint)(nextFree[scanI] % width);
44 						y = cast(uint)(nextFree[scanI] / width);
45 						continue scanning;
46 					}
47 					scanI++;
48 				}
49 				scanI -= rects[i].w; //move to first column
50 				scanI += width; //move to next row
51 			}
52 			size_t fillI = x + (y * width);
53 			foreach(fillY; 0..rects[i].h){
54 				nextFree[fillI..fillI+rects[i].w] = fillI+rects[i].w;
55 				fillI += width; //move to next row
56 			}
57 			rects[i].x = x;
58 			rects[i].y = y;
59 			rects[i].packed = true;
60 			
61 			x = 0;
62 			y = 0;
63 			i++;
64 			unpackedI++;
65 			if(i >= rects.length || unpackedI >= rects.length){
66 				return rects;
67 			}
68 		}
69 		y++;
70 	}
71 	assert(0);
72 }