4 import iv
.glbinds
.utils
;
12 // ////////////////////////////////////////////////////////////////////////// //
14 just a 2d bitmap that keeps rgb colors.
15 there is also the code to find the biggest non-empty rectangle on the bitmap.
16 empty pixels are represented with zeroes.
18 the algorithm was taken from this SO topic: https://stackoverflow.com/questions/7245/
27 Pair
[] stack
; // stack
28 int top
; // top of stack
30 void push (int a
, int b
) nothrow @safe @nogc {
37 void pop (int *a
, int *b
) nothrow @safe @nogc {
45 int wdt
, hgt
; // dimension of input
47 uint[] ydotCount
; // for each y coord
52 delete cache
; cache
= null;
53 delete stack
; stack
= null;
54 delete grid
; grid
= null;
55 delete ydotCount
; ydotCount
= null;
56 wdt
= hgt
= dotCount
= 0;
60 void setSize (int awdt
, int ahgt
) {
61 if (awdt
< 1) awdt
= 0;
62 if (ahgt
< 1) ahgt
= 0;
65 if (grid
.length
< awdt
*ahgt
) grid
.length
= awdt
*ahgt
;
66 grid
[0..awdt
*ahgt
] = 0;
67 if (ydotCount
.length
< ahgt
) ydotCount
.length
= ahgt
;
68 ydotCount
[0..hgt
] = 0;
75 ydotCount
[0..hgt
] = 0;
80 void setPixel (int x
, int y
, uint rgb
) nothrow @trusted @nogc {
82 if (x
< 0 || y
< 0 || x
>= wdt || y
>= hgt
) return;
83 uint *cp
= grid
.ptr
+cast(uint)y
*cast(uint)wdt
+cast(uint)x
;
91 uint resetPixel (int x
, int y
) nothrow @trusted @nogc {
93 if (x
< 0 || y
< 0 || x
>= wdt || y
>= hgt
) return 0;
94 uint *cp
= grid
.ptr
+cast(uint)y
*cast(uint)wdt
+cast(uint)x
;
105 void updateCache (int currY
) nothrow @trusted @nogc {
107 for (int m = 0; m < wdt; ++m, ++cp) {
108 if (!grid[currY*wdt+m]) cache[m] = 0; else ++cache[m];
111 const(uint) *lp
= grid
.ptr
+cast(uint)currY
*cast(uint)wdt
;
113 for (int m
= wdt
; m
--; ++cp
) {
114 if (*lp
++) ++(*cp
); else *cp
= 0;
120 this is the slowest part of the conversion code.
122 bool doOne (int *rx0
, int *ry0
, int *rx1
, int *ry1
) nothrow @trusted {
123 if (dotCount
== 0) return false;
125 if (cache
.length
< wdt
+1) cache
.length
= wdt
+1;
126 if (stack
.length
< wdt
+1) stack
.length
= wdt
+1;
132 best_ll
.one
= best_ll
.two
= 0;
133 best_ur
.one
= best_ur
.two
= -1;
136 bool cacheCleared
= true;
138 for (int m
= 0; m
<= wdt
; ++m
) cache
[m
] = stack
[m
].one
= stack
[m
].two
= 0;
141 for (int n
= 0; n
< hgt
; ++n
) {
142 // there is no need to scan empty lines
143 // (and we usually have quite a lot of them)
144 if (ydotCount
[n
] == 0) {
153 cacheCleared
= false;
154 const(int) *cp
= cache
.ptr
;
155 for (int m
= 0; m
<= wdt
; ++m
) {
156 const int cvl
= *cp
++;
157 if (cvl
> openWidth
) {
158 // open new rectangle
161 } else if (cvl
< openWidth
) {
162 // close rectangle(s)
163 int m0
= void, w0
= void;
166 const int area
= openWidth
*(m
-m0
);
167 if (area
> best_area
) {
169 best_ll
.one
= m0
; best_ll
.two
= n
;
170 best_ur
.one
= m
-1; best_ur
.two
= n
-openWidth
+1;
173 } while (cvl
< openWidth
);
175 if (openWidth
!= 0) push(m0
, w0
);
180 *rx0
= (best_ll
.one
< best_ur
.one ? best_ll
.one
: best_ur
.one
);
181 *ry0
= (best_ll
.two
< best_ur
.two ? best_ll
.two
: best_ur
.two
);
182 *rx1
= (best_ll
.one
> best_ur
.one ? best_ll
.one
: best_ur
.one
);
183 *ry1
= (best_ll
.two
> best_ur
.two ? best_ll
.two
: best_ur
.two
);
187 for (int y = *ry0; y <= *ry1; ++y) {
188 for (int x = *rx0; x <= *rx1; ++x) {