1 #include "Draw.h"
2 
3 namespace Upp {
4 
5 enum
6 {
7 	MAXAA = 4,
8 
9 	MAP_COUNT   = 0,
10 	MAP_SEGMENT = 1,
11 	MAP_BLOCK   = 2,
12 	MAP_STEP    = 3,
13 	MAP_DATA    = 4,
14 };
15 
16 enum { LOG2_STRETCH_CURVE = 10, COUNT_STRETCH_CURVE = 1 << LOG2_STRETCH_CURVE };
17 
GetStretchCurve()18 static const byte *GetStretchCurve()
19 {
20 	static byte cache[COUNT_STRETCH_CURVE];
21 	ONCELOCK {
22 		for(int i = 0; i < COUNT_STRETCH_CURVE; i++)
23 		{
24 			enum { HALF = COUNT_STRETCH_CURVE >> 1 };
25 			double a = (i <= HALF ? i / double(HALF) : (COUNT_STRETCH_CURVE - i) / double(HALF));
26 			double o = pow(a, 0.85);
27 			cache[i] = minmax<int>((int)((i <= HALF ? o : 2 - o) * 128), 0, 255);
28 		}
29 	}
30 	return cache;
31 }
32 
AAGetMap(int & dmin,int & dmax,int dclipmin,int dclipmax,int smin,int smax,int sclipmin,int sclipmax,int times,int avail)33 Vector<dword> AAGetMap(int& dmin, int& dmax, int dclipmin, int dclipmax,
34 	                   int smin, int smax, int sclipmin, int sclipmax, int times, int avail)
35 {
36 	Vector<dword> map;
37 	if(dmax == dmin || smax == smin)
38 		return map;
39 	if(dmax < dmin)
40 	{
41 		Swap(dmin, dmax);
42 		Swap(smin, smax);
43 	}
44 	int dw = dmax - dmin, sw = smax - smin, spos;
45 	if(sw > 0)
46 	{
47 		int x0 = dmin;
48 		if(smin < sclipmin)
49 			x0 += iscalefloor(sclipmin - smin, dw, sw);
50 		if(x0 < dclipmin)
51 			x0 = dclipmin;
52 		spos = smin * dw + (x0 - dmin) * sw;
53 		dmin = x0;
54 		if(smax > sclipmax)
55 			dmax -= iscalefloor(smax - sclipmax, dw, sw);
56 		if(dmax > dclipmax)
57 			dmax = dclipmax;
58 	}
59 	else
60 	{
61 		int x0 = dmin;
62 		if(smin > sclipmax)
63 			x0 += iscalefloor(sclipmax - smin, dw, sw);
64 		if(x0 < dclipmin)
65 			x0 = dclipmin;
66 		spos = smin * dw + (x0 - dmin) * sw;
67 		dmin = x0;
68 		if(smax < sclipmin)
69 			dmax -= iscalefloor(smax - sclipmin, dw, sw);
70 		Swap(smin, smax);
71 	}
72 	int count = min(dclipmax, dmax) - dmin;
73 	if(smin < sclipmin)
74 		smin = sclipmin;
75 	if(smax > sclipmax)
76 		smax = sclipmax;
77 	if(smax <= smin || count <= 0)
78 		return map;
79 	int span = min(tabs(sw) % dw ? idivceil(tabs(sw), dw) + 1 : tabs(sw) / dw, smax - smin);
80 	bool bigseg = (span >= MAXAA);
81 	int segment = (bigseg ? MAXAA : span);
82 	int segstep = span / segment;
83 	map.SetCount(4 + count * (bigseg ? 1 : 1 + segment));
84 	map[MAP_COUNT] = dword(count);
85 	map[MAP_SEGMENT] = dword(segment);
86 	map[MAP_BLOCK] = 1 + (bigseg ? 0 : segment);
87 	map[MAP_STEP] = (span / segment) * times;
88 	dword *out = map.Begin() + MAP_DATA;
89 	int sendoffset = (smax - (segment - 1) * segstep - 1) * times;
90 	int last = 0;
91 
92 	if(smax - smin == 1)
93 	{
94 		ASSERT(segment == 1);
95 		dword dval = dword(smin * times);
96 		*out++ = dval;
97 		*out++ = avail;
98 		while(--count > 0)
99 		{
100 			*out++ = 0;
101 			*out++ = avail;
102 		}
103 	}
104 	else if(tabs(sw) >= dw)
105 	{ // size reduction
106 		int sbegin = smin * dw, send = smax * dw, aw = tabs(sw);
107 		for(spos += min(sw, 0); --count >= 0; spos += sw)
108 		{
109 			int pb = max(spos, sbegin), pe = min(spos + aw, send);
110 			int total = pe - pb, left = avail;
111 			int start = idivfloor(pb, dw), end = idivceil(pe, dw) - 1, rem = pb % dw;
112 //			DUMP(start);
113 //			DUMP(end);
114 			if(pb >= send)
115 			{
116 				last += *out++ = sendoffset - last;
117 				if(!bigseg)
118 				{
119 					int i = segment - 1;
120 					while(--i >= 0)
121 						*out++ = 0;
122 					*out++ = left;
123 				}
124 			}
125 			else if(end <= start)
126 			{ // 1 source pixel only
127 //				ASSERT(!bigseg);
128 				int scomp = minmax(start + segment - smax, 0, start - smin);
129 				last += *out++ = (start - scomp) * times - last;
130 				if(!bigseg)
131 				{
132 					int i = scomp;
133 					while(--i >= 0)
134 						*out++ = 0;
135 					*out++ = dword(left);
136 					i = segment - scomp - 1;
137 					while(--i >= 0)
138 						*out++ = 0;
139 				}
140 			}
141 			else
142 			{
143 				int delta = (dw - rem) * left / total;
144 				if(!delta)
145 					start++;
146 				int scomp = minmax(start + span - smax, 0, start - smin);
147 				last += *out++ = (start - scomp) * times - last;
148 				if(!bigseg)
149 				{
150 					int i = scomp;
151 					while(--i >= 0)
152 						*out++ = 0;
153 					i = segment - scomp;
154 					if(delta)
155 					{
156 						*out++ = delta;
157 						left -= delta;
158 						total -= dw - rem;
159 						i--;
160 					}
161 					while(++start < end)
162 					{
163 						ASSERT(i > 0);
164 						delta = dw * left / total;
165 						*out++ = delta;
166 						left -= delta;
167 						total -= dw;
168 						--i;
169 					}
170 					if(left > 0)
171 					{
172 						ASSERT(i > 0);
173 						*out++ = left;
174 						--i;
175 					}
176 					while(--i >= 0)
177 						*out++ = 0;
178 				}
179 			}
180 //			LOG("-> " << map[rec] << " + " << map[rec + 1]);
181 		}
182 	}
183 	else
184 	{ // size inflation
185 		static const byte *curve = GetStretchCurve();
186 		ASSERT(segment == 2 && !bigseg);
187 		int sbegin = smin * dw, send = (smax - 1) * dw;
188 		for(spos += (sw - dw) >> 1; --count >= 0; spos += sw)
189 		{
190 			if(spos <= sbegin)
191 			{
192 				last += out[0] = smin * times - last;
193 				out[1] = avail;
194 				out[2] = 0;
195 			}
196 			else if(spos >= send)
197 			{
198 				last += out[0] = sendoffset - last;
199 				out[1] = 0;
200 				out[2] = avail;
201 			}
202 			else
203 			{
204 				int pos = spos / dw;
205 				int rel = spos % dw;
206 				last += out[0] = pos * times - last;
207 				out[1] = avail - (out[2] = curve[rel * COUNT_STRETCH_CURVE / dw]);
208 			}
209 			out += 3;
210 		}
211 	}
212 
213 #ifdef _DEBUG
214 	ASSERT(out == map.End());
215 	int offs = 0, step = map[MAP_BLOCK], segspan = (map[MAP_SEGMENT] - 1) * map[MAP_STEP] + 1;
216 	for(int t = 0; t < (int)map[MAP_COUNT]; t++)
217 	{
218 		offs += map[MAP_DATA + t * step];
219 		ASSERT(offs >= times * smin && offs + segspan <= times * smax);
220 	}
221 #endif
222 
223 	return map;
224 }
225 
BltAAMapRGBA1(dword * dest,const RGBA * s,const dword * map)226 static void BltAAMapRGBA1(dword *dest, const RGBA *s, const dword *map)
227 {
228 	int count = map[MAP_COUNT];
229 	map += 4;
230 	while(count--) {
231 		s += map[0];
232 		dest[0] = s->b << 8;
233 		dest[1] = s->g << 8;
234 		dest[2] = s->r << 8;
235 		dest[3] = s->a << 8;
236 		map += 2;
237 		dest += 4;
238 	}
239 }
240 
BltAAMapRGBA2(dword * dest,const RGBA * s,const dword * map)241 static void BltAAMapRGBA2(dword *dest, const RGBA *s, const dword *map)
242 {
243 	int count = map[MAP_COUNT];
244 	map += 4;
245 	while(count--) {
246 		s += map[0];
247 		dest[0] = s[0].b * map[1] + s[1].b * map[2];
248 		dest[1] = s[0].g * map[1] + s[1].g * map[2];
249 		dest[2] = s[0].r * map[1] + s[1].r * map[2];
250 		dest[3] = s[0].a * map[1] + s[1].a * map[2];
251 		map += 3;
252 		dest += 4;
253 	}
254 }
255 
256 
BltAAMapRGBA3(dword * dest,const RGBA * s,const dword * map)257 static void BltAAMapRGBA3(dword *dest, const RGBA *s, const dword *map)
258 {
259 	int count = map[MAP_COUNT];
260 	map += 4;
261 	while(count--) {
262 		s += map[0];
263 		dest[0] = s[0].b * map[1] + s[1].b * map[2] + s[2].b * map[3];
264 		dest[1] = s[0].g * map[1] + s[1].g * map[2] + s[2].g * map[3];
265 		dest[2] = s[0].r * map[1] + s[1].r * map[2] + s[2].r * map[3];
266 		dest[3] = s[0].a * map[1] + s[1].a * map[2] + s[2].a * map[3];
267 		map += 4;
268 		dest += 4;
269 	}
270 }
271 
BltAAMapRGBA4(dword * dest,const RGBA * s,const dword * map)272 static void BltAAMapRGBA4(dword *dest, const RGBA *s, const dword *map)
273 {
274 	int step = map[MAP_STEP];
275 	int count = map[MAP_COUNT];
276 	map += 4;
277 	while(count--) {
278 		s += map[0];
279 		dest[0] = (s[0].b + s[step].b + s[2 * step].b + s[3 * step].b) << 6;
280 		dest[1] = (s[0].g + s[step].g + s[2 * step].g + s[3 * step].g) << 6;
281 		dest[2] = (s[0].r + s[step].r + s[2 * step].r + s[3 * step].r) << 6;
282 		dest[3] = (s[0].a + s[step].a + s[2 * step].a + s[3 * step].a) << 6;
283 		map += 1;
284 		dest += 4;
285 	}
286 }
287 
BltAASet2Fix(RGBA * dest,const dword * src1,dword w1,const dword * src2,dword w2,int count)288 void BltAASet2Fix(RGBA *dest, const dword *src1, dword w1, const dword *src2, dword w2, int count)
289 {
290 	while(count--) {
291 		dest->b = byte((src1[0] * w1 + src2[0] * w2) >> 16);
292 		dest->g = byte((src1[1] * w1 + src2[1] * w2) >> 16);
293 		dest->r = byte((src1[2] * w1 + src2[2] * w2) >> 16);
294 		dest->a = byte((src1[3] * w1 + src2[3] * w2) >> 16);
295 		dest++;
296 		src1 += 4;
297 		src2 += 4;
298 	}
299 }
300 
BltAASet3Fix(RGBA * dest,const dword * src1,dword w1,const dword * src2,dword w2,const dword * src3,dword w3,dword count)301 void BltAASet3Fix(RGBA *dest,
302                   const dword *src1, dword w1, const dword *src2, dword w2, const dword *src3, dword w3,
303                   dword count)
304 {
305 	while(count--) {
306 		dest->b = byte((src1[0] * w1 + src2[0] * w2 + src3[0] * w3) >> 16);
307 		dest->g = byte((src1[1] * w1 + src2[1] * w2 + src3[1] * w3) >> 16);
308 		dest->r = byte((src1[2] * w1 + src2[2] * w2 + src3[2] * w3) >> 16);
309 		dest->a = byte((src1[3] * w1 + src2[3] * w2 + src3[3] * w3) >> 16);
310 		dest++;
311 		src1 += 4;
312 		src2 += 4;
313 		src3 += 4;
314 	}
315 }
316 
BltAASet4Fix(RGBA * dest,const dword * src1,const dword * src2,const dword * src3,const dword * src4,int count)317 void BltAASet4Fix(RGBA *dest, const dword *src1, const dword *src2,
318                               const dword *src3, const dword *src4, int count)
319 {
320 	while(count--) {
321 		dest->b = byte((src1[0] + src2[0] + src3[0] + src4[0]) >> 10);
322 		dest->g = byte((src1[1] + src2[1] + src3[1] + src4[1]) >> 10);
323 		dest->r = byte((src1[2] + src2[2] + src3[2] + src4[2]) >> 10);
324 		dest->a = byte((src1[3] + src2[3] + src3[3] + src4[3]) >> 10);
325 		dest++;
326 		src1 += 4;
327 		src2 += 4;
328 		src3 += 4;
329 		src4 += 4;
330 	}
331 }
332 
BltAAFix2(RGBA * dest,const dword * src,int count)333 void BltAAFix2(RGBA *dest, const dword *src, int count)
334 {
335 #ifdef CPU_LITTLE_ENDIAN
336 	const byte *s = (byte *)src + 1;
337 #else
338 	const byte *s = (byte *)src + 2;
339 #endif
340 	while(count--) {
341 		dest->b = s[0];
342 		dest->g = s[4];
343 		dest->r = s[8];
344 		dest->a = s[12];
345 		dest++;
346 		s += 16;
347 	}
348 }
349 
Create(Size _tsz,Raster & _src,const Rect & src_rc)350 void RescaleImage::Create(Size _tsz, Raster& _src, const Rect& src_rc)
351 {
352 	y = -1;
353 	src = &_src;
354 	tsz = _tsz;
355 	if(tsz.cx == 0 || tsz.cy == 0)
356 		return;
357 
358 	size = src->GetSize();
359 
360 	Rect dr = tsz;
361 	horz = AAGetMap(dr.left, dr.right, dr.left, dr.right,
362 	                src_rc.left, src_rc.right, 0, size.cx, 1, 0x100);
363 	if(horz.IsEmpty())
364 		return;
365 
366 	vert = AAGetMap(dr.top, dr.bottom, dr.top, dr.bottom,
367 	                src_rc.top, src_rc.bottom, 0, size.cy, 1, 0x100);
368 	if(vert.IsEmpty())
369 		return;
370 
371 	switch(horz[MAP_SEGMENT]) {
372 	case 1:  row_proc = BltAAMapRGBA1; break;
373 	case 2:  row_proc = BltAAMapRGBA2; break;
374 	case 3:  row_proc = BltAAMapRGBA3; break;
375 	case 4:  row_proc = BltAAMapRGBA4; break;
376 	default: NEVER(); return;
377 	}
378 
379 	cx4 = 4 * tsz.cx;
380 	count = vert[MAP_COUNT];
381 	segment = vert[MAP_SEGMENT];
382 	entry = vert[MAP_BLOCK];
383 	step = vert[MAP_STEP];
384 	segspan = (segment - 1) * step + 1;
385 	bigseg = (segment == MAXAA);
386 	row_buffers.Alloc(cx4 * segment);
387 	first = vert[4];
388 	full = 0;
389 	offsets = vert.GetIter(4);
390 	offset = 0;
391 	y = 0;
392 	cii = 0;
393 	cache[0].ii = cache[1].ii = cache[2].ii = cache[3].ii = -1;
394 }
395 
GetLine(int ii)396 const RGBA *RescaleImage::GetLine(int ii)
397 {
398 	if(cache[0].ii == ii)
399 		return cache[0].line;
400 	if(cache[1].ii == ii)
401 		return cache[1].line;
402 	if(cache[2].ii == ii)
403 		return cache[2].line;
404 	if(cache[3].ii == ii)
405 		return cache[3].line;
406 	cache[cii].line = (*src)[ii];
407 	cache[cii].ii = ii;
408 	const RGBA *l = cache[cii].line;
409 	cii = (cii + 1) % 4;
410 	return l;
411 }
412 
Get(RGBA * tgt)413 void RescaleImage::Get(RGBA *tgt)
414 {
415 	if(y < 0 || offsets >= vert.End()) {
416 		memset(tgt, 0, sizeof(RGBA) * tsz.cx);
417 		return;
418 	}
419 	offset += *offsets++;
420 	ASSERT(offset >= 0 && offset + segspan <= size.cy);
421 	if(bigseg) {
422 		row_proc(&row_buffers[0 * cx4], GetLine(offset + 0 * step), horz);
423 		row_proc(&row_buffers[1 * cx4], GetLine(offset + 1 * step), horz);
424 		row_proc(&row_buffers[2 * cx4], GetLine(offset + 2 * step), horz);
425 		row_proc(&row_buffers[3 * cx4], GetLine(offset + 3 * step), horz);
426 		BltAASet4Fix(tgt, &row_buffers[0 * cx4], &row_buffers[1 * cx4],
427 			              &row_buffers[2 * cx4], &row_buffers[3 * cx4], tsz.cx);
428 	}
429 	else {
430 		int endoff = offset + segment;
431 		for(int next = first + full; next < endoff; next++) {
432 			if(full >= segment)
433 				first++;
434 			else
435 				full++;
436 			row_proc(&row_buffers[next % segment * cx4], GetLine(next), horz);
437 		}
438 		while(first > offset) {
439 			if(full < segment)
440 				full++;
441 			--first;
442 			row_proc(&row_buffers[first % segment * cx4], GetLine(first), horz);
443 		}
444 		ASSERT(offset >= first && endoff <= first + full);
445 		switch(segment) {
446 		case 1:
447 			BltAAFix2(tgt, &row_buffers[offset % segment * cx4], tsz.cx);
448 			offsets++;
449 			break;
450 		case 2:
451 			if(offsets[0] == 0)
452 				BltAAFix2(tgt, &row_buffers[(offset + 1) % segment * cx4], tsz.cx);
453 			else
454 			if(offsets[1] == 0)
455 				BltAAFix2(tgt, &row_buffers[offset % segment * cx4], tsz.cx);
456 			else
457 				BltAASet2Fix(tgt, &row_buffers[(offset + 0) % segment * cx4], offsets[0],
458 					              &row_buffers[(offset + 1) % segment * cx4], offsets[1],
459 					         tsz.cx);
460 			offsets += 2;
461 			break;
462 		case 3:
463 			BltAASet3Fix(tgt,
464 			             &row_buffers[(offset + 0) % segment * cx4], offsets[0],
465 			             &row_buffers[(offset + 1) % segment * cx4], offsets[1],
466 			             &row_buffers[(offset + 2) % segment * cx4], offsets[2], tsz.cx);
467 			offsets += 3;
468 			break;
469 		default:
470 			NEVER();
471 			break;
472 		}
473 	}
474 }
475 
Rescale(RasterEncoder & tgt,Size tsz,Raster & src,const Rect & src_rc,Gate<int,int> progress)476 bool Rescale(RasterEncoder& tgt, Size tsz, Raster& src, const Rect& src_rc,
477              Gate<int, int> progress)
478 {
479 	tgt.Create(tsz, src);
480 	RescaleImage rs;
481 	rs.Create(tsz, src, src_rc);
482 	for(int i = 0; i < tsz.cy; i++) {
483 		if(progress(i, tsz.cy))
484 			return false;
485 		rs.Get(tgt);
486 		tgt.WriteLine();
487 	}
488 	return true;
489 }
490 
Rescale(const Image & src,Size sz,const Rect & src_rc,Gate<int,int> progress)491 Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate<int, int> progress)
492 {
493 	if(src.GetSize() == sz && src_rc == sz)
494 		return src;
495 	ImageRaster isrc(src);
496 	ImageEncoder tgt;
497 	Rescale(tgt, sz, isrc, src_rc);
498 	return tgt;
499 }
500 
Rescale(const Image & src,Size sz,Gate<int,int> progress)501 Image Rescale(const Image& src, Size sz, Gate<int, int> progress)
502 {
503 	return Rescale(src, sz, src.GetSize(), progress);
504 }
505 
Rescale(const Image & src,int cx,int cy,Gate<int,int> progress)506 Image Rescale(const Image& src, int cx, int cy, Gate<int, int> progress)
507 {
508 	return Rescale(src, Size(cx, cy), progress);
509 }
510 
511 }
512