1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/util.h"
24 #include "common/system.h"
25 #include "common/frac.h"
26 
27 #include "graphics/managed_surface.h"
28 #include "graphics/nine_patch.h"
29 
30 #include "gui/ThemeEngine.h"
31 #include "graphics/VectorRenderer.h"
32 #include "graphics/VectorRendererSpec.h"
33 
34 #define VECTOR_RENDERER_FAST_TRIANGLES
35 
36 /** Fixed point SQUARE ROOT **/
fp_sqroot(uint32 x)37 inline frac_t fp_sqroot(uint32 x) {
38 #if 0
39 	// Use the FPU to compute the square root and then convert it to fixed
40 	// point data. On systems with a fast FPU, this can be a lot faster than
41 	// the integer based code below - on my system roughly 50x! However, on
42 	// systems without an FPU, the converse might be true.
43 	// For now, we only use the integer based code.
44 	return doubleToFrac(sqrt((double)x));
45 #else
46 	// The code below wants to use a lot of registers, which is not good on
47 	// x86 processors. By taking advantage of the fact the the input value is
48 	// an integer, it might be possible to improve this. Furthermore, we could
49 	// take advantage of the fact that we call this function several times on
50 	// decreasing values. By feeding it the sqrt of the previous old x, as well
51 	// as the old x, it should be possible to compute the correct sqrt with far
52 	// fewer than 23 iterations.
53 	uint32 root, remHI, remLO, testDIV, count;
54 
55 	root = 0;
56 	remHI = 0;
57 	remLO = x << 16;
58 	count = 23;
59 
60 	do {
61 		remHI = (remHI << 2) | (remLO >> 30);
62 		remLO <<= 2;
63 		root <<= 1;
64 		testDIV = (root << 1) + 1;
65 
66 		if (remHI >= testDIV) {
67 			remHI -= testDIV;
68 			root++;
69 		}
70 	} while (count--);
71 
72 	return root;
73 #endif
74 }
75 
76 /*
77 	HELPER MACROS for Bresenham's circle drawing algorithm
78 	Note the proper spelling on this header.
79 */
80 #define BE_ALGORITHM() do { \
81 	if (f >= 0) { \
82 		y--; \
83 		ddF_y += 2; \
84 		f += ddF_y; \
85 		py -= pitch; \
86 	} \
87 	px += pitch; \
88 	ddF_x += 2; \
89 	f += ddF_x + 1; \
90 } while(0)
91 
92 #define BE_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py) do { \
93 	*(ptr1 + (y) - (px)) = color; \
94 	*(ptr1 + (x) - (py)) = color; \
95 	*(ptr2 - (x) - (py)) = color; \
96 	*(ptr2 - (y) - (px)) = color; \
97 } while (0)
98 
99 #define BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py) do { \
100 	*(ptr3 - (y) + (px)) = color; \
101 	*(ptr3 - (x) + (py)) = color; \
102 	*(ptr4 + (x) + (py)) = color; \
103 	*(ptr4 + (y) + (px)) = color; \
104 } while (0)
105 
106 #define BE_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
107 	BE_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py); \
108 	BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py); \
109 } while (0)
110 
111 #define BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
112 	if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
113 		*(ptr1 + (y) - (px)) = color; \
114 	if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
115 		*(ptr1 + (x) - (py)) = color; \
116 	if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
117 		*(ptr2 - (x) - (py)) = color; \
118 	if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
119 		*(ptr2 - (y) - (px)) = color; \
120 } while (0)
121 
122 #define BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
123 	if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
124 		*(ptr3 - (y) + (px)) = color; \
125 	if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
126 		*(ptr3 - (x) + (py)) = color; \
127 	if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
128 		*(ptr4 + (x) + (py)) = color; \
129 	if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
130 		*(ptr4 + (y) + (px)) = color; \
131 } while (0)
132 
133 #define BE_DRAWCIRCLE_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
134 	BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
135 	BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
136 } while (0)
137 
138 #define BE_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
139 	*(ptr1 + (y) - (px)) = color1; \
140 	*(ptr1 + (x) - (py)) = color1; \
141 	*(ptr2 - (x) - (py)) = color1; \
142 	*(ptr2 - (y) - (px)) = color1; \
143 	*(ptr3 - (y) + (px)) = color1; \
144 	*(ptr3 - (x) + (py)) = color1; \
145 	*(ptr4 + (x) + (py)) = color2; \
146 	*(ptr4 + (y) + (px)) = color2; \
147 } while (0)
148 
149 #define BE_DRAWCIRCLE_BCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
150 	if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
151 		*(ptr1 + (y) - (px)) = color1; \
152 	if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
153 		*(ptr1 + (x) - (py)) = color1; \
154 	if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
155 		*(ptr2 - (x) - (py)) = color1; \
156 	if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
157 		*(ptr2 - (y) - (px)) = color1; \
158 	if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
159 		*(ptr3 - (y) + (px)) = color1; \
160 	if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
161 		*(ptr3 - (x) + (py)) = color1; \
162 	if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
163 		*(ptr4 + (x) + (py)) = color2; \
164 	if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
165 		*(ptr4 + (y) + (px)) = color2; \
166 } while (0)
167 
168 #define BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \
169 	this->blendPixelPtr(ptr + (y) - (px), color, a); \
170 } while (0)
171 
172 #define BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr,x,y,px,py,a) do { \
173 	this->blendPixelPtr(ptr + (x) - (py), color, a); \
174 } while (0)
175 
176 #define BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
177 	if (IS_IN_CLIP((realX) + (y), (realY) - (x))) \
178 		this->blendPixelPtr(ptr + (y) - (px), color, a); \
179 } while (0)
180 
181 #define BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
182 	if (IS_IN_CLIP((realX) + (x), (realY) - (y))) \
183 		this->blendPixelPtr(ptr + (x) - (py), color, a); \
184 } while (0)
185 
186 #define BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \
187 	this->blendPixelPtr(ptr - (x) - (py), color, a); \
188 } while (0)
189 
190 #define BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr,x,y,px,py,a) do { \
191 	this->blendPixelPtr(ptr - (y) - (px), color, a); \
192 } while (0)
193 
194 #define BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
195 	if (IS_IN_CLIP((realX) - (x), (realY) - (y))) \
196 		this->blendPixelPtr(ptr - (x) - (py), color, a); \
197 } while (0)
198 
199 #define BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
200 	if (IS_IN_CLIP((realX) - (y), (realY) - (x))) \
201 		this->blendPixelPtr(ptr - (y) - (px), color, a); \
202 } while (0)
203 
204 #define BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \
205 	this->blendPixelPtr(ptr - (y) + (px), color, a); \
206 } while (0)
207 
208 #define BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr,x,y,px,py,a) do { \
209 	this->blendPixelPtr(ptr - (x) + (py), color, a); \
210 } while (0)
211 
212 #define BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
213 	if (IS_IN_CLIP((realX) - (y), (realY) + (x))) \
214 		this->blendPixelPtr(ptr - (y) + (px), color, a); \
215 } while (0)
216 
217 #define BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
218 	if (IS_IN_CLIP((realX) - (x), (realY) + (y))) \
219 		this->blendPixelPtr(ptr - (x) + (py), color, a); \
220 } while (0)
221 
222 #define BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \
223 	this->blendPixelPtr(ptr + (x) + (py), color, a); \
224 } while (0)
225 
226 #define BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr,x,y,px,py,a) do { \
227 	this->blendPixelPtr(ptr + (y) + (px), color, a); \
228 } while (0)
229 
230 #define BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
231 	if (IS_IN_CLIP((realX) + (x), (realY) + (y))) \
232 		this->blendPixelPtr(ptr + (x) + (py), color, a); \
233 } while (0)
234 
235 #define BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
236 	if (IS_IN_CLIP((realX) + (y), (realY) + (x))) \
237 		this->blendPixelPtr(ptr + (y) + (px), color, a); \
238 } while (0)
239 
240 #define BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py) do { \
241 	*(ptr1 + (y) - (px)) = color1; \
242 	*(ptr1 + (x) - (py)) = color2; \
243 	*(ptr2 - (x) - (py)) = color2; \
244 	*(ptr2 - (y) - (px)) = color1; \
245 } while (0)
246 
247 #define BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py) do { \
248 	*(ptr3 - (y) + (px)) = color3; \
249 	*(ptr3 - (x) + (py)) = color4; \
250 	*(ptr4 + (x) + (py)) = color4; \
251 	*(ptr4 + (y) + (px)) = color3; \
252 } while (0)
253 
254 #define BE_DRAWCIRCLE_XCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
255 	BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py); \
256 	BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py); \
257 } while (0)
258 
259 #define IS_IN_CLIP(x,y) (_clippingArea.left <= (x) && (x) < _clippingArea.right \
260 	&& _clippingArea.top <= (y) && (y) < _clippingArea.bottom)
261 
262 #define BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
263 	if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
264 		*(ptr1 + (y) - (px)) = color1; \
265 \
266 	if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
267 		*(ptr1 + (x) - (py)) = color2; \
268 \
269 	if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
270 		*(ptr2 - (x) - (py)) = color2; \
271 \
272 	if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
273 		*(ptr2 - (y) - (px)) = color1; \
274 } while (0)
275 
276 #define BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
277 	if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
278 		*(ptr3 - (y) + (px)) = color3; \
279 \
280 	if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
281 		*(ptr3 - (x) + (py)) = color4; \
282 \
283 	if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
284 		*(ptr4 + (x) + (py)) = color4; \
285 \
286 	if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
287 		*(ptr4 + (y) + (px)) = color3; \
288 } while (0)
289 
290 #define BE_DRAWCIRCLE_XCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
291 	BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
292 	BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
293 } while (0)
294 
295 
296 #define BE_RESET() do { \
297 	f = 1 - r; \
298 	ddF_x = 0; ddF_y = -2 * r; \
299 	x = 0; y = r; px = 0; py = pitch * r; \
300 } while (0)
301 
302 #define TRIANGLE_MAINX() \
303 		if (error_term >= 0) { \
304 			ptr_right += pitch; \
305 			ptr_left += pitch; \
306 			error_term += dysub; \
307 		} else { \
308 			error_term += ddy; \
309 		} \
310 		ptr_right++; \
311 		ptr_left--;
312 
313 #define TRIANGLE_MAINY() \
314 		if (error_term >= 0) { \
315 			ptr_right++; \
316 			ptr_left--; \
317 			error_term += dxsub; \
318 		} else { \
319 			error_term += ddx; \
320 		} \
321 		ptr_right += pitch; \
322 		ptr_left += pitch;
323 
324 /** HELPER MACROS for WU's circle drawing algorithm **/
325 #define WU_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py,a) do { \
326 	this->blendPixelPtr(ptr1 + (y) - (px), color, a); \
327 	this->blendPixelPtr(ptr1 + (x) - (py), color, a); \
328 	this->blendPixelPtr(ptr2 - (x) - (py), color, a); \
329 	this->blendPixelPtr(ptr2 - (y) - (px), color, a); \
330 } while (0)
331 
332 #define WU_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py,a) do { \
333 	this->blendPixelPtr(ptr3 - (y) + (px), color, a); \
334 	this->blendPixelPtr(ptr3 - (x) + (py), color, a); \
335 	this->blendPixelPtr(ptr4 + (x) + (py), color, a); \
336 	this->blendPixelPtr(ptr4 + (y) + (px), color, a); \
337 } while (0)
338 
339 #define WU_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a) do { \
340 	WU_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py,a); \
341 	WU_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py,a); \
342 } while (0)
343 
344 
345 // Color depending on y
346 // Note: this is only for the outer pixels
347 #define WU_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py,a,func) do { \
348 	this->func(ptr1 + (y) - (px), color1, a); \
349 	this->func(ptr1 + (x) - (py), color2, a); \
350 	this->func(ptr2 - (x) - (py), color2, a); \
351 	this->func(ptr2 - (y) - (px), color1, a); \
352 } while (0)
353 
354 #define WU_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py,a,func) do { \
355 	this->func(ptr3 - (y) + (px), color3, a); \
356 	this->func(ptr3 - (x) + (py), color4, a); \
357 	this->func(ptr4 + (x) + (py), color4, a); \
358 	this->func(ptr4 + (y) + (px), color3, a); \
359 } while (0)
360 
361 #define WU_DRAWCIRCLE_XCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a,func) do { \
362 	WU_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py,a,func); \
363 	WU_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py,a,func); \
364 } while (0)
365 
366 // Color depending on corner (tl,tr,bl: color1, br: color2)
367 // Note: this is only for the outer pixels
368 #define WU_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a) do { \
369 	this->blendPixelPtr(ptr1 + (y) - (px), color1, a); \
370 	this->blendPixelPtr(ptr1 + (x) - (py), color1, a); \
371 	this->blendPixelPtr(ptr2 - (x) - (py), color1, a); \
372 	this->blendPixelPtr(ptr2 - (y) - (px), color1, a); \
373 	this->blendPixelPtr(ptr3 - (y) + (px), color1, a); \
374 	this->blendPixelPtr(ptr3 - (x) + (py), color1, a); \
375 	this->blendPixelPtr(ptr4 + (x) + (py), color2, a); \
376 	this->blendPixelPtr(ptr4 + (y) + (px), color2, a); \
377 } while (0)
378 
379 #define WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \
380 	this->blendPixelPtr(ptr + (y) - (px), color, a); \
381 } while (0)
382 
383 #define WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr,x,y,px,py,a) do { \
384 	this->blendPixelPtr(ptr + (x) - (py), color, a); \
385 } while (0)
386 
387 #define WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \
388 	this->blendPixelPtr(ptr - (x) - (py), color, a); \
389 } while (0)
390 
391 #define WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr,x,y,px,py,a) do { \
392 	this->blendPixelPtr(ptr - (y) - (px), color, a); \
393 } while (0)
394 
395 #define WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \
396 	this->blendPixelPtr(ptr - (y) + (px), color, a); \
397 } while (0)
398 
399 #define WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr,x,y,px,py,a) do { \
400 	this->blendPixelPtr(ptr - (x) + (py), color, a); \
401 } while (0)
402 
403 #define WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \
404 	this->blendPixelPtr(ptr + (x) + (py), color, a); \
405 } while (0)
406 
407 #define WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr,x,y,px,py,a) do { \
408 	this->blendPixelPtr(ptr + (y) + (px), color, a); \
409 } while (0)
410 
411 // optimized Wu's algorithm
412 #define WU_ALGORITHM() do { \
413 	oldT = T; \
414 	T = fp_sqroot(rsq - y*y) ^ 0xFFFF; \
415 	py += pitch; \
416 	if (T < oldT) { \
417 		x--; px -= pitch; \
418 	} \
419 	a2 = (T >> 8); \
420 	a1 = ~a2; \
421 } while (0)
422 
423 
424 namespace Graphics {
425 
426 /**
427  * Fills several pixels in a row with a given color.
428  *
429  * This is a replacement function for Common::fill, using an unrolled
430  * loop to maximize performance on most architectures.
431  * This function may (and should) be overloaded in any child renderers
432  * for portable platforms with platform-specific assembly code.
433  *
434  * This fill operation is extensively used throughout the renderer, so this
435  * counts as one of the main bottlenecks. Please replace it with assembly
436  * when possible!
437  *
438  * @param first Pointer to the first pixel to fill.
439  * @param last Pointer to the last pixel to fill.
440  * @param color Color of the pixel
441  */
442 template<typename PixelType>
colorFill(PixelType * first,PixelType * last,PixelType color)443 void colorFill(PixelType *first, PixelType *last, PixelType color) {
444 	int count = (last - first);
445 	if (!count)
446 		return;
447 	int n = (count + 7) >> 3;
448 	switch (count % 8) {
449 	default:
450 	case 0:	do {
451 	       		*first++ = color; // fall through
452 	case 7:		*first++ = color; // fall through
453 	case 6:		*first++ = color; // fall through
454 	case 5:		*first++ = color; // fall through
455 	case 4:		*first++ = color; // fall through
456 	case 3:		*first++ = color; // fall through
457 	case 2:		*first++ = color; // fall through
458 	case 1:		*first++ = color;
459 	       	} while (--n > 0);
460 	}
461 }
462 
463 template<typename PixelType>
colorFillClip(PixelType * first,PixelType * last,PixelType color,int realX,int realY,Common::Rect & clippingArea)464 void colorFillClip(PixelType *first, PixelType *last, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
465 	if (realY < clippingArea.top || realY >= clippingArea.bottom)
466 		return;
467 
468 	int count = (last - first);
469 
470 	if (realX > clippingArea.right || realX + count < clippingArea.left)
471 		return;
472 
473 	if (realX < clippingArea.left) {
474 		int diff = (clippingArea.left - realX);
475 		realX += diff;
476 		first += diff;
477 		count -= diff;
478 	}
479 
480 	if (clippingArea.right <= realX + count) {
481 		int diff = (realX + count - clippingArea.right);
482 		count -= diff;
483 	}
484 
485 	if (!count)
486 		return;
487 
488 	int n = (count + 7) >> 3;
489 	switch (count % 8) {
490 	default:
491 	case 0:	do {
492 	       		*first++ = color; // fall through
493 	case 7:		*first++ = color; // fall through
494 	case 6:		*first++ = color; // fall through
495 	case 5:		*first++ = color; // fall through
496 	case 4:		*first++ = color; // fall through
497 	case 3:		*first++ = color; // fall through
498 	case 2:		*first++ = color; // fall through
499 	case 1:		*first++ = color;
500 	       	} while (--n > 0);
501 	}
502 }
503 
504 /**
505  * Fills several pixels in a column with a given color.
506  *
507  * @param first Pointer to the first pixel to fill.
508  * @param last Pointer to the last pixel to fill.
509  * @param pitch Number of pixels in a line.
510  * @param color Color of the pixel
511  */
512 template<typename PixelType>
colorVFill(PixelType * first,PixelType * last,int pitch,PixelType color)513 void colorVFill(PixelType *first, PixelType *last, int pitch, PixelType color) {
514 	int count = (last - first) / pitch;
515 	if (!count)
516 		return;
517 	for (PixelType *p = first; count; p+= pitch, count--) {
518 		*p = color;
519 	}
520 }
521 
522 template<typename PixelType>
colorVFillClip(PixelType * first,PixelType * last,int pitch,PixelType color,int realX,int realY,Common::Rect & clippingArea)523 void colorVFillClip(PixelType *first, PixelType *last, int pitch, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
524 	if (realX < clippingArea.left || realX >= clippingArea.right)
525 		return;
526 
527 	int count = (last - first) / pitch;
528 
529 	if (realY > clippingArea.bottom || realY + count < clippingArea.top)
530 		return;
531 
532 	if (realY < clippingArea.top) {
533 		int diff = (clippingArea.top - realY);
534 		realY += diff;
535 		first += diff * pitch;
536 		count -= diff;
537 	}
538 
539 	if (clippingArea.bottom <= realY + count) {
540 		int diff = (realY + count - clippingArea.bottom);
541 		count -= diff;
542 	}
543 
544 	if (!count)
545 		return;
546 
547 	for (PixelType *p = first; count; p+= pitch, count--) {
548 		*p = color;
549 	}
550 }
551 
552 
createRenderer(int mode)553 VectorRenderer *createRenderer(int mode) {
554 #ifdef DISABLE_FANCY_THEMES
555 	assert(mode == GUI::ThemeEngine::kGfxStandard);
556 #endif
557 
558 	PixelFormat format = g_system->getOverlayFormat();
559 	switch (mode) {
560 	case GUI::ThemeEngine::kGfxStandard:
561 		if (g_system->getOverlayFormat().bytesPerPixel == 4)
562 			return new VectorRendererSpec<uint32>(format);
563 		else if (g_system->getOverlayFormat().bytesPerPixel == 2)
564 			return new VectorRendererSpec<uint16>(format);
565 		break;
566 #ifndef DISABLE_FANCY_THEMES
567 	case GUI::ThemeEngine::kGfxAntialias:
568 		if (g_system->getOverlayFormat().bytesPerPixel == 4)
569 			return new VectorRendererAA<uint32>(format);
570 		else if (g_system->getOverlayFormat().bytesPerPixel == 2)
571 			return new VectorRendererAA<uint16>(format);
572 		break;
573 #endif
574 	default:
575 		break;
576 	}
577 
578 	return 0;
579 }
580 
581 template<typename PixelType>
582 VectorRendererSpec<PixelType>::
VectorRendererSpec(PixelFormat format)583 VectorRendererSpec(PixelFormat format) :
584 	_format(format),
585 	_redMask((0xFF >> format.rLoss) << format.rShift),
586 	_greenMask((0xFF >> format.gLoss) << format.gShift),
587 	_blueMask((0xFF >> format.bLoss) << format.bShift),
588 	_alphaMask((0xFF >> format.aLoss) << format.aShift) {
589 
590 	_bitmapAlphaColor = _format.RGBToColor(255, 0, 255);
591 	_clippingArea = Common::Rect(0, 0, 32767, 32767);
592 
593 	_fgColor = _bgColor = _bevelColor = 0;
594 	_gradientStart = _gradientEnd = 0;
595 }
596 
597 /****************************
598  * Gradient-related methods *
599  ****************************/
600 
601 template<typename PixelType>
602 void VectorRendererSpec<PixelType>::
setGradientColors(uint8 r1,uint8 g1,uint8 b1,uint8 r2,uint8 g2,uint8 b2)603 setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) {
604 	_gradientEnd = _format.RGBToColor(r2, g2, b2);
605 	_gradientStart = _format.RGBToColor(r1, g1, b1);
606 
607 	if (sizeof(PixelType) == 4) {
608 		_gradientBytes[0] = ((_gradientEnd & _redMask) >> _format.rShift) - ((_gradientStart & _redMask) >> _format.rShift);
609 		_gradientBytes[1] = ((_gradientEnd & _greenMask) >> _format.gShift) - ((_gradientStart & _greenMask) >> _format.gShift);
610 		_gradientBytes[2] = ((_gradientEnd & _blueMask) >> _format.bShift) - ((_gradientStart & _blueMask) >> _format.bShift);
611 	} else {
612 		_gradientBytes[0] = (_gradientEnd & _redMask) - (_gradientStart & _redMask);
613 		_gradientBytes[1] = (_gradientEnd & _greenMask) - (_gradientStart & _greenMask);
614 		_gradientBytes[2] = (_gradientEnd & _blueMask) - (_gradientStart & _blueMask);
615 	}
616 }
617 
618 template<typename PixelType>
619 inline PixelType VectorRendererSpec<PixelType>::
calcGradient(uint32 pos,uint32 max)620 calcGradient(uint32 pos, uint32 max) {
621 	PixelType output = 0;
622 	pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max;
623 
624 	if (sizeof(PixelType) == 4) {
625 		output |= ((_gradientStart & _redMask) + (((_gradientBytes[0] * pos) >> 12) << _format.rShift)) & _redMask;
626 		output |= ((_gradientStart & _greenMask) + (((_gradientBytes[1] * pos) >> 12) << _format.gShift)) & _greenMask;
627 		output |= ((_gradientStart & _blueMask) + (((_gradientBytes[2] * pos) >> 12) << _format.bShift)) & _blueMask;
628 	} else {
629 		output |= ((_gradientStart & _redMask) + ((_gradientBytes[0] * pos) >> 12)) & _redMask;
630 		output |= ((_gradientStart & _greenMask) + ((_gradientBytes[1] * pos) >> 12)) & _greenMask;
631 		output |= ((_gradientStart & _blueMask) + ((_gradientBytes[2] * pos) >> 12)) & _blueMask;
632 	}
633 	output |= _alphaMask;
634 
635 	return output;
636 }
637 
638 template<typename PixelType>
639 void VectorRendererSpec<PixelType>::
precalcGradient(int h)640 precalcGradient(int h) {
641 	PixelType prevcolor = 0, color;
642 
643 	_gradCache.resize(0);
644 	_gradIndexes.resize(0);
645 
646 	for (int i = 0; i < h + 2; i++) {
647 		color = calcGradient(i, h);
648 		if (color != prevcolor || i == 0 || i > h - 1) {
649 			prevcolor = color;
650 			_gradCache.push_back(color);
651 			_gradIndexes.push_back(i);
652 		}
653 	}
654 }
655 
656 template<typename PixelType>
657 void VectorRendererSpec<PixelType>::
gradientFill(PixelType * ptr,int width,int x,int y)658 gradientFill(PixelType *ptr, int width, int x, int y) {
659 	bool ox = ((y & 1) == 1);
660 	int curGrad = 0;
661 
662 	while (_gradIndexes[curGrad + 1] <= y)
663 		curGrad++;
664 
665 	// precalcGradient assures that _gradIndexes entries always differ in
666 	// their value. This assures stripSize is always different from zero.
667 	int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad];
668 
669 	int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
670 
671 	// Dithering:
672 	//   +--+ +--+ +--+ +--+
673 	//   |  | |  | | *| | *|
674 	//   |  | | *| |* | |**|
675 	//   +--+ +--+ +--+ +--+
676 	//     0    1    2    3
677 	if (grad == 0 ||
678 		_gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
679 		stripSize < 2) { // the stip is small
680 		colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]);
681 	} else if (grad == 3 && ox) {
682 		colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]);
683 	} else {
684 		for (int j = x; j < x + width; j++, ptr++) {
685 			bool oy = ((j & 1) == 1);
686 
687 			if ((ox && oy) ||
688 				((grad == 2 || grad == 3) && ox && !oy) ||
689 				(grad == 3 && oy))
690 				*ptr = _gradCache[curGrad + 1];
691 			else
692 				*ptr = _gradCache[curGrad];
693 		}
694 	}
695 }
696 
697 template<typename PixelType>
698 void VectorRendererSpec<PixelType>::
gradientFillClip(PixelType * ptr,int width,int x,int y,int realX,int realY)699 gradientFillClip(PixelType *ptr, int width, int x, int y, int realX, int realY) {
700 	if (realY < _clippingArea.top || realY >= _clippingArea.bottom) return;
701 	bool ox = ((y & 1) == 1);
702 	int curGrad = 0;
703 
704 	while (_gradIndexes[curGrad + 1] <= y)
705 		curGrad++;
706 
707 	// precalcGradient assures that _gradIndexes entries always differ in
708 	// their value. This assures stripSize is always different from zero.
709 	int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad];
710 
711 	int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
712 
713 	// Dithering:
714 	//   +--+ +--+ +--+ +--+
715 	//   |  | |  | | *| | *|
716 	//   |  | | *| |* | |**|
717 	//   +--+ +--+ +--+ +--+
718 	//     0    1    2    3
719 	if (grad == 0 ||
720 		_gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
721 		stripSize < 2) { // the stip is small
722 		colorFillClip<PixelType>(ptr, ptr + width, _gradCache[curGrad], realX, realY, _clippingArea);
723 	} else if (grad == 3 && ox) {
724 		colorFillClip<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1], realX, realY, _clippingArea);
725 	} else {
726 		for (int j = x; j < x + width; j++, ptr++) {
727 			if (realX + j - x < _clippingArea.left || realX + j - x >= _clippingArea.right) continue;
728 			bool oy = ((j & 1) == 1);
729 
730 			if ((ox && oy) ||
731 				((grad == 2 || grad == 3) && ox && !oy) ||
732 				(grad == 3 && oy))
733 				*ptr = _gradCache[curGrad + 1];
734 			else
735 				*ptr = _gradCache[curGrad];
736 		}
737 	}
738 }
739 
740 template<typename PixelType>
741 void VectorRendererSpec<PixelType>::
fillSurface()742 fillSurface() {
743 	Common::Rect drawRect(0, 0, _activeSurface->w, _activeSurface->h);
744 	drawRect.clip(_clippingArea);
745 
746 	if (drawRect.isEmpty()) {
747 		return;
748 	}
749 
750 	int h = _activeSurface->h;
751 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
752 
753 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, drawRect.top);
754 
755 	if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillForeground) {
756 		PixelType color = (Base::_fillMode == kFillBackground ? _bgColor : _fgColor);
757 		PixelType *ptrLeft = (ptr + drawRect.left), *ptrRight = ptr + drawRect.right;
758 		for (int i = drawRect.top; i < drawRect.bottom; i++) {
759 			colorFill<PixelType>(ptrLeft, ptrRight, color);
760 
761 			ptrLeft += pitch;
762 			ptrRight += pitch;
763 		}
764 
765 	} else if (Base::_fillMode == kFillGradient) {
766 		precalcGradient(h);
767 
768 		for (int i = drawRect.top; i < drawRect.bottom; i++) {
769 			gradientFill(ptr + drawRect.left, drawRect.width(), 0, i);
770 
771 			ptr += pitch;
772 		}
773 	}
774 }
775 
776 template<typename PixelType>
777 void VectorRendererSpec<PixelType>::
copyFrame(OSystem * sys,const Common::Rect & r)778 copyFrame(OSystem *sys, const Common::Rect &r) {
779 
780 	sys->copyRectToOverlay(
781 		_activeSurface->getBasePtr(r.left, r.top),
782 		_activeSurface->pitch,
783 	    r.left, r.top, r.width(), r.height()
784 	);
785 }
786 
787 template<typename PixelType>
788 void VectorRendererSpec<PixelType>::
blitSurface(const Graphics::ManagedSurface * source,const Common::Rect & r)789 blitSurface(const Graphics::ManagedSurface *source, const Common::Rect &r) {
790 	assert(source->w == _activeSurface->w && source->h == _activeSurface->h);
791 
792 	byte *dst_ptr = (byte *)_activeSurface->getBasePtr(r.left, r.top);
793 	const byte *src_ptr = (const byte *)source->getBasePtr(r.left, r.top);
794 
795 	const int dst_pitch = _activeSurface->pitch;
796 	const int src_pitch = source->pitch;
797 
798 	int h = r.height();
799 	const int w = r.width() * sizeof(PixelType);
800 
801 	while (h--) {
802 		memcpy(dst_ptr, src_ptr, w);
803 		dst_ptr += dst_pitch;
804 		src_ptr += src_pitch;
805 	}
806 }
807 
808 template<typename PixelType>
809 void VectorRendererSpec<PixelType>::
blitKeyBitmap(const Graphics::ManagedSurface * source,const Common::Point & p,bool themeTrans)810 blitKeyBitmap(const Graphics::ManagedSurface *source, const Common::Point &p, bool themeTrans) {
811 	Common::Rect drawRect(p.x, p.y, p.x + source->w, p.y + source->h);
812 	drawRect.clip(_clippingArea);
813 	drawRect.moveTo(0, 0);
814 
815 	if (drawRect.isEmpty()) {
816 		return;
817 	}
818 
819 	if (themeTrans)
820 		_activeSurface->transBlitFrom(*source, drawRect, p, _bitmapAlphaColor);
821 	else
822 		_activeSurface->blitFrom(*source, drawRect, p);
823 }
824 
825 template<typename PixelType>
826 void VectorRendererSpec<PixelType>::
applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle)827 applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) {
828 	int pixels = _activeSurface->w * _activeSurface->h;
829 	PixelType *ptr = (PixelType *)_activeSurface->getPixels();
830 	uint8 r, g, b;
831 	uint lum;
832 
833 	// Mask to clear the last bit of every color component and all unused bits
834 	const uint32 colorMask = ~((1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) // R/G/B components
835 			| (_format.aLoss == 8 ? 0 : (1 << _format.aShift)) // Alpha component
836 			| ~(_alphaMask | _redMask | _greenMask | _blueMask)); // All unused bits
837 
838 	if (shadingStyle == GUI::ThemeEngine::kShadingDim) {
839 
840 		// TODO: Check how this interacts with kFeatureOverlaySupportsAlpha
841 		for (int i = 0; i < pixels; ++i) {
842 			*ptr = ((*ptr & colorMask) >> 1) | _alphaMask;
843 			++ptr;
844 		}
845 
846 	} else if (shadingStyle == GUI::ThemeEngine::kShadingLuminance) {
847 		while (pixels--) {
848 			_format.colorToRGB(*ptr, r, g, b);
849 			lum = (r >> 2) + (g >> 1) + (b >> 3);
850 			*ptr++ = _format.RGBToColor(lum, lum, lum);
851 		}
852 	}
853 }
854 
855 template<typename PixelType>
856 inline void VectorRendererSpec<PixelType>::
blendPixelPtr(PixelType * ptr,PixelType color,uint8 alpha)857 blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) {
858 	if (alpha == 0xff) {
859 		// fully opaque pixel, don't blend
860 		*ptr = color | _alphaMask;
861 	} else if (sizeof(PixelType) == 4) {
862 		const byte sR = (color & _redMask) >> _format.rShift;
863 		const byte sG = (color & _greenMask) >> _format.gShift;
864 		const byte sB = (color & _blueMask) >> _format.bShift;
865 
866 		byte dR = (*ptr & _redMask) >> _format.rShift;
867 		byte dG = (*ptr & _greenMask) >> _format.gShift;
868 		byte dB = (*ptr & _blueMask) >> _format.bShift;
869 		byte dA = (*ptr & _alphaMask) >> _format.aShift;
870 
871 		dR += ((sR - dR) * alpha) >> 8;
872 		dG += ((sG - dG) * alpha) >> 8;
873 		dB += ((sB - dB) * alpha) >> 8;
874 		dA += ((0xff - dA) * alpha) >> 8;
875 
876 		*ptr = ((dR << _format.rShift) & _redMask)
877 		     | ((dG << _format.gShift) & _greenMask)
878 		     | ((dB << _format.bShift) & _blueMask)
879 		     | ((dA << _format.aShift) & _alphaMask);
880 	} else if (sizeof(PixelType) == 2) {
881 		int idst = *ptr;
882 		int isrc = color;
883 
884 		*ptr = (PixelType)(
885 			(_redMask & ((idst & _redMask) +
886 			((int)(((int)(isrc & _redMask) -
887 			(int)(idst & _redMask)) * alpha) >> 8))) |
888 			(_greenMask & ((idst & _greenMask) +
889 			((int)(((int)(isrc & _greenMask) -
890 			(int)(idst & _greenMask)) * alpha) >> 8))) |
891 			(_blueMask & ((idst & _blueMask) +
892 			((int)(((int)(isrc & _blueMask) -
893 			(int)(idst & _blueMask)) * alpha) >> 8))) |
894 			(_alphaMask & ((idst & _alphaMask) +
895 			((int)(((int)(_alphaMask) -
896 			(int)(idst & _alphaMask)) * alpha) >> 8))));
897 	} else {
898 		error("Unsupported BPP format: %u", (uint)sizeof(PixelType));
899 	}
900 }
901 
902 template<typename PixelType>
903 inline void VectorRendererSpec<PixelType>::
blendPixelPtrClip(PixelType * ptr,PixelType color,uint8 alpha,int x,int y)904 blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y) {
905 	if (IS_IN_CLIP(x, y))
906 		blendPixelPtr(ptr, color, alpha);
907 }
908 
909 template<typename PixelType>
910 inline void VectorRendererSpec<PixelType>::
blendPixelDestAlphaPtr(PixelType * ptr,PixelType color,uint8 alpha)911 blendPixelDestAlphaPtr(PixelType *ptr, PixelType color, uint8 alpha) {
912 	int idst = *ptr;
913 	// This function is only used for corner pixels in rounded rectangles, so
914 	// the performance hit of this if shouldn't be too high.
915 	// We're also ignoring the cases where dst has intermediate alpha.
916 	if ((idst & _alphaMask) == 0) {
917 		// set color and alpha channels
918 		*ptr = (PixelType)(color & (_redMask | _greenMask | _blueMask)) |
919 		                  ((alpha >> _format.aLoss) << _format.aShift);
920 	} else {
921 		// blend color with background
922 		blendPixelPtr(ptr, color, alpha);
923 	}
924 }
925 
926 template<typename PixelType>
927 inline void VectorRendererSpec<PixelType>::
darkenFill(PixelType * ptr,PixelType * end)928 darkenFill(PixelType *ptr, PixelType *end) {
929 	PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift));
930 
931 	if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
932 		// !kFeatureOverlaySupportsAlpha (but might have alpha bits)
933 
934 		while (ptr != end) {
935 			*ptr = ((*ptr & ~mask) >> 2) | _alphaMask;
936 			++ptr;
937 		}
938 	} else {
939 		// kFeatureOverlaySupportsAlpha
940 		// assuming at least 3 alpha bits
941 
942 		mask |= 3 << _format.aShift;
943 		PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss));
944 
945 		while (ptr != end) {
946 			// Darken the color, and increase the alpha
947 			// (0% -> 75%, 100% -> 100%)
948 			*ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA);
949 			++ptr;
950 		}
951 	}
952 }
953 
954 template<typename PixelType>
955 inline void VectorRendererSpec<PixelType>::
darkenFillClip(PixelType * ptr,PixelType * end,int x,int y)956 darkenFillClip(PixelType *ptr, PixelType *end, int x, int y) {
957 	PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift));
958 
959 	if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
960 		// !kFeatureOverlaySupportsAlpha (but might have alpha bits)
961 
962 		while (ptr != end) {
963 			if (IS_IN_CLIP(x, y)) *ptr = ((*ptr & ~mask) >> 2) | _alphaMask;
964 			++ptr;
965 			++x;
966 		}
967 	} else {
968 		// kFeatureOverlaySupportsAlpha
969 		// assuming at least 3 alpha bits
970 
971 		mask |= 3 << _format.aShift;
972 		PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss));
973 
974 		while (ptr != end) {
975 			// Darken the color, and increase the alpha
976 			// (0% -> 75%, 100% -> 100%)
977 			if (IS_IN_CLIP(x, y)) *ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA);
978 			++ptr;
979 			++x;
980 		}
981 	}
982 }
983 
984 /********************************************************************
985  ********************************************************************
986  * Primitive shapes drawing - Public API calls - VectorRendererSpec *
987  ********************************************************************
988  ********************************************************************/
989 template<typename PixelType>
990 void VectorRendererSpec<PixelType>::
drawString(const Graphics::Font * font,const Common::U32String & text,const Common::Rect & area,Graphics::TextAlign alignH,GUI::ThemeEngine::TextAlignVertical alignV,int deltax,bool ellipsis,const Common::Rect & textDrawableArea)991 drawString(const Graphics::Font *font, const Common::U32String &text, const Common::Rect &area,
992 			Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool ellipsis, const Common::Rect &textDrawableArea) {
993 
994 	int offset = area.top;
995 
996 	if (font->getFontHeight() < area.height()) {
997 		switch (alignV) {
998 		case GUI::ThemeEngine::kTextAlignVCenter:
999 			offset = area.top + ((area.height() - font->getFontHeight()) >> 1);
1000 			break;
1001 		case GUI::ThemeEngine::kTextAlignVBottom:
1002 			offset = area.bottom - font->getFontHeight();
1003 			break;
1004 		default:
1005 			break;
1006 		}
1007 	}
1008 
1009 	Common::Rect drawArea;
1010 	if (textDrawableArea.isEmpty()) {
1011 		// In case no special area to draw to is given we only draw in the
1012 		// area specified by the user.
1013 		drawArea = area;
1014 		// warning("there is no text drawable area. Please set this area for clipping");
1015 	} else {
1016 		// The area we can draw to is the intersection between the allowed
1017 		// drawing area (textDrawableArea) and the area where we try to draw
1018 		// the text (area).
1019 		drawArea = textDrawableArea.findIntersectingRect(area);
1020 	}
1021 
1022 	// Better safe than sorry. We intersect with the actual surface boundaries
1023 	// to avoid any ugly clipping in _activeSurface->getSubArea which messes
1024 	// up the calculation of the x and y coordinates where to draw the string.
1025 	drawArea = drawArea.findIntersectingRect(Common::Rect(0, 0, _activeSurface->w, _activeSurface->h));
1026 
1027 	if (!drawArea.isEmpty()) {
1028 		Common::Rect textArea(area);
1029 		textArea.right -= deltax;
1030 
1031 		Surface textAreaSurface = _activeSurface->getSubArea(drawArea);
1032 
1033 		if (deltax >= 0) {
1034 			textArea.left += deltax;
1035 			deltax = 0;
1036 		}
1037 
1038 		font->drawString(&textAreaSurface, text, textArea.left - drawArea.left, offset - drawArea.top, textArea.width(), _fgColor, alignH, deltax, ellipsis);
1039 	}
1040 }
1041 
1042 template<typename PixelType>
1043 void VectorRendererSpec<PixelType>::
drawLine(int x1,int y1,int x2,int y2)1044 drawLine(int x1, int y1, int x2, int y2) {
1045 	x1 = CLIP(x1, 0, (int)Base::_activeSurface->w);
1046 	x2 = CLIP(x2, 0, (int)Base::_activeSurface->w);
1047 	y1 = CLIP(y1, 0, (int)Base::_activeSurface->h);
1048 	y2 = CLIP(y2, 0, (int)Base::_activeSurface->h);
1049 
1050 	// we draw from top to bottom
1051 	if (y2 < y1) {
1052 		SWAP(x1, x2);
1053 		SWAP(y1, y2);
1054 	}
1055 
1056 	uint dx = ABS(x2 - x1);
1057 	uint dy = ABS(y2 - y1);
1058 
1059 	// this is a point, not a line. stoopid.
1060 	if (dy == 0 && dx == 0)
1061 		return;
1062 
1063 	if (Base::_strokeWidth == 0)
1064 		return;
1065 
1066 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
1067 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1068 	int st = Base::_strokeWidth >> 1;
1069 
1070 	bool useClippingVersions = !_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2);
1071 
1072 	int ptr_x = x1, ptr_y = y1;
1073 
1074 	if (dy == 0) { // horizontal lines
1075 		if (useClippingVersions) {
1076 			colorFillClip<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor, x1, y1, _clippingArea);
1077 		} else {
1078 			colorFill<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor);
1079 		}
1080 
1081 		for (int i = 0, p = pitch; i < st; ++i, p += pitch) {
1082 			if (useClippingVersions) {
1083 				colorFillClip<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor, x1, y1 + p/pitch, _clippingArea);
1084 				colorFillClip<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor, x1, y1 - p/pitch, _clippingArea);
1085 			} else {
1086 				colorFill<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor);
1087 				colorFill<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor);
1088 			}
1089 		}
1090 
1091 	} else if (dx == 0) { // vertical lines
1092 						  // these ones use a static pitch increase.
1093 		while (y1++ <= y2) {
1094 			if (useClippingVersions) {
1095 				colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, x1 - st, ptr_y, _clippingArea);
1096 			} else {
1097 				colorFill<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor);
1098 			}
1099 			ptr += pitch;
1100 			++ptr_y;
1101 		}
1102 
1103 	} else if (dx == dy) { // diagonal lines
1104 						   // these ones also use a fixed pitch increase
1105 		pitch += (x2 > x1) ? 1 : -1;
1106 
1107 		while (dy--) {
1108 			if (useClippingVersions) {
1109 				colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, ptr_x - st, ptr_y, _clippingArea);
1110 			} else {
1111 				colorFill<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor);
1112 			}
1113 			ptr += pitch;
1114 			++ptr_y;
1115 			if (x2 > x1) ++ptr_x; else --ptr_x;
1116 		}
1117 
1118 	} else { // generic lines, use the standard algorithm...
1119 		if (useClippingVersions) {
1120 			drawLineAlgClip(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
1121 		} else {
1122 			drawLineAlg(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
1123 		}
1124 	}
1125 }
1126 
1127 /** CIRCLES **/
1128 template<typename PixelType>
1129 void VectorRendererSpec<PixelType>::
drawCircle(int x,int y,int r)1130 drawCircle(int x, int y, int r) {
1131 	if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h ||
1132 		x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0)
1133 		return;
1134 
1135 	bool useClippingVersions = !_clippingArea.contains(Common::Rect(x - r, y - r, x + r, y + r));
1136 
1137 	if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
1138 		&& x + r + Base::_shadowOffset < Base::_activeSurface->w
1139 		&& y + r + Base::_shadowOffset < Base::_activeSurface->h) {
1140 		if (useClippingVersions)
1141 			drawCircleAlgClip(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
1142 		else
1143 			drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
1144 	}
1145 
1146 	switch (Base::_fillMode) {
1147 	case kFillDisabled:
1148 		if (Base::_strokeWidth) {
1149 			if (useClippingVersions)
1150 				drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
1151 			else
1152 				drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
1153 		}
1154 		break;
1155 
1156 	case kFillForeground:
1157 		if (useClippingVersions)
1158 			drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
1159 		else
1160 			drawCircleAlg(x, y, r, _fgColor, kFillForeground);
1161 		break;
1162 
1163 	case kFillBackground:
1164 		if (Base::_strokeWidth > 1) {
1165 			if (useClippingVersions) {
1166 				drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
1167 				drawCircleAlgClip(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
1168 			} else {
1169 				drawCircleAlg(x, y, r, _fgColor, kFillForeground);
1170 				drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
1171 			}
1172 		} else {
1173 			if (useClippingVersions) {
1174 				drawCircleAlgClip(x, y, r, _bgColor, kFillBackground);
1175 				drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
1176 			} else {
1177 				drawCircleAlg(x, y, r, _bgColor, kFillBackground);
1178 				drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
1179 			}
1180 		}
1181 		break;
1182 
1183 	case kFillGradient:
1184 		break;
1185 
1186 	default:
1187 		break;
1188 	}
1189 }
1190 
1191 /** SQUARES **/
1192 template<typename PixelType>
1193 void VectorRendererSpec<PixelType>::
drawSquare(int x,int y,int w,int h)1194 drawSquare(int x, int y, int w, int h) {
1195 	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
1196 		w <= 0 || h <= 0 || x < 0 || y < 0)
1197 		return;
1198 
1199 	bool useClippingVersions = !_clippingArea.contains(Common::Rect(x, y, x + w, y + h));
1200 
1201 	if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
1202 		&& x + w + Base::_shadowOffset < Base::_activeSurface->w
1203 		&& y + h + Base::_shadowOffset < Base::_activeSurface->h) {
1204 		if (useClippingVersions)
1205 			drawSquareShadowClip(x, y, w, h, Base::_shadowOffset);
1206 		else
1207 			drawSquareShadow(x, y, w, h, Base::_shadowOffset);
1208 	}
1209 
1210 	switch (Base::_fillMode) {
1211 	case kFillDisabled:
1212 		if (Base::_strokeWidth) {
1213 			if (useClippingVersions)
1214 				drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
1215 			else
1216 				drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
1217 		}
1218 		break;
1219 
1220 	case kFillForeground:
1221 		if (useClippingVersions)
1222 			drawSquareAlgClip(x, y, w, h, _fgColor, kFillForeground);
1223 		else
1224 			drawSquareAlg(x, y, w, h, _fgColor, kFillForeground);
1225 		break;
1226 
1227 	case kFillBackground:
1228 		if (useClippingVersions) {
1229 			drawSquareAlgClip(x, y, w, h, _bgColor, kFillBackground);
1230 			drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
1231 		} else {
1232 			drawSquareAlg(x, y, w, h, _bgColor, kFillBackground);
1233 			drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
1234 		}
1235 		break;
1236 
1237 	case kFillGradient:
1238 		VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient);
1239 		if (Base::_strokeWidth) {
1240 			if (useClippingVersions)
1241 				drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
1242 			else
1243 				drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
1244 		}
1245 		break;
1246 
1247 	default:
1248 		break;
1249 	}
1250 }
1251 
1252 /** ROUNDED SQUARES **/
1253 template<typename PixelType>
1254 void VectorRendererSpec<PixelType>::
drawRoundedSquare(int x,int y,int r,int w,int h)1255 drawRoundedSquare(int x, int y, int r, int w, int h) {
1256 	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
1257 		w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0)
1258 		return;
1259 
1260 	if ((r * 2) > w || (r * 2) > h)
1261 		r = MIN(w / 2, h / 2);
1262 
1263 	if (r <= 0)
1264 		return;
1265 
1266 	bool useOriginal = _clippingArea.contains(Common::Rect(x, y, x + w, y + h));
1267 
1268 	if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
1269 		&& x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w
1270 		&& y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h
1271 		&& h > (Base::_shadowOffset + 1) * 2) {
1272 		if (useOriginal) {
1273 			drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset);
1274 		} else {
1275 			drawRoundedSquareShadowClip(x, y, r, w, h, Base::_shadowOffset);
1276 		}
1277 	}
1278 
1279 	if (useOriginal) {
1280 		drawRoundedSquareAlg(x, y, r, w, h, _fgColor, Base::_fillMode);
1281 	} else {
1282 		drawRoundedSquareAlgClip(x, y, r, w, h, _fgColor, Base::_fillMode);
1283 	}
1284 }
1285 
1286 template<typename PixelType>
1287 void VectorRendererSpec<PixelType>::
drawTab(int x,int y,int r,int w,int h,int s)1288 drawTab(int x, int y, int r, int w, int h, int s) {
1289 	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
1290 		w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h)
1291 		return;
1292 
1293 	bool useClippingVersions = !_clippingArea.contains(Common::Rect(x, y, x + w, y + h));
1294 
1295 	if (r == 0 && Base::_bevel > 0) {
1296 		if (useClippingVersions)
1297 			drawBevelTabAlgClip(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
1298 		else
1299 			drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
1300 		return;
1301 	}
1302 
1303 	if (r == 0) {
1304 		return;
1305 	}
1306 
1307 	switch (Base::_fillMode) {
1308 	case kFillDisabled:
1309 		// FIXME: Implement this
1310 		return;
1311 
1312 	case kFillGradient:
1313 	case kFillBackground:
1314 		// FIXME: This is broken for the AA renderer.
1315 		// See the rounded rect alg for how to fix it. (The border should
1316 		// be drawn before the interior, both inside drawTabAlg.)
1317 		if (useClippingVersions) {
1318 			drawTabShadowClip(x, y, w - 2, h, r, s);
1319 			drawTabAlgClip(x, y, w - 2, h, r, _bgColor, Base::_fillMode);
1320 			if (Base::_strokeWidth)
1321 				drawTabAlgClip(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
1322 		} else {
1323 			drawTabShadow(x, y, w - 2, h, r, s);
1324 			drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode);
1325 			if (Base::_strokeWidth)
1326 				drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
1327 		}
1328 		break;
1329 
1330 	case kFillForeground:
1331 		if (useClippingVersions)
1332 			drawTabAlgClip(x, y, w, h, r, _fgColor, Base::_fillMode);
1333 		else
1334 			drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode);
1335 		break;
1336 
1337 	default:
1338 		break;
1339 	}
1340 }
1341 
1342 template<typename PixelType>
1343 void VectorRendererSpec<PixelType>::
drawTriangle(int x,int y,int w,int h,TriangleOrientation orient)1344 drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
1345 	if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
1346 		return;
1347 
1348 	PixelType color = 0;
1349 
1350 	if (Base::_strokeWidth <= 1) {
1351 		if (Base::_fillMode == kFillForeground)
1352 			color = _fgColor;
1353 		else if (Base::_fillMode == kFillBackground)
1354 			color = _bgColor;
1355 	} else {
1356 		if (Base::_fillMode == kFillDisabled)
1357 			return;
1358 		color = _fgColor;
1359 	}
1360 
1361 	if (Base::_dynamicData != 0)
1362 		orient = (TriangleOrientation)Base::_dynamicData;
1363 
1364 	bool useClippingVersions = !_clippingArea.contains(Common::Rect(x, y, x + w, y + h));
1365 
1366 	void (VectorRendererSpec<PixelType>::*drawFunc)(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) = nullptr;
1367 	bool inverted = false;
1368 
1369 	switch (orient) {
1370 	case kTriangleUp:
1371 	case kTriangleDown:
1372 		if (useClippingVersions)
1373 			drawFunc = &VectorRendererSpec<PixelType>::drawTriangleVertAlgClip;
1374 		else
1375 			drawFunc = &VectorRendererSpec<PixelType>::drawTriangleVertAlg;
1376 		inverted = (orient == kTriangleDown);
1377 		break;
1378 
1379 	case kTriangleLeft:
1380 	case kTriangleRight:
1381 		if (useClippingVersions)
1382 			drawFunc = &VectorRendererSpec<PixelType>::drawTriangleHorzAlgClip;
1383 		else
1384 			drawFunc = &VectorRendererSpec<PixelType>::drawTriangleHorzAlg;
1385 		inverted = (orient == kTriangleRight);
1386 		break;
1387 	case kTriangleAuto:
1388 	default:
1389 		break;
1390 	}
1391 
1392 	if (drawFunc) {
1393 		(this->*drawFunc)(x, y, w, h, inverted, color, Base::_fillMode);
1394 		if (Base::_strokeWidth > 0) {
1395 			if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
1396 				(this->*drawFunc)(x, y, w, h, inverted, _fgColor, kFillDisabled);
1397 			}
1398 		}
1399 	}
1400 }
1401 
1402 
1403 /********************************************************************
1404  ********************************************************************
1405  * Aliased Primitive drawing ALGORITHMS - VectorRendererSpec
1406  ********************************************************************
1407  ********************************************************************/
1408 /** TAB ALGORITHM - NON AA */
1409 template<typename PixelType>
1410 void VectorRendererSpec<PixelType>::
drawTabAlg(int x1,int y1,int w,int h,int r,PixelType color,VectorRenderer::FillMode fill_m,int baseLeft,int baseRight)1411 drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
1412 	// Don't draw anything for empty rects.
1413 	if (w <= 0 || h <= 0) {
1414 		return;
1415 	}
1416 
1417 	int f, ddF_x, ddF_y;
1418 	int x, y, px, py;
1419 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1420 	int sw  = 0, sp = 0, hp = 0;
1421 
1422 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
1423 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
1424 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
1425 
1426 	int real_radius = r;
1427 	int short_h = h - r;
1428 	int long_h = h;
1429 
1430 	if (fill_m == kFillDisabled) {
1431 		while (sw++ < Base::_strokeWidth) {
1432 			colorFill<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
1433 			colorFill<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
1434 			sp += pitch;
1435 
1436 			BE_RESET();
1437 			r--;
1438 
1439 			while (x++ < y) {
1440 				BE_ALGORITHM();
1441 				BE_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py);
1442 
1443 				if (Base::_strokeWidth > 1)
1444 					BE_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px - pitch, py);
1445 			}
1446 		}
1447 
1448 		ptr_fill += pitch * real_radius;
1449 		while (short_h--) {
1450 			colorFill<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color);
1451 			colorFill<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color);
1452 			ptr_fill += pitch;
1453 		}
1454 
1455 		if (baseLeft) {
1456 			sw = 0;
1457 			ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
1458 			while (sw++ < Base::_strokeWidth) {
1459 				colorFill<PixelType>(ptr_fill - baseLeft, ptr_fill, color);
1460 				ptr_fill += pitch;
1461 			}
1462 		}
1463 
1464 		if (baseRight) {
1465 			sw = 0;
1466 			ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
1467 			while (sw++ < Base::_strokeWidth) {
1468 				colorFill<PixelType>(ptr_fill, ptr_fill + baseRight, color);
1469 				ptr_fill += pitch;
1470 			}
1471 		}
1472 	} else {
1473 		BE_RESET();
1474 
1475 		precalcGradient(long_h);
1476 
1477 		PixelType color1, color2;
1478 		color1 = color2 = color;
1479 
1480 		while (x++ < y) {
1481 			BE_ALGORITHM();
1482 
1483 			if (fill_m == kFillGradient) {
1484 				color1 = calcGradient(real_radius - x, long_h);
1485 				color2 = calcGradient(real_radius - y, long_h);
1486 
1487 				gradientFill(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y);
1488 				gradientFill(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x);
1489 
1490 				BE_DRAWCIRCLE_XCOLOR_TOP(ptr_tr, ptr_tl, x, y, px, py);
1491 			} else {
1492 				colorFill<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color);
1493 				colorFill<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color);
1494 
1495 				BE_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py);
1496 			}
1497 		}
1498 
1499 		ptr_fill += pitch * r;
1500 		while (short_h--) {
1501 			if (fill_m == kFillGradient) {
1502 				gradientFill(ptr_fill, w + 1, x1, real_radius++);
1503 			} else {
1504 				colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color);
1505 			}
1506 			ptr_fill += pitch;
1507 		}
1508 	}
1509 }
1510 
1511 template<typename PixelType>
1512 void VectorRendererSpec<PixelType>::
drawTabAlgClip(int x1,int y1,int w,int h,int r,PixelType color,VectorRenderer::FillMode fill_m,int baseLeft,int baseRight)1513 drawTabAlgClip(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
1514 	// Don't draw anything for empty rects.
1515 	if (w <= 0 || h <= 0) {
1516 		return;
1517 	}
1518 
1519 	int f, ddF_x, ddF_y;
1520 	int x, y, px, py;
1521 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1522 	int sw = 0, sp = 0, hp = 0;
1523 
1524 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
1525 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
1526 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
1527 	int tl_x = x1 + r, tl_y = y1 + r;
1528 	int tr_x = x1 + w - r, tr_y = y1 + r;
1529 	int fill_x = x1, fill_y = y1;
1530 
1531 	int real_radius = r;
1532 	int short_h = h - r;
1533 	int long_h = h;
1534 
1535 	if (fill_m == kFillDisabled) {
1536 		while (sw++ < Base::_strokeWidth) {
1537 			colorFillClip<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, fill_x + r, fill_y + sp/pitch, _clippingArea);
1538 			colorFillClip<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, fill_x + r, fill_y + hp / pitch - sp / pitch, _clippingArea);
1539 			sp += pitch;
1540 
1541 			BE_RESET();
1542 			r--;
1543 
1544 			while (x++ < y) {
1545 				BE_ALGORITHM();
1546 				BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
1547 
1548 				if (Base::_strokeWidth > 1)
1549 					BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px - pitch, py, tr_x, tr_y, tl_x, tl_y);
1550 			}
1551 		}
1552 
1553 		ptr_fill += pitch * real_radius;
1554 		fill_y += real_radius;
1555 		while (short_h--) {
1556 			colorFillClip<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color, fill_x, fill_y, _clippingArea);
1557 			colorFillClip<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, fill_x + w - Base::_strokeWidth + 1, fill_y, _clippingArea);
1558 			ptr_fill += pitch;
1559 			++fill_y;
1560 		}
1561 
1562 		if (baseLeft) {
1563 			sw = 0;
1564 			ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
1565 			fill_x = x1;
1566 			fill_y = y1 + h + 1;
1567 			while (sw++ < Base::_strokeWidth) {
1568 				colorFillClip<PixelType>(ptr_fill - baseLeft, ptr_fill, color, fill_x - baseLeft, fill_y, _clippingArea);
1569 				ptr_fill += pitch;
1570 				++fill_y;
1571 			}
1572 		}
1573 
1574 		if (baseRight) {
1575 			sw = 0;
1576 			ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
1577 			fill_x = x1 + w;
1578 			fill_y = y1 + h + 1;
1579 			while (sw++ < Base::_strokeWidth) {
1580 				colorFillClip<PixelType>(ptr_fill, ptr_fill + baseRight, color, fill_x, fill_y, _clippingArea);
1581 				ptr_fill += pitch;
1582 				++fill_y;
1583 			}
1584 		}
1585 	} else {
1586 		BE_RESET();
1587 
1588 		precalcGradient(long_h);
1589 
1590 		PixelType color1, color2;
1591 		color1 = color2 = color;
1592 
1593 		while (x++ < y) {
1594 			BE_ALGORITHM();
1595 
1596 			if (fill_m == kFillGradient) {
1597 				color1 = calcGradient(real_radius - x, long_h);
1598 				color2 = calcGradient(real_radius - y, long_h);
1599 
1600 				gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y, tl_x - x, tl_y - y);
1601 				gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x, tl_x - y, tl_y - x);
1602 
1603 				BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
1604 			} else {
1605 				colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color, tl_x - x, tl_y - y, _clippingArea);
1606 				colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color, tl_x - y, tl_y - x, _clippingArea);
1607 
1608 				BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
1609 			}
1610 		}
1611 
1612 		ptr_fill += pitch * r;
1613 		fill_y += r;
1614 		while (short_h--) {
1615 			if (fill_m == kFillGradient) {
1616 				gradientFillClip(ptr_fill, w + 1, x1, real_radius++, fill_x, fill_y);
1617 			} else {
1618 				colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color, fill_x, fill_y, _clippingArea);
1619 			}
1620 			ptr_fill += pitch;
1621 			++fill_y;
1622 		}
1623 	}
1624 }
1625 
1626 template<typename PixelType>
1627 void VectorRendererSpec<PixelType>::
drawTabShadow(int x1,int y1,int w,int h,int r,int s)1628 drawTabShadow(int x1, int y1, int w, int h, int r, int s) {
1629 	int offset = s;
1630 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1631 
1632 	// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
1633 	uint8 expFactor = 3;
1634 	uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
1635 
1636 	int xstart = x1;
1637 	int ystart = y1;
1638 	int width = w;
1639 	int height = h + offset + 1;
1640 
1641 	for (int i = offset; i >= 0; i--) {
1642 		int f, ddF_x, ddF_y;
1643 		int x, y, px, py;
1644 
1645 		PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
1646 		PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
1647 		PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart);
1648 
1649 		int short_h = height - (2 * r);
1650 		PixelType color = _format.RGBToColor(0, 0, 0);
1651 
1652 		BE_RESET();
1653 
1654 		// HACK: As we are drawing circles exploting 8-axis symmetry,
1655 		// there are 4 pixels on each circle which are drawn twice.
1656 		// this is ok on filled circles, but when blending on surfaces,
1657 		// we cannot let it blend twice. awful.
1658 		uint32 hb = 0;
1659 
1660 		while (x++ < y) {
1661 			BE_ALGORITHM();
1662 
1663 			if (((1 << x) & hb) == 0) {
1664 				blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
1665 				hb |= (1 << x);
1666 			}
1667 
1668 			if (((1 << y) & hb) == 0) {
1669 				blendFill(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha);
1670 				hb |= (1 << y);
1671 			}
1672 		}
1673 
1674 		ptr_fill += pitch * r;
1675 		while (short_h--) {
1676 			blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha);
1677 			ptr_fill += pitch;
1678 		}
1679 
1680 		// Move shadow one pixel upward each iteration
1681 		xstart += 1;
1682 		// Multiply with expfactor
1683 		alpha = (alpha * (expFactor << 8)) >> 9;
1684 	}
1685 }
1686 
1687 template<typename PixelType>
1688 void VectorRendererSpec<PixelType>::
drawTabShadowClip(int x1,int y1,int w,int h,int r,int s)1689 drawTabShadowClip(int x1, int y1, int w, int h, int r, int s) {
1690 	int offset = s;
1691 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1692 
1693 	// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
1694 	uint8 expFactor = 3;
1695 	uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
1696 
1697 	int xstart = x1;
1698 	int ystart = y1;
1699 	int width = w;
1700 	int height = h + offset + 1;
1701 
1702 	for (int i = offset; i >= 0; i--) {
1703 		int f, ddF_x, ddF_y;
1704 		int x, y, px, py;
1705 
1706 		PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
1707 		PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
1708 		PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart);
1709 
1710 		int tl_x = xstart + r, tl_y = ystart + r;
1711 		int fill_x = xstart, fill_y = ystart;
1712 
1713 		int short_h = height - (2 * r);
1714 		PixelType color = _format.RGBToColor(0, 0, 0);
1715 
1716 		BE_RESET();
1717 
1718 		// HACK: As we are drawing circles exploting 8-axis symmetry,
1719 		// there are 4 pixels on each circle which are drawn twice.
1720 		// this is ok on filled circles, but when blending on surfaces,
1721 		// we cannot let it blend twice. awful.
1722 		uint32 hb = 0;
1723 
1724 		while (x++ < y) {
1725 			BE_ALGORITHM();
1726 
1727 			if (((1 << x) & hb) == 0) {
1728 				blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, tl_x - y, tl_y - x);
1729 				hb |= (1 << x);
1730 			}
1731 
1732 			if (((1 << y) & hb) == 0) {
1733 				blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, tl_x - x, tl_y - y);
1734 				hb |= (1 << y);
1735 			}
1736 		}
1737 
1738 		ptr_fill += pitch * r;
1739 		fill_y += r;
1740 		while (short_h--) {
1741 			blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, fill_x, fill_y);
1742 			ptr_fill += pitch;
1743 			++fill_y;
1744 		}
1745 
1746 		// Move shadow one pixel upward each iteration
1747 		xstart += 1;
1748 		// Multiply with expfactor
1749 		alpha = (alpha * (expFactor << 8)) >> 9;
1750 	}
1751 }
1752 
1753 /** BEVELED TABS FOR CLASSIC THEME **/
1754 template<typename PixelType>
1755 void VectorRendererSpec<PixelType>::
drawBevelTabAlg(int x,int y,int w,int h,int bevel,PixelType top_color,PixelType bottom_color,int baseLeft,int baseRight)1756 drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) {
1757 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1758 	int i, j;
1759 
1760 	PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1761 
1762 	i = bevel;
1763 	while (i--) {
1764 		colorFill<PixelType>(ptr_left, ptr_left + w, top_color);
1765 		ptr_left += pitch;
1766 	}
1767 
1768 	if (baseLeft > 0) {
1769 		i = h - bevel;
1770 		ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1771 		while (i--) {
1772 			colorFill<PixelType>(ptr_left, ptr_left + bevel, top_color);
1773 			ptr_left += pitch;
1774 		}
1775 	}
1776 
1777 	i = h - bevel;
1778 	j = bevel - 1;
1779 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
1780 	while (i--) {
1781 		colorFill<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color);
1782 		if (j > 0) j--;
1783 		ptr_left += pitch;
1784 	}
1785 
1786 	i = bevel;
1787 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel);
1788 	while (i--) {
1789 		colorFill<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color);
1790 
1791 		if (baseLeft)
1792 			colorFill<PixelType>(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color);
1793 		ptr_left += pitch;
1794 	}
1795 }
1796 
1797 template<typename PixelType>
1798 void VectorRendererSpec<PixelType>::
drawBevelTabAlgClip(int x,int y,int w,int h,int bevel,PixelType top_color,PixelType bottom_color,int baseLeft,int baseRight)1799 drawBevelTabAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) {
1800 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1801 	int i, j;
1802 
1803 	PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1804 	int ptr_x = x, ptr_y = y;
1805 
1806 	i = bevel;
1807 	while (i--) {
1808 		colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
1809 		ptr_left += pitch;
1810 		++ptr_y;
1811 	}
1812 
1813 	if (baseLeft > 0) {
1814 		i = h - bevel;
1815 		ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1816 		ptr_x = x; ptr_y = y;
1817 		while (i--) {
1818 			colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
1819 			ptr_left += pitch;
1820 			++ptr_y;
1821 		}
1822 	}
1823 
1824 	i = h - bevel;
1825 	j = bevel - 1;
1826 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
1827 	ptr_x = x + w - bevel; ptr_y = y;
1828 	while (i--) {
1829 		colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
1830 		if (j > 0) j--;
1831 		ptr_left += pitch;
1832 		++ptr_y;
1833 	}
1834 
1835 	i = bevel;
1836 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel);
1837 	ptr_x = x + w - bevel; ptr_y = y + h - bevel;
1838 	while (i--) {
1839 		colorFillClip<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color, ptr_x, ptr_y, _clippingArea);
1840 
1841 		if (baseLeft)
1842 			colorFillClip<PixelType>(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color, ptr_x - w - baseLeft + bevel, ptr_y, _clippingArea);
1843 		ptr_left += pitch;
1844 		++ptr_y;
1845 	}
1846 }
1847 
1848 /** SQUARE ALGORITHM **/
1849 template<typename PixelType>
1850 void VectorRendererSpec<PixelType>::
drawSquareAlg(int x,int y,int w,int h,PixelType color,VectorRenderer::FillMode fill_m)1851 drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
1852 	// Do not draw anything for empty rects.
1853 	if (w <= 0 || h <= 0) {
1854 		return;
1855 	}
1856 
1857 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
1858 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1859 	int max_h = h;
1860 
1861 	if (fill_m != kFillDisabled) {
1862 		while (h--) {
1863 			if (fill_m == kFillGradient)
1864 				color = calcGradient(max_h - h, max_h);
1865 
1866 			colorFill<PixelType>(ptr, ptr + w, color);
1867 			ptr += pitch;
1868 		}
1869 	} else {
1870 		int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
1871 
1872 		while (sw--) {
1873 			colorFill<PixelType>(ptr + sp, ptr + w + sp, color);
1874 			colorFill<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color);
1875 			sp += pitch;
1876 		}
1877 
1878 		while (h--) {
1879 			colorFill<PixelType>(ptr, ptr + Base::_strokeWidth, color);
1880 			colorFill<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color);
1881 			ptr += pitch;
1882 		}
1883 	}
1884 }
1885 
1886 template<typename PixelType>
1887 void VectorRendererSpec<PixelType>::
drawSquareAlgClip(int x,int y,int w,int h,PixelType color,VectorRenderer::FillMode fill_m)1888 drawSquareAlgClip(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
1889 	// Do not draw anything for empty rects.
1890 	if (w <= 0 || h <= 0) {
1891 		return;
1892 	}
1893 
1894 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
1895 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1896 	int max_h = h;
1897 	int ptr_y = y;
1898 
1899 	if (fill_m != kFillDisabled) {
1900 		while (h--) {
1901 			if (fill_m == kFillGradient)
1902 				color = calcGradient(max_h - h, max_h);
1903 
1904 			colorFillClip<PixelType>(ptr, ptr + w, color, x, ptr_y, _clippingArea);
1905 			ptr += pitch;
1906 			++ptr_y;
1907 		}
1908 	} else {
1909 		int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
1910 
1911 		while (sw--) {
1912 			colorFillClip<PixelType>(ptr + sp, ptr + w + sp, color, x, ptr_y + sp/pitch, _clippingArea);
1913 			colorFillClip<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color, x, ptr_y + h - sp/pitch, _clippingArea);
1914 			sp += pitch;
1915 		}
1916 
1917 		while (h--) {
1918 			colorFillClip<PixelType>(ptr, ptr + Base::_strokeWidth, color, x, ptr_y, _clippingArea);
1919 			colorFillClip<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color, x + w - Base::_strokeWidth, ptr_y, _clippingArea);
1920 			ptr += pitch;
1921 			ptr_y += 1;
1922 		}
1923 	}
1924 }
1925 
1926 /** SQUARE ALGORITHM **/
1927 template<typename PixelType>
1928 void VectorRendererSpec<PixelType>::
drawBevelSquareAlg(int x,int y,int w,int h,int bevel,PixelType top_color,PixelType bottom_color)1929 drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color) {
1930 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1931 	int i, j;
1932 	PixelType *ptr_left;
1933 
1934 	// Fill Background
1935 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1936 	i = h;
1937 	// Optimize rendering in case the background color is black
1938 	if ((_bgColor & ~_alphaMask) == 0) {
1939 		while (i--) {
1940 			darkenFill(ptr_left, ptr_left + w);
1941 			ptr_left += pitch;
1942 		}
1943 	} else {
1944 		while (i--) {
1945 			blendFill(ptr_left, ptr_left + w, _bgColor, 200);
1946 			ptr_left += pitch;
1947 		}
1948 	}
1949 
1950 	x = MAX(x - bevel, 0);
1951 	y = MAX(y - bevel, 0);
1952 
1953 	w = MIN(x + w + (bevel * 2), (int)_activeSurface->w) - x;
1954 	h = MIN(y + h + (bevel * 2), (int)_activeSurface->h) - y;
1955 
1956 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1957 	i = bevel;
1958 	while (i--) {
1959 		colorFill<PixelType>(ptr_left, ptr_left + w, top_color);
1960 		ptr_left += pitch;
1961 	}
1962 
1963 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
1964 	i = h - bevel;
1965 	while (i--) {
1966 		colorFill<PixelType>(ptr_left, ptr_left + bevel, top_color);
1967 		ptr_left += pitch;
1968 	}
1969 
1970 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
1971 	i = bevel;
1972 	while (i--) {
1973 		colorFill<PixelType>(ptr_left + i, ptr_left + w, bottom_color);
1974 		ptr_left += pitch;
1975 	}
1976 
1977 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
1978 	i = h - bevel;
1979 	j = bevel - 1;
1980 	while (i--) {
1981 		colorFill<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color);
1982 		if (j > 0) j--;
1983 		ptr_left += pitch;
1984 	}
1985 }
1986 
1987 template<typename PixelType>
1988 void VectorRendererSpec<PixelType>::
drawBevelSquareAlgClip(int x,int y,int w,int h,int bevel,PixelType top_color,PixelType bottom_color)1989 drawBevelSquareAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color) {
1990 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
1991 	int i, j;
1992 	PixelType *ptr_left;
1993 	int ptr_x, ptr_y;
1994 
1995 	// Fill Background
1996 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
1997 	ptr_x = x; ptr_y = y;
1998 	i = h;
1999 	// Optimize rendering in case the background color is black
2000 	if ((_bgColor & ~_alphaMask) == 0) {
2001 		while (i--) {
2002 			darkenFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y);
2003 			ptr_left += pitch;
2004 			++ptr_y;
2005 		}
2006 	} else {
2007 		while (i-- ) {
2008 			blendFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y, _bgColor, 200);
2009 			ptr_left += pitch;
2010 		}
2011 	}
2012 
2013 	x = MAX(x - bevel, 0);
2014 	y = MAX(y - bevel, 0);
2015 
2016 	w = MIN(x + w + (bevel * 2), (int)_activeSurface->w) - x;
2017 	h = MIN(y + h + (bevel * 2), (int)_activeSurface->h) - y;
2018 
2019 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
2020 	ptr_x = x; ptr_y = y;
2021 	i = bevel;
2022 	while (i--) {
2023 		colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
2024 		ptr_left += pitch;
2025 		++ptr_y;
2026 	}
2027 
2028 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
2029 	ptr_x = x; ptr_y = y + bevel;
2030 	i = h - bevel;
2031 	while (i--) {
2032 		colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
2033 		ptr_left += pitch;
2034 		++ptr_y;
2035 	}
2036 
2037 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
2038 	ptr_x = x; ptr_y = y + h - bevel;
2039 	i = bevel;
2040 	while (i--) {
2041 		colorFillClip<PixelType>(ptr_left + i, ptr_left + w, bottom_color, ptr_x + i, ptr_y, _clippingArea);
2042 		ptr_left += pitch;
2043 		++ptr_y;
2044 	}
2045 
2046 	ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
2047 	ptr_x = x + w - bevel; ptr_y = y;
2048 	i = h - bevel;
2049 	j = bevel - 1;
2050 	while (i--) {
2051 		colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
2052 		if (j > 0) j--;
2053 		ptr_left += pitch;
2054 		++ptr_y;
2055 	}
2056 }
2057 
2058 /** GENERIC LINE ALGORITHM **/
2059 template<typename PixelType>
2060 void VectorRendererSpec<PixelType>::
drawLineAlg(int x1,int y1,int x2,int y2,uint dx,uint dy,PixelType color)2061 drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
2062 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2063 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2064 	int xdir = (x2 > x1) ? 1 : -1;
2065 
2066 	*ptr = (PixelType)color;
2067 
2068 	if (dx > dy) {
2069 		int ddy = dy * 2;
2070 		int dysub = ddy - (dx * 2);
2071 		int error_term = ddy - dx;
2072 
2073 		while (dx--) {
2074 			if (error_term >= 0) {
2075 				ptr += pitch;
2076 				error_term += dysub;
2077 			} else {
2078 				error_term += ddy;
2079 			}
2080 
2081 			ptr += xdir;
2082 			*ptr = (PixelType)color;
2083 		}
2084 	} else {
2085 		int ddx = dx * 2;
2086 		int dxsub = ddx - (dy * 2);
2087 		int error_term = ddx - dy;
2088 
2089 		while (dy--) {
2090 			if (error_term >= 0) {
2091 				ptr += xdir;
2092 				error_term += dxsub;
2093 			} else {
2094 				error_term += ddx;
2095 			}
2096 
2097 			ptr += pitch;
2098 			*ptr = (PixelType)color;
2099 		}
2100 	}
2101 
2102 	ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
2103 	*ptr = (PixelType)color;
2104 }
2105 
2106 template<typename PixelType>
2107 void VectorRendererSpec<PixelType>::
drawLineAlgClip(int x1,int y1,int x2,int y2,uint dx,uint dy,PixelType color)2108 drawLineAlgClip(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
2109 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2110 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2111 	int xdir = (x2 > x1) ? 1 : -1;
2112 	int ptr_x = x1, ptr_y = y1;
2113 
2114 	if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
2115 
2116 	if (dx > dy) {
2117 		int ddy = dy * 2;
2118 		int dysub = ddy - (dx * 2);
2119 		int error_term = ddy - dx;
2120 
2121 		while (dx--) {
2122 			if (error_term >= 0) {
2123 				ptr += pitch;
2124 				++ptr_y;
2125 				error_term += dysub;
2126 			} else {
2127 				error_term += ddy;
2128 			}
2129 
2130 			ptr += xdir;
2131 			ptr_x += xdir;
2132 			if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
2133 		}
2134 	} else {
2135 		int ddx = dx * 2;
2136 		int dxsub = ddx - (dy * 2);
2137 		int error_term = ddx - dy;
2138 
2139 		while (dy--) {
2140 			if (error_term >= 0) {
2141 				ptr += xdir;
2142 				ptr_x += xdir;
2143 				error_term += dxsub;
2144 			} else {
2145 				error_term += ddx;
2146 			}
2147 
2148 			ptr += pitch;
2149 			++ptr_y;
2150 			if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
2151 		}
2152 	}
2153 
2154 	ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
2155 	ptr_x = x2; ptr_y = y2;
2156 	if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
2157 }
2158 
2159 /** VERTICAL TRIANGLE DRAWING ALGORITHM **/
2160 /**
2161 	FIXED POINT ARITHMETIC
2162 **/
2163 
2164 #define FIXED_POINT 1
2165 
2166 #if FIXED_POINT
2167 #define ipart(x) ((x) & ~0xFF)
2168 // This is not really correct since gradient is not percentage, but [0..255]
2169 #define rfpart(x) ((0x100 - ((x) & 0xFF)) * 100 >> 8)
2170 //#define rfpart(x) (0x100 - ((x) & 0xFF))
2171 #else
2172 #define ipart(x) ((int)x)
2173 #define round(x) (ipart(x + 0.5))
2174 #define fpart(x) (x - ipart(x))
2175 #define rfpart(x) (int)((1 - fpart(x)) * 100)
2176 #endif
2177 
2178 template<typename PixelType>
2179 void VectorRendererSpec<PixelType>::
drawTriangleHorzAlg(int x1,int y1,int w,int h,bool inverted,PixelType color,VectorRenderer::FillMode fill_m)2180 drawTriangleHorzAlg(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
2181 	// Don't draw anything for empty rects. This assures dy is always different
2182 	// from zero.
2183 	if (w <= 0 || h <= 0) {
2184 		return;
2185 	}
2186 
2187 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2188 	int gradient_w = 0;
2189 	int x_pitch_sign = 1;
2190 	if (!inverted) {
2191 		x1 += w;
2192 		x_pitch_sign = -1;
2193 	}
2194 
2195 	PixelType *ptr_bottom = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2196 	PixelType *floor = ptr_bottom - pitch;
2197 	PixelType *ptr_top = (PixelType *)_activeSurface->getBasePtr(x1, y1 + h);
2198 
2199 	int x2 = x1 + w;
2200 	int y2 = y1 + h / 2;
2201 
2202 #if FIXED_POINT
2203 	int dx = (x2 - x1) << 8;
2204 	int dy = (y2 - y1) << 8;
2205 
2206 	if (abs(dy) > abs(dx)) {
2207 #else
2208 	double dx = (double)x2 - (double)x1;
2209 	double dy = (double)y2 - (double)y1;
2210 
2211 	if (fabs(dy) > fabs(dx)) {
2212 #endif
2213 		while (floor != ptr_top) {
2214 			floor += pitch;
2215 			blendPixelPtr(floor, color, 50);
2216 		}
2217 
2218 #if FIXED_POINT
2219 		// In this branch dx is always different from zero. This is because
2220 		// abs(dx) is strictly greater than abs(dy), and abs returns zero
2221 		// as minimal value.
2222 		int gradient = (dx << 8) / dy;
2223 		int interx = (x1 << 8) + gradient;
2224 #else
2225 		double gradient = dx / dy;
2226 		double interx = x1 + gradient;
2227 #endif
2228 
2229 		for (int y = y1 + 1; y < y2; y++) {
2230 #if FIXED_POINT
2231 			if (interx + gradient >= ipart(interx) + 0x100) {
2232 #else
2233 			if (interx + gradient >= ipart(interx) + 1) {
2234 #endif
2235 				ptr_bottom += pitch;
2236 				ptr_top -= pitch;
2237 			}
2238 
2239 			ptr_top += x_pitch_sign;
2240 			ptr_bottom += x_pitch_sign;
2241 
2242 			interx += gradient;
2243 
2244 			switch (fill_m) {
2245 			case kFillDisabled:
2246 				*ptr_top = *ptr_bottom = color;
2247 				break;
2248 			case kFillForeground:
2249 			case kFillBackground:
2250 				colorVFill<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color);
2251 				blendPixelPtr(ptr_bottom, color, rfpart(interx));
2252 				blendPixelPtr(ptr_top, color, rfpart(interx));
2253 				break;
2254 			case kFillGradient:
2255 				colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w));
2256 				blendPixelPtr(ptr_bottom, color, rfpart(interx));
2257 				blendPixelPtr(ptr_top, color, rfpart(interx));
2258 				break;
2259 			default:
2260 				break;
2261 			}
2262 		}
2263 
2264 		return;
2265 	}
2266 
2267 #if FIXED_POINT
2268 	if (abs(dy) < abs(dx)) {
2269 #else
2270 	if (fabs(dy) < fabs(dx)) {
2271 #endif
2272 		ptr_top -= pitch;
2273 		while (floor != ptr_top) {
2274 			floor += pitch;
2275 			blendPixelPtr(floor, color, 50);
2276 		}
2277 
2278 #if FIXED_POINT
2279 		int gradient = (dy << 8) / (dx + 0x100);
2280 		int intery = (y1 << 8) + gradient;
2281 #else
2282 		double gradient = dy / (dx + 1);
2283 		double intery = y1 + gradient;
2284 #endif
2285 
2286 		for (int x = x1 + 1; x < x2; x++) {
2287 #if FIXED_POINT
2288 			if (intery + gradient >= ipart(intery) + 0x100) {
2289 #else
2290 			if (intery + gradient >= ipart(intery) + 1) {
2291 #endif
2292 				ptr_bottom += pitch;
2293 				ptr_top -= pitch;
2294 			}
2295 
2296 			ptr_top += x_pitch_sign;
2297 			ptr_bottom += x_pitch_sign;
2298 
2299 			intery += gradient;
2300 
2301 			switch (fill_m) {
2302 			case kFillDisabled:
2303 				*ptr_top = *ptr_bottom = color;
2304 				break;
2305 			case kFillForeground:
2306 			case kFillBackground:
2307 				colorVFill<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color);
2308 				blendPixelPtr(ptr_bottom, color, rfpart(intery));
2309 				blendPixelPtr(ptr_top, color, rfpart(intery));
2310 				break;
2311 			case kFillGradient:
2312 				colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w));
2313 				blendPixelPtr(ptr_bottom, color, rfpart(intery));
2314 				blendPixelPtr(ptr_top, color, rfpart(intery));
2315 				break;
2316 			default:
2317 				break;
2318 			}
2319 		}
2320 
2321 		return;
2322 	}
2323 
2324 	ptr_top -= pitch;
2325 
2326 	while (floor != ptr_top) {
2327 		floor += pitch;
2328 		blendPixelPtr(floor, color, 50);
2329 	}
2330 
2331 #if FIXED_POINT
2332 	int gradient = (dy / dx) << 8;
2333 	int intery = (y1 << 8) + gradient;
2334 #else
2335 	double gradient = dy / dx;
2336 	double intery = y1 + gradient;
2337 #endif
2338 
2339 	for (int x = x1 + 1; x < x2; x++) {
2340 		ptr_bottom += pitch;
2341 		ptr_top -= pitch;
2342 
2343 		ptr_top += x_pitch_sign;
2344 		ptr_bottom += x_pitch_sign;
2345 
2346 		intery += gradient;
2347 
2348 		switch (fill_m) {
2349 		case kFillDisabled:
2350 			*ptr_top = *ptr_bottom = color;
2351 			break;
2352 		case kFillForeground:
2353 		case kFillBackground:
2354 			colorVFill<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color);
2355 			blendPixelPtr(ptr_bottom, color, rfpart(intery));
2356 			blendPixelPtr(ptr_top, color, rfpart(intery));
2357 			break;
2358 		case kFillGradient:
2359 			colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w));
2360 			blendPixelPtr(ptr_bottom, color, rfpart(intery));
2361 			blendPixelPtr(ptr_top, color, rfpart(intery));
2362 			break;
2363 		default:
2364 			break;
2365 		}
2366 	}
2367 
2368 }
2369 
2370 /////////////
2371 
2372 template<typename PixelType>
2373 void VectorRendererSpec<PixelType>::
2374 drawTriangleHorzAlgClip(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
2375 	// Don't draw anything for empty rects. This assures dy is always different
2376 	// from zero.
2377 	if (w <= 0 || h <= 0) {
2378 		return;
2379 	}
2380 
2381 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2382 	int gradient_w = 0;
2383 	int x_pitch_sign = 1;
2384 	if (!inverted) {
2385 		x1 += w;
2386 		x_pitch_sign = -1;
2387 	}
2388 
2389 	PixelType *ptr_bottom = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2390 	PixelType *floor = ptr_bottom - pitch;
2391 	PixelType *ptr_top = (PixelType *)_activeSurface->getBasePtr(x1, y1 + h);
2392 
2393 	int x2 = x1 + w;
2394 	int y2 = y1 + h / 2;
2395 	int x_bottom = x1;
2396 	int y_bottom = y1;
2397 	int x_top = x1;
2398 	int y_top = y1 + h;
2399 	int x_floor = x_bottom;
2400 	int y_floor = y_bottom - 1;
2401 
2402 #if FIXED_POINT
2403 	int dx = (x2 - x1) << 8;
2404 	int dy = (y2 - y1) << 8;
2405 
2406 	if (abs(dy) > abs(dx)) {
2407 #else
2408 	double dx = (double)x2 - (double)x1;
2409 	double dy = (double)y2 - (double)y1;
2410 
2411 	if (fabs(dy) > fabs(dx)) {
2412 #endif
2413 		while (floor != ptr_top) {
2414 			floor += pitch;
2415 			blendPixelPtrClip(floor, color, 50, x_floor, ++y_floor);
2416 		}
2417 
2418 #if FIXED_POINT
2419 		// In this branch dx is always different from zero. This is because
2420 		// abs(dx) is strictly greater than abs(dy), and abs returns zero
2421 		// as minimal value.
2422 		int gradient = (dx << 8) / dy;
2423 		int interx = (x1 << 8) + gradient;
2424 #else
2425 		double gradient = dx / dy;
2426 		double interx = x1 + gradient;
2427 #endif
2428 
2429 		for (int y = y1 + 1; y < y2; y++) {
2430 #if FIXED_POINT
2431 			if (interx + gradient >= ipart(interx) + 0x100) {
2432 #else
2433 			if (interx + gradient >= ipart(interx) + 1) {
2434 #endif
2435 				ptr_bottom += pitch;
2436 				ptr_top -= pitch;
2437 				++y_bottom;
2438 				--y_top;
2439 			}
2440 
2441 			ptr_top += x_pitch_sign;
2442 			ptr_bottom += x_pitch_sign;
2443 			x_top += x_pitch_sign;
2444 			x_bottom += x_pitch_sign;
2445 
2446 			interx += gradient;
2447 
2448 			switch (fill_m) {
2449 			case kFillDisabled:
2450 				if (IS_IN_CLIP(x_top, y_top)) *ptr_top = color;
2451 				if (IS_IN_CLIP(x_bottom, y_bottom)) *ptr_bottom = color;
2452 				break;
2453 			case kFillForeground:
2454 			case kFillBackground:
2455 				colorVFillClip<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color, x_bottom, y_bottom + 1, _clippingArea);
2456 				blendPixelPtrClip(ptr_bottom, color, rfpart(interx), x_bottom, y_bottom);
2457 				blendPixelPtrClip(ptr_top, color, rfpart(interx), x_top, y_top);
2458 				break;
2459 			case kFillGradient:
2460 				colorVFillClip<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w), x_bottom, y_bottom, _clippingArea);
2461 				blendPixelPtrClip(ptr_bottom, color, rfpart(interx), x_bottom, y_bottom);
2462 				blendPixelPtrClip(ptr_top, color, rfpart(interx), x_top, y_top);
2463 				break;
2464 			default:
2465 				break;
2466 			}
2467 			}
2468 
2469 		return;
2470 		}
2471 
2472 #if FIXED_POINT
2473 	if (abs(dy) < abs(dx)) {
2474 #else
2475 	if (fabs(dy) < fabs(dx)) {
2476 #endif
2477 		ptr_top -= pitch;
2478 		--y_top;
2479 		while (floor != ptr_top) {
2480 			floor += pitch;
2481 			blendPixelPtrClip(floor, color, 50, x_floor, ++y_floor);
2482 		}
2483 
2484 #if FIXED_POINT
2485 		int gradient = (dy << 8) / (dx + 0x100);
2486 		int intery = (y1 << 8) + gradient;
2487 #else
2488 		double gradient = dy / (dx + 1);
2489 		double intery = y1 + gradient;
2490 #endif
2491 
2492 		for (int x = x1 + 1; x < x2; x++) {
2493 #if FIXED_POINT
2494 			if (intery + gradient >= ipart(intery) + 0x100) {
2495 #else
2496 			if (intery + gradient >= ipart(intery) + 1) {
2497 #endif
2498 				ptr_bottom += pitch;
2499 				ptr_top -= pitch;
2500 				++y_bottom;
2501 				--y_top;
2502 			}
2503 
2504 			ptr_top += x_pitch_sign;
2505 			ptr_bottom += x_pitch_sign;
2506 			x_bottom += x_pitch_sign;
2507 			x_top += x_pitch_sign;
2508 
2509 			intery += gradient;
2510 
2511 			switch (fill_m) {
2512 			case kFillDisabled:
2513 				if (IS_IN_CLIP(x_top, y_top)) *ptr_top = color;
2514 				if (IS_IN_CLIP(x_bottom, y_bottom)) *ptr_bottom = color;
2515 				break;
2516 			case kFillForeground:
2517 			case kFillBackground:
2518 				colorVFillClip<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color, x_bottom, y_bottom + 1, _clippingArea);
2519 				blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
2520 				blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
2521 				break;
2522 			case kFillGradient:
2523 				colorVFillClip<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w), x_bottom, y_bottom, _clippingArea);
2524 				blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
2525 				blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
2526 				break;
2527 			default:
2528 				break;
2529 			}
2530 			}
2531 
2532 		return;
2533 		}
2534 
2535 	ptr_top -= pitch;
2536 	--y_top;
2537 	while (floor != ptr_top) {
2538 		floor += pitch;
2539 		blendPixelPtrClip(floor, color, 50, x_floor, ++y_floor);
2540 	}
2541 
2542 #if FIXED_POINT
2543 	int gradient = (dy / dx) << 8;
2544 	int intery = (y1 << 8) + gradient;
2545 #else
2546 	double gradient = dy / dx;
2547 	double intery = y1 + gradient;
2548 #endif
2549 
2550 	for (int x = x1 + 1; x < x2; x++) {
2551 		ptr_bottom += pitch;
2552 		ptr_top -= pitch;
2553 		++y_bottom;
2554 		--y_top;
2555 
2556 		ptr_top += x_pitch_sign;
2557 		ptr_bottom += x_pitch_sign;
2558 		x_bottom += x_pitch_sign;
2559 		x_top += x_pitch_sign;
2560 
2561 		intery += gradient;
2562 
2563 		switch (fill_m) {
2564 		case kFillDisabled:
2565 			if (IS_IN_CLIP(x_top, y_top)) *ptr_top = color;
2566 			if (IS_IN_CLIP(x_bottom, y_bottom)) *ptr_bottom = color;
2567 			break;
2568 		case kFillForeground:
2569 		case kFillBackground:
2570 			colorVFillClip<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color, x_bottom, y_bottom + 1, _clippingArea);
2571 			blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
2572 			blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
2573 			break;
2574 		case kFillGradient:
2575 			colorVFillClip<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w), x_bottom, y_bottom, _clippingArea);
2576 			blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
2577 			blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
2578 			break;
2579 		default:
2580 			break;
2581 		}
2582 	}
2583 }
2584 
2585 /////////////
2586 
2587 /** HORIZONTAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
2588 template<typename PixelType>
2589 void VectorRendererSpec<PixelType>::
2590 drawTriangleFastH(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
2591 	// Do not draw anything for empty rects.
2592 	if (size <= 0) {
2593 		return;
2594 	}
2595 
2596 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2597 	int x_pitch_sign = 1;
2598 
2599 	if (!inverted) {
2600 		y1 += size;
2601 		x_pitch_sign = -1;
2602 	}
2603 
2604 	int gradient_w = 0;
2605 	PixelType *ptr_bottom = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2606 	PixelType *ptr_top = (PixelType *)_activeSurface->getBasePtr(x1, y1 + size);
2607 	int x2 = x1 + size;
2608 	int y2 = y1 + size / 2;
2609 	int deltaX = abs(x2 - x1);
2610 	int deltaY = abs(y2 - y1);
2611 	int signX = x1 < x2 ? 1 : -1;
2612 	int signY = y1 < y2 ? 1 : -1;
2613 	int error = deltaX - deltaY;
2614 
2615 	colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, color);
2616 
2617 	while (1) {
2618 		switch (fill_m) {
2619 		case kFillDisabled:
2620 			*ptr_top = *ptr_bottom = color;
2621 			break;
2622 		case kFillForeground:
2623 		case kFillBackground:
2624 			colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, color);
2625 			break;
2626 		case kFillGradient:
2627 			colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, size));
2628 			break;
2629 		default:
2630 			break;
2631 		}
2632 
2633 		if (x1 == x2 && y1 == y2)
2634 			break;
2635 
2636 		int error2 = error * 2;
2637 
2638 		if (error2 > -deltaX) {
2639 			error -= deltaX;
2640 			y1 += signY;
2641 			ptr_bottom += signY * pitch;
2642 			ptr_top += -signY * pitch;
2643 		}
2644 
2645 		if (error2 < deltaY) {
2646 			error += deltaY;
2647 			x1 += signX;
2648 			ptr_bottom += x_pitch_sign;
2649 			ptr_top += x_pitch_sign;
2650 		}
2651 	}
2652 }
2653 
2654 template<typename PixelType>
2655 void VectorRendererSpec<PixelType>::
2656 drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
2657 	// Don't draw anything for empty rects. This assures dy is always different
2658 	// from zero.
2659 	if (w <= 0 || h <= 0) {
2660 		return;
2661 	}
2662 
2663 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2664 	int gradient_h = 0;
2665 	if (!inverted) {
2666 		pitch = -pitch;
2667 		y1 += h;
2668 	}
2669 
2670 	PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2671 	PixelType *floor = ptr_right - 1;
2672 	PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
2673 
2674 	int x2 = x1 + w / 2;
2675 	int y2 = y1 + h;
2676 
2677 #if FIXED_POINT
2678 	int dx = (x2 - x1) << 8;
2679 	int dy = (y2 - y1) << 8;
2680 
2681 	if (abs(dx) > abs(dy)) {
2682 #else
2683 	double dx = (double)x2 - (double)x1;
2684 	double dy = (double)y2 - (double)y1;
2685 
2686 	if (fabs(dx) > fabs(dy)) {
2687 #endif
2688 		while (floor++ != ptr_left)
2689 			blendPixelPtr(floor, color, 50);
2690 
2691 #if FIXED_POINT
2692 		// In this branch dx is always different from zero. This is because
2693 		// abs(dx) is strictly greater than abs(dy), and abs returns zero
2694 		// as minimal value.
2695 		int gradient = (dy << 8) / dx;
2696 		int intery = (y1 << 8) + gradient;
2697 #else
2698 		double gradient = dy / dx;
2699 		double intery = y1 + gradient;
2700 #endif
2701 
2702 		for (int x = x1 + 1; x < x2; x++) {
2703 #if FIXED_POINT
2704 			if (intery + gradient >= ipart(intery) + 0x100) {
2705 #else
2706 			if (intery + gradient >= ipart(intery) + 1) {
2707 #endif
2708 				ptr_right++;
2709 				ptr_left--;
2710 			}
2711 
2712 			ptr_left += pitch;
2713 			ptr_right += pitch;
2714 
2715 			intery += gradient;
2716 
2717 			switch (fill_m) {
2718 			case kFillDisabled:
2719 				*ptr_left = *ptr_right = color;
2720 				break;
2721 			case kFillForeground:
2722 			case kFillBackground:
2723 				colorFill<PixelType>(ptr_right + 1, ptr_left, color);
2724 				blendPixelPtr(ptr_right, color, rfpart(intery));
2725 				blendPixelPtr(ptr_left, color, rfpart(intery));
2726 				break;
2727 			case kFillGradient:
2728 				colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
2729 				blendPixelPtr(ptr_right, color, rfpart(intery));
2730 				blendPixelPtr(ptr_left, color, rfpart(intery));
2731 				break;
2732 			default:
2733 				break;
2734 			}
2735 		}
2736 
2737 		return;
2738 	}
2739 
2740 #if FIXED_POINT
2741 	if (abs(dx) < abs(dy)) {
2742 #else
2743 	if (fabs(dx) < fabs(dy)) {
2744 #endif
2745 		ptr_left--;
2746 		while (floor++ != ptr_left)
2747 			blendPixelPtr(floor, color, 50);
2748 
2749 #if FIXED_POINT
2750 		int gradient = (dx << 8) / (dy + 0x100);
2751 		int interx = (x1 << 8) + gradient;
2752 #else
2753 		double gradient = dx / (dy + 1);
2754 		double interx = x1 + gradient;
2755 #endif
2756 
2757 		for (int y = y1 + 1; y < y2; y++) {
2758 #if FIXED_POINT
2759 			if (interx + gradient >= ipart(interx) + 0x100) {
2760 #else
2761 			if (interx + gradient >= ipart(interx) + 1) {
2762 #endif
2763 				ptr_right++;
2764 				ptr_left--;
2765 			}
2766 
2767 			ptr_left += pitch;
2768 			ptr_right += pitch;
2769 
2770 			interx += gradient;
2771 
2772 			switch (fill_m) {
2773 			case kFillDisabled:
2774 				*ptr_left = *ptr_right = color;
2775 				break;
2776 			case kFillForeground:
2777 			case kFillBackground:
2778 				colorFill<PixelType>(ptr_right + 1, ptr_left, color);
2779 				blendPixelPtr(ptr_right, color, rfpart(interx));
2780 				blendPixelPtr(ptr_left, color, rfpart(interx));
2781 				break;
2782 			case kFillGradient:
2783 				colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
2784 				blendPixelPtr(ptr_right, color, rfpart(interx));
2785 				blendPixelPtr(ptr_left, color, rfpart(interx));
2786 				break;
2787 			default:
2788 				break;
2789 			}
2790 		}
2791 
2792 		return;
2793 	}
2794 
2795 	ptr_left--;
2796 
2797 	while (floor++ != ptr_left)
2798 		blendPixelPtr(floor, color, 50);
2799 
2800 #if FIXED_POINT
2801 	int gradient = (dx / dy) << 8;
2802 	int interx = (x1 << 8) + gradient;
2803 #else
2804 	double gradient = dx / dy;
2805 	double interx = x1 + gradient;
2806 #endif
2807 
2808 	for (int y = y1 + 1; y < y2; y++) {
2809 		ptr_right++;
2810 		ptr_left--;
2811 
2812 		ptr_left += pitch;
2813 		ptr_right += pitch;
2814 
2815 		interx += gradient;
2816 
2817 		switch (fill_m) {
2818 		case kFillDisabled:
2819 			*ptr_left = *ptr_right = color;
2820 			break;
2821 		case kFillForeground:
2822 		case kFillBackground:
2823 			colorFill<PixelType>(ptr_right + 1, ptr_left, color);
2824 			blendPixelPtr(ptr_right, color, rfpart(interx));
2825 			blendPixelPtr(ptr_left, color, rfpart(interx));
2826 			break;
2827 		case kFillGradient:
2828 			colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
2829 			blendPixelPtr(ptr_right, color, rfpart(interx));
2830 			blendPixelPtr(ptr_left, color, rfpart(interx));
2831 			break;
2832 		default:
2833 			break;
2834 		}
2835 	}
2836 
2837 }
2838 
2839 /////////////
2840 
2841 template<typename PixelType>
2842 void VectorRendererSpec<PixelType>::
2843 drawTriangleVertAlgClip(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
2844 	// Don't draw anything for empty rects. This assures dy is always different
2845 	// from zero.
2846 	if (w <= 0 || h <= 0) {
2847 		return;
2848 	}
2849 
2850 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
2851 	int gradient_h = 0;
2852 	int y_pitch_sign = 1;
2853 	if (!inverted) {
2854 		pitch = -pitch;
2855 		y1 += h;
2856 		y_pitch_sign = -1;
2857 	}
2858 
2859 	PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
2860 	PixelType *floor = ptr_right - 1;
2861 	PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
2862 
2863 	int x2 = x1 + w / 2;
2864 	int y2 = y1 + h;
2865 	int x_right = x1;
2866 	int y_right = y1;
2867 	int x_left = x1 + w;
2868 	int y_left = y1;
2869 	int x_floor = x_right - 1;
2870 	int y_floor = y_right;
2871 
2872 #if FIXED_POINT
2873 	int dx = (x2 - x1) << 8;
2874 	int dy = (y2 - y1) << 8;
2875 
2876 	if (abs(dx) > abs(dy)) {
2877 #else
2878 	double dx = (double)x2 - (double)x1;
2879 	double dy = (double)y2 - (double)y1;
2880 
2881 	if (fabs(dx) > fabs(dy)) {
2882 #endif
2883 		while (floor++ != ptr_left)
2884 			blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
2885 
2886 #if FIXED_POINT
2887 		// In this branch dx is always different from zero. This is because
2888 		// abs(dx) is strictly greater than abs(dy), and abs returns zero
2889 		// as minimal value.
2890 		int gradient = (dy << 8) / dx;
2891 		int intery = (y1 << 8) + gradient;
2892 #else
2893 		double gradient = dy / dx;
2894 		double intery = y1 + gradient;
2895 #endif
2896 
2897 		for (int x = x1 + 1; x < x2; x++) {
2898 #if FIXED_POINT
2899 			if (intery + gradient >= ipart(intery) + 0x100) {
2900 #else
2901 			if (intery + gradient >= ipart(intery) + 1) {
2902 #endif
2903 				ptr_right++;
2904 				ptr_left--;
2905 				++x_right;
2906 				--x_left;
2907 			}
2908 
2909 			ptr_left += pitch;
2910 			ptr_right += pitch;
2911 			y_right += y_pitch_sign;
2912 			y_left += y_pitch_sign;
2913 
2914 			intery += gradient;
2915 
2916 			switch (fill_m) {
2917 			case kFillDisabled:
2918 				if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
2919 				if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
2920 				break;
2921 			case kFillForeground:
2922 			case kFillBackground:
2923 				colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right + 1, y_right, _clippingArea);
2924 				blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
2925 				blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
2926 				break;
2927 			case kFillGradient:
2928 				colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
2929 				blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
2930 				blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
2931 				break;
2932 			default:
2933 				break;
2934 			}
2935 			}
2936 
2937 		return;
2938 		}
2939 
2940 #if FIXED_POINT
2941 	if (abs(dx) < abs(dy)) {
2942 #else
2943 	if (fabs(dx) < fabs(dy)) {
2944 #endif
2945 		ptr_left--;
2946 		--x_left;
2947 		while (floor++ != ptr_left)
2948 			blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
2949 
2950 #if FIXED_POINT
2951 		int gradient = (dx << 8) / (dy + 0x100);
2952 		int interx = (x1 << 8) + gradient;
2953 #else
2954 		double gradient = dx / (dy + 1);
2955 		double interx = x1 + gradient;
2956 #endif
2957 
2958 		for (int y = y1 + 1; y < y2; y++) {
2959 #if FIXED_POINT
2960 			if (interx + gradient >= ipart(interx) + 0x100) {
2961 #else
2962 			if (interx + gradient >= ipart(interx) + 1) {
2963 #endif
2964 				ptr_right++;
2965 				ptr_left--;
2966 				++x_right;
2967 				--x_left;
2968 			}
2969 
2970 			ptr_left += pitch;
2971 			ptr_right += pitch;
2972 			y_right += y_pitch_sign;
2973 			y_left += y_pitch_sign;
2974 
2975 			interx += gradient;
2976 
2977 			switch (fill_m) {
2978 			case kFillDisabled:
2979 				if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
2980 				if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
2981 				break;
2982 			case kFillForeground:
2983 			case kFillBackground:
2984 				colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right + 1, y_right, _clippingArea);
2985 				blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
2986 				blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
2987 				break;
2988 			case kFillGradient:
2989 				colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
2990 				blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
2991 				blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
2992 				break;
2993 			default:
2994 				break;
2995 			}
2996 			}
2997 
2998 		return;
2999 		}
3000 
3001 	ptr_left--;
3002 	--x_left;
3003 	while (floor++ != ptr_left)
3004 		blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
3005 
3006 #if FIXED_POINT
3007 	int gradient = (dx / dy) << 8;
3008 	int interx = (x1 << 8) + gradient;
3009 #else
3010 	double gradient = dx / dy;
3011 	double interx = x1 + gradient;
3012 #endif
3013 
3014 	for (int y = y1 + 1; y < y2; y++) {
3015 		ptr_right++;
3016 		ptr_left--;
3017 		++x_right;
3018 		--x_left;
3019 
3020 		ptr_left += pitch;
3021 		ptr_right += pitch;
3022 		y_right += y_pitch_sign;
3023 		y_left += y_pitch_sign;
3024 
3025 		interx += gradient;
3026 
3027 		switch (fill_m) {
3028 		case kFillDisabled:
3029 			if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
3030 			if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
3031 			break;
3032 		case kFillForeground:
3033 		case kFillBackground:
3034 			colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right + 1, y_right, _clippingArea);
3035 			blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
3036 			blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
3037 			break;
3038 		case kFillGradient:
3039 			colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
3040 			blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
3041 			blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
3042 			break;
3043 		default:
3044 			break;
3045 		}
3046 	}
3047 }
3048 
3049 /////////////
3050 
3051 /** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
3052 template<typename PixelType>
3053 void VectorRendererSpec<PixelType>::
3054 drawTriangleFastV(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
3055 	// Do not draw anything for empty rects.
3056 	if (size <= 0) {
3057 		return;
3058 	}
3059 
3060 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3061 
3062 	if (!inverted) {
3063 		pitch = -pitch;
3064 		y1 += size;
3065 	}
3066 
3067 	int gradient_h = 0;
3068 	PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
3069 	PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + size, y1);
3070 	int x2 = x1 + size / 2;
3071 	int y2 = y1 + size;
3072 	int deltaX = abs(x2 - x1);
3073 	int deltaY = abs(y2 - y1);
3074 	int signX = x1 < x2 ? 1 : -1;
3075 	int signY = y1 < y2 ? 1 : -1;
3076 	int error = deltaX - deltaY;
3077 
3078 	colorFill<PixelType>(ptr_right, ptr_left, color);
3079 
3080 	while (1) {
3081 		switch (fill_m) {
3082 		case kFillDisabled:
3083 			*ptr_left = *ptr_right = color;
3084 			break;
3085 		case kFillForeground:
3086 		case kFillBackground:
3087 			colorFill<PixelType>(ptr_right, ptr_left, color);
3088 			break;
3089 		case kFillGradient:
3090 			colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, size));
3091 			break;
3092 		default:
3093 			break;
3094 		}
3095 
3096 		if (x1 == x2 && y1 == y2)
3097 			break;
3098 
3099 		int error2 = error * 2;
3100 
3101 		if (error2 > -deltaY) {
3102 			error -= deltaY;
3103 			x1 += signX;
3104 			ptr_right += signX;
3105 			ptr_left += -signX;
3106 		}
3107 
3108 		if (error2 < deltaX) {
3109 			error += deltaX;
3110 			y1 += signY;
3111 			ptr_right += pitch;
3112 			ptr_left += pitch;
3113 		}
3114 	}
3115 }
3116 
3117 /** ROUNDED SQUARE ALGORITHM **/
3118 template<typename PixelType>
3119 void VectorRendererSpec<PixelType>::
3120 drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
3121 	int f, ddF_x, ddF_y;
3122 	int x, y, px, py;
3123 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3124 	int sw = 0;
3125 
3126 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
3127 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
3128 	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
3129 	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
3130 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3131 
3132 	int real_radius = r;
3133 	int short_h = h - (2 * r) + 2;
3134 
3135 	PixelType color1 = color;
3136 	PixelType color2 = color;
3137 
3138 	while (sw++ < Base::_strokeWidth) {
3139 		PixelType *ptr_fill3 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + sw - 1);
3140 		this->blendFill(ptr_fill3 + r, ptr_fill3 + w + 1 - r, color1, alpha_t); // top
3141 
3142 		PixelType *ptr_fill2 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h - sw + 1);
3143 		this->blendFill(ptr_fill2 + r, ptr_fill2 + w + 1 - r, color2, alpha_b); // bottom
3144 
3145 		BE_RESET();
3146 		r--;
3147 
3148 		int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1));
3149 		int alphaStep_br = ((alpha_r - alpha_b) / (y + 1));
3150 		int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1));
3151 		int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1));
3152 
3153 		// Avoid blending the last pixels twice, since we have an alpha
3154 		while (x++ < (y - 2)) {
3155 			BE_ALGORITHM();
3156 
3157 			BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)));
3158 			BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)));
3159 			BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)));
3160 			BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)));
3161 
3162 			BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)));
3163 			BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)));
3164 			BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)));
3165 			BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)));
3166 
3167 			if (Base::_strokeWidth > 1) {
3168 				BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py);
3169 				BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py);
3170 			}
3171 		}
3172 	}
3173 
3174 	ptr_fill += pitch * real_radius;
3175 	while (short_h--) {
3176 		blendFill(ptr_fill, ptr_fill + Base::_strokeWidth, color, alpha_l); // left
3177 		blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, alpha_r); // right
3178 		ptr_fill += pitch;
3179 	}
3180 }
3181 
3182 template<typename PixelType>
3183 void VectorRendererSpec<PixelType>::
3184 drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
3185 	int f, ddF_x, ddF_y;
3186 	int x, y, px, py;
3187 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3188 	int sw = 0, sp = 0, hp = h * pitch;
3189 
3190 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
3191 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
3192 	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
3193 	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
3194 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3195 
3196 	int real_radius = r;
3197 	int short_h = h - (2 * r) + 2;
3198 
3199 	PixelType color1 = color;
3200 	PixelType color2 = color;
3201 
3202 	while (sw++ < Base::_strokeWidth) {
3203 		blendFillClip(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t,
3204 			x1 + r, y1 + sp/pitch); // top
3205 		blendFillClip(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b,
3206 			x1 + r, y1 + (hp - sp)/ pitch); // bottom
3207 		sp += pitch;
3208 
3209 		BE_RESET();
3210 		r--;
3211 
3212 		int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1));
3213 		int alphaStep_br = ((alpha_r - alpha_b) / (y + 1));
3214 		int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1));
3215 		int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1));
3216 
3217 		// Avoid blending the last pixels twice, since we have an alpha
3218 		while (x++ < (y - 2)) {
3219 			BE_ALGORITHM();
3220 
3221 			BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)), x1 + w - r, y1 + r);
3222 			BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)), x1 + w - r, y1 + h - r);
3223 			BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)), x1 + r, y1 + h - r);
3224 			BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)), x1 + r, y1 + r);
3225 
3226 			BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)), x1 + w - r, y1 + r);
3227 			BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)), x1 + w - r, y1 + h - r);
3228 			BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)), x1 + r, y1 + h - r);
3229 			BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)), x1 + r, y1 + r);
3230 
3231 			if (Base::_strokeWidth > 1) {
3232 				BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py,
3233 					x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
3234 				BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py,
3235 					x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
3236 			}
3237 		}
3238 	}
3239 
3240 	ptr_fill += pitch * real_radius;
3241 	while (short_h--) {
3242 		blendFillClip(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l,
3243 			x1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // left
3244 		blendFillClip(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r,
3245 			x1 + w - Base::_strokeWidth + 1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // right
3246 		ptr_fill += pitch;
3247 	}
3248 }
3249 
3250 template<typename PixelType>
3251 void VectorRendererSpec<PixelType>::
3252 drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
3253 	// Do not draw empty space rounded squares.
3254 	if (w <= 0 || h <= 0) {
3255 		return;
3256 	}
3257 
3258 	int f, ddF_x, ddF_y;
3259 	int x, y, px, py;
3260 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3261 
3262 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
3263 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
3264 	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
3265 	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
3266 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3267 
3268 	int real_radius = r;
3269 	int short_h = h - (2 * r) + 2;
3270 	int long_h = h;
3271 
3272 	BE_RESET();
3273 
3274 	PixelType color1 = color;
3275 
3276 	if (fill_m == kFillGradient) {
3277 		PixelType color2, color3, color4;
3278 		precalcGradient(long_h);
3279 
3280 		while (x++ < y) {
3281 			BE_ALGORITHM();
3282 
3283 			color1 = calcGradient(real_radius - x, long_h);
3284 			color2 = calcGradient(real_radius - y, long_h);
3285 			color3 = calcGradient(long_h - r + x, long_h);
3286 			color4 = calcGradient(long_h - r + y, long_h);
3287 
3288 			gradientFill(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y);
3289 			gradientFill(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x);
3290 
3291 			gradientFill(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y);
3292 			gradientFill(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x);
3293 
3294 			BE_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
3295 		}
3296 	} else {
3297 		while (x++ < y) {
3298 			BE_ALGORITHM();
3299 
3300 			colorFill<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1);
3301 			colorFill<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1);
3302 
3303 			colorFill<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1);
3304 			colorFill<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1);
3305 
3306 			// do not remove - messes up the drawing at lower resolutions
3307 			BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
3308 		}
3309 	}
3310 
3311 	ptr_fill += pitch * r;
3312 	while (short_h--) {
3313 		if (fill_m == kFillGradient) {
3314 			gradientFill(ptr_fill, w + 1, x1, real_radius++);
3315 		} else {
3316 			colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color1);
3317 		}
3318 		ptr_fill += pitch;
3319 	}
3320 }
3321 
3322 template<typename PixelType>
3323 void VectorRendererSpec<PixelType>::
3324 drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
3325 	// Do not draw empty space rounded squares.
3326 	if (w <= 0 || h <= 0) {
3327 		return;
3328 	}
3329 
3330 	int f, ddF_x, ddF_y;
3331 	int x, y, px, py;
3332 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3333 
3334 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
3335 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
3336 	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
3337 	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
3338 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3339 
3340 	int real_radius = r;
3341 	int short_h = h - (2 * r) + 2;
3342 	int long_h = h;
3343 
3344 	BE_RESET();
3345 
3346 	PixelType color1 = color;
3347 
3348 	if (fill_m == kFillGradient) {
3349 		PixelType color2, color3, color4;
3350 		precalcGradient(long_h);
3351 
3352 		while (x++ < y) {
3353 			BE_ALGORITHM();
3354 
3355 			color1 = calcGradient(real_radius - x, long_h);
3356 			color2 = calcGradient(real_radius - y, long_h);
3357 			color3 = calcGradient(long_h - r + x, long_h);
3358 			color4 = calcGradient(long_h - r + y, long_h);
3359 
3360 			//TL = (x1 + r, y1 + r)
3361 			gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y,
3362 				x1 + r - x, y1 + r - y);
3363 			gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x,
3364 				x1 + r - y, y1 + r - x);
3365 
3366 			//BL = (x1 + r, y1 + h - r)
3367 			gradientFillClip(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y,
3368 				x1 + r - x, y1 + h - r + y);
3369 			gradientFillClip(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x,
3370 				x1 + r - y, y1 + h - r + x);
3371 
3372 			BE_DRAWCIRCLE_XCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
3373 				x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
3374 		}
3375 	} else {
3376 		while (x++ < y) {
3377 			BE_ALGORITHM();
3378 
3379 			colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1,
3380 				x1 + r - x, y1 + r - y, _clippingArea);
3381 			colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1,
3382 				x1 + r - y, y1 + r - x, _clippingArea);
3383 
3384 			colorFillClip<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1,
3385 				x1 + r - x, y1 + h - r + y, _clippingArea);
3386 			colorFillClip<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1,
3387 				x1 + r - y, y1 + h - r + x, _clippingArea);
3388 
3389 			// do not remove - messes up the drawing at lower resolutions
3390 			BE_DRAWCIRCLE_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
3391 				x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
3392 		}
3393 	}
3394 
3395 	ptr_fill += pitch * r;
3396 	int short_h_orig = short_h;
3397 	while (short_h--) {
3398 		if (fill_m == kFillGradient) {
3399 			gradientFillClip(ptr_fill, w + 1, x1, real_radius++, x1, y1 + r + short_h_orig - short_h -1);
3400 		} else {
3401 			colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color1, x1, y1 + r + short_h_orig - short_h - 1, _clippingArea);
3402 		}
3403 		ptr_fill += pitch;
3404 	}
3405 }
3406 
3407 template<typename PixelType>
3408 void VectorRendererSpec<PixelType>::
3409 drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
3410 	const uint8 borderAlpha_t = 0;
3411 	const uint8 borderAlpha_r = 127;
3412 	const uint8 borderAlpha_b = 255;
3413 	const uint8 borderAlpha_l = 63;
3414 
3415 	const uint8 bevelAlpha_t = 255;
3416 	const uint8 bevelAlpha_r = 31;
3417 	const uint8 bevelAlpha_b = 0;
3418 	const uint8 bevelAlpha_l = 127;
3419 
3420 	// If only border is visible
3421 	if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
3422 		if (fill_m == Base::kFillBackground)
3423 			drawInteriorRoundedSquareAlg(x1, y1, r, w, h, _bgColor, fill_m);
3424 		else
3425 			drawInteriorRoundedSquareAlg(x1, y1, r, w, h, color, fill_m);
3426 	}
3427 
3428 	if (Base::_strokeWidth) {
3429 		if (r != 0 && _bevel > 0) {
3430 			drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
3431 			drawBorderRoundedSquareAlg(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
3432 		} else {
3433 			drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
3434 		}
3435 	}
3436 }
3437 
3438 template<typename PixelType>
3439 void VectorRendererSpec<PixelType>::
3440 drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
3441 	const uint8 borderAlpha_t = 0;
3442 	const uint8 borderAlpha_r = 127;
3443 	const uint8 borderAlpha_b = 255;
3444 	const uint8 borderAlpha_l = 63;
3445 
3446 	const uint8 bevelAlpha_t = 255;
3447 	const uint8 bevelAlpha_r = 31;
3448 	const uint8 bevelAlpha_b = 0;
3449 	const uint8 bevelAlpha_l = 127;
3450 
3451 	// If only border is visible
3452 	if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
3453 		if (fill_m == Base::kFillBackground)
3454 			drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, _bgColor, fill_m);
3455 		else
3456 			drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m);
3457 	}
3458 
3459 	//I expect these to work fine with clipping:
3460 	if (Base::_strokeWidth) {
3461 		if (r != 0 && _bevel > 0) {
3462 			drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
3463 			drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
3464 		} else {
3465 			drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
3466 		}
3467 	}
3468 }
3469 
3470 /** CIRCLE ALGORITHM **/
3471 template<typename PixelType>
3472 void VectorRendererSpec<PixelType>::
3473 drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
3474 	int f, ddF_x, ddF_y;
3475 	int x, y, px, py, sw = 0;
3476 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3477 	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3478 
3479 	if (fill_m == kFillDisabled) {
3480 		while (sw++ < Base::_strokeWidth) {
3481 			BE_RESET();
3482 			r--;
3483 
3484 			*(ptr + y) = color;
3485 			*(ptr - y) = color;
3486 			*(ptr + py) = color;
3487 			*(ptr - py) = color;
3488 
3489 			while (x++ < y) {
3490 				BE_ALGORITHM();
3491 				BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py);
3492 
3493 				if (Base::_strokeWidth > 1) {
3494 					BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x - 1, y, px, py);
3495 					BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px - pitch, py);
3496 				}
3497 			}
3498 		}
3499 	} else {
3500 		colorFill<PixelType>(ptr - r, ptr + r, color);
3501 		BE_RESET();
3502 
3503 		while (x++ < y) {
3504 			BE_ALGORITHM();
3505 			colorFill<PixelType>(ptr - x + py, ptr + x + py, color);
3506 			colorFill<PixelType>(ptr - x - py, ptr + x - py, color);
3507 			colorFill<PixelType>(ptr - y + px, ptr + y + px, color);
3508 			colorFill<PixelType>(ptr - y - px, ptr + y - px, color);
3509 		}
3510 	}
3511 }
3512 
3513 
3514 template<typename PixelType>
3515 void VectorRendererSpec<PixelType>::
3516 drawCircleAlgClip(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
3517 	int f, ddF_x, ddF_y;
3518 	int x, y, px, py, sw = 0;
3519 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3520 	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3521 
3522 	if (fill_m == kFillDisabled) {
3523 		while (sw++ < Base::_strokeWidth) {
3524 			BE_RESET();
3525 			r--;
3526 
3527 			if (IS_IN_CLIP(x1 + y, y1)) *(ptr + y) = color;
3528 			if (IS_IN_CLIP(x1 - y, y1)) *(ptr - y) = color;
3529 			if (IS_IN_CLIP(x1, y1 + y)) *(ptr + py) = color;
3530 			if (IS_IN_CLIP(x1, y1 - y)) *(ptr - py) = color;
3531 
3532 			while (x++ < y) {
3533 				BE_ALGORITHM();
3534 				BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
3535 
3536 				if (Base::_strokeWidth > 1) {
3537 					BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x - 1, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
3538 					BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px - pitch, py, x1, y1, x1, y1, x1, y1, x1, y1);
3539 				}
3540 			}
3541 		}
3542 	} else {
3543 		colorFillClip<PixelType>(ptr - r, ptr + r, color, x1 - r, y1 + r, _clippingArea);
3544 		BE_RESET();
3545 
3546 		while (x++ < y) {
3547 			BE_ALGORITHM();
3548 			colorFillClip<PixelType>(ptr - x + py, ptr + x + py, color, x1 - x, y1 + y, _clippingArea);
3549 			colorFillClip<PixelType>(ptr - x - py, ptr + x - py, color, x1 - x, y1 - y, _clippingArea);
3550 			colorFillClip<PixelType>(ptr - y + px, ptr + y + px, color, x1 - y, y1 + x, _clippingArea);
3551 			colorFillClip<PixelType>(ptr - y - px, ptr + y - px, color, x1 - y, y1 - x, _clippingArea);
3552 		}
3553 	}
3554 }
3555 
3556 
3557 /********************************************************************
3558  ********************************************************************
3559  * SHADOW drawing algorithms - VectorRendererSpec *******************
3560  ********************************************************************
3561  ********************************************************************/
3562 template<typename PixelType>
3563 void VectorRendererSpec<PixelType>::
3564 drawSquareShadow(int x, int y, int w, int h, int offset) {
3565 	// Do nothing for empty rects or no shadow offset.
3566 	if (w <= 0 || h <= 0 || offset <= 0) {
3567 		return;
3568 	}
3569 
3570 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset);
3571 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3572 	int i, j;
3573 
3574 	i = h - offset;
3575 
3576 	while (i--) {
3577 		j = offset;
3578 		while (j--)
3579 			blendPixelPtr(ptr + j, 0, ((offset - j) << 8) / offset);
3580 		ptr += pitch;
3581 	}
3582 
3583 	ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1);
3584 
3585 	while (i++ < offset) {
3586 		j = w - offset;
3587 		while (j--)
3588 			blendPixelPtr(ptr + j, 0, ((offset - i) << 8) / offset);
3589 		ptr += pitch;
3590 	}
3591 
3592 	ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
3593 
3594 	i = 0;
3595 	while (i++ < offset) {
3596 		j = offset - 1;
3597 		while (j--)
3598 			blendPixelPtr(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset));
3599 		ptr += pitch;
3600 	}
3601 }
3602 
3603 template<typename PixelType>
3604 void VectorRendererSpec<PixelType>::
3605 drawSquareShadowClip(int x, int y, int w, int h, int offset) {
3606 	// Do nothing for empty rects or no shadow offset.
3607 	if (w <= 0 || h <= 0 || offset <= 0) {
3608 		return;
3609 	}
3610 
3611 	PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset);
3612 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3613 	int i, j, ptr_x = x+w-1, ptr_y = y+offset;
3614 
3615 	i = h - offset;
3616 
3617 	while (i--) {
3618 		j = offset;
3619 		while (j--)
3620 			blendPixelPtrClip(ptr + j, 0, ((offset - j) << 8) / offset, ptr_x + j, ptr_y);
3621 		ptr += pitch;
3622 		++ptr_y;
3623 	}
3624 
3625 	ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1);
3626 	ptr_x = x + offset;
3627 	ptr_y = y + h - 1;
3628 
3629 	while (i++ < offset) {
3630 		j = w - offset;
3631 		while (j--)
3632 			blendPixelPtrClip(ptr + j, 0, ((offset - i) << 8) / offset, ptr_x + j, ptr_y);
3633 		ptr += pitch;
3634 		++ptr_y;
3635 	}
3636 
3637 	ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
3638 	ptr_x = x + w;
3639 	ptr_y = y + h;
3640 
3641 	i = 0;
3642 	while (i++ < offset) {
3643 		j = offset - 1;
3644 		while (j--)
3645 			blendPixelPtrClip(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset), ptr_x + j, ptr_y);
3646 		ptr += pitch;
3647 		++ptr_y;
3648 	}
3649 }
3650 
3651 template<typename PixelType>
3652 void VectorRendererSpec<PixelType>::
3653 drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
3654 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3655 
3656 	// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
3657 	uint8 expFactor = 3;
3658 	uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
3659 
3660 	// These constants ensure a border of 2px on the left and of each rounded square
3661 	Common::Rect shadowRect(w + offset + 2, h + offset + 1);
3662 	shadowRect.translate((x1 > 2) ? x1 - 2 : x1, y1);
3663 
3664 	// The rounded rectangle drawn on top of this shadow is guaranteed
3665 	// to occlude entirely the following rect with a non-transparent color.
3666 	// As an optimization, we don't draw the shadow inside of it.
3667 	Common::Rect occludingRect(x1, y1, x1 + w, y1 + h);
3668 	occludingRect.top    += r;
3669 	occludingRect.bottom -= r;
3670 
3671 	// Soft shadows are constructed by drawing increasingly
3672 	// darker and smaller rectangles on top of each other.
3673 	for (int i = offset; i >= 0; i--) {
3674 		int f, ddF_x, ddF_y;
3675 		int x, y, px, py;
3676 
3677 		// No more room to draw: abort
3678 		if ((shadowRect.width() < 2*r) ||
3679 			(shadowRect.height() < 2*r)) {
3680 			break;
3681 		}
3682 
3683 		PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left  + r, shadowRect.top + r);
3684 		PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.top + r);
3685 		PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left  + r, shadowRect.bottom - r);
3686 		PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.bottom - r);
3687 
3688 		PixelType color = _format.RGBToColor(0, 0, 0);
3689 
3690 		BE_RESET();
3691 
3692 		// HACK: As we are drawing circles exploiting 8-axis symmetry,
3693 		// there are 4 pixels on each circle which are drawn twice.
3694 		// this is ok on filled circles, but when blending on surfaces,
3695 		// we cannot let it blend twice. awful.
3696 		uint32 hb = 0;
3697 
3698 		// Draw the top and bottom parts of the shadow. Those parts have rounded corners.
3699 		while (x++ < y) {
3700 			BE_ALGORITHM();
3701 
3702 			if (((1 << x) & hb) == 0) {
3703 				blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
3704 				blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha);
3705 				hb |= (1 << x);
3706 			}
3707 
3708 			if (((1 << y) & hb) == 0) {
3709 				blendFill(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha);
3710 				blendFill(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha);
3711 				hb |= (1 << y);
3712 			}
3713 		}
3714 
3715 		// Draw the middle part of the shadow. This part is a rectangle with regular corners.
3716 		PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(0, shadowRect.top + r);
3717 		for (int y2 = shadowRect.top + r; y2 < shadowRect.bottom - r + 1; y2++) {
3718 
3719 			if (occludingRect.top <= y2 && y2 < occludingRect.bottom) {
3720 				if (shadowRect.left < occludingRect.left) {
3721 					blendFill(ptr_fill + shadowRect.left, ptr_fill + occludingRect.left, color, (uint8)alpha);
3722 				}
3723 				if (occludingRect.right < shadowRect.right + 1) {
3724 					blendFill(ptr_fill + occludingRect.right, ptr_fill + shadowRect.right + 1, color, (uint8)alpha);
3725 				}
3726 			} else {
3727 				blendFill(ptr_fill + shadowRect.left, ptr_fill + shadowRect.right + 1, color, (uint8)alpha);
3728 			}
3729 
3730 			ptr_fill += pitch;
3731 		}
3732 
3733 		// Make shadow smaller each iteration
3734 		shadowRect.grow(-1);
3735 
3736 		if (_shadowFillMode == kShadowExponential)
3737 			// Multiply with expfactor
3738 			alpha = (alpha * (expFactor << 8)) >> 9;
3739 	}
3740 }
3741 
3742 template<typename PixelType>
3743 void VectorRendererSpec<PixelType>::
3744 drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) {
3745 	int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
3746 
3747 	// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
3748 	uint8 expFactor = 3;
3749 	uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
3750 
3751 	// These constants ensure a border of 2px on the left and of each rounded square
3752 	Common::Rect shadowRect(w + offset + 2, h + offset + 1);
3753 	shadowRect.translate((x1 > 2) ? x1 - 2 : x1, y1);
3754 
3755 	// The rounded rectangle drawn on top of this shadow is guaranteed
3756 	// to occlude entirely the following rect with a non-transparent color.
3757 	// As an optimization, we don't draw the shadow inside of it.
3758 	Common::Rect occludingRect(x1, y1, x1 + w, y1 + h);
3759 	occludingRect.top    += r;
3760 	occludingRect.bottom -= r;
3761 
3762 	// Soft shadows are constructed by drawing increasingly
3763 	// darker and smaller rectangles on top of each other.
3764 	for (int i = offset; i >= 0; i--) {
3765 		int f, ddF_x, ddF_y;
3766 		int x, y, px, py;
3767 
3768 		PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left  + r, shadowRect.top + r);
3769 		PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.top + r);
3770 		PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left  + r, shadowRect.bottom - r);
3771 		PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.bottom - r);
3772 
3773 		PixelType color = _format.RGBToColor(0, 0, 0);
3774 
3775 		BE_RESET();
3776 
3777 		// HACK: As we are drawing circles exploiting 8-axis symmetry,
3778 		// there are 4 pixels on each circle which are drawn twice.
3779 		// this is ok on filled circles, but when blending on surfaces,
3780 		// we cannot let it blend twice. awful.
3781 		uint32 hb = 0;
3782 
3783 		while (x++ < y) {
3784 			BE_ALGORITHM();
3785 
3786 			if (((1 << x) & hb) == 0) {
3787 				blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha,
3788 				              shadowRect.left + r - y, shadowRect.top + r - x);
3789 				blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha,
3790 				              shadowRect.left + r - y, shadowRect.bottom - r + x);
3791 
3792 				hb |= (1 << x);
3793 			}
3794 
3795 			if (((1 << y) & hb) == 0) {
3796 				blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha,
3797 				              shadowRect.left + r - x, shadowRect.top + r - y);
3798 				blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha,
3799 				              shadowRect.left + r - x, shadowRect.bottom - r + y);
3800 
3801 				hb |= (1 << y);
3802 			}
3803 		}
3804 
3805 		// Draw the middle part of the shadow. This part is a rectangle with regular corners.
3806 		PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(0, shadowRect.top + r);
3807 		for (int y2 = shadowRect.top + r; y2 < shadowRect.bottom - r + 1; y2++) {
3808 
3809 			if (occludingRect.top <= y2 && y2 < occludingRect.bottom) {
3810 				if (shadowRect.left < occludingRect.left) {
3811 					blendFillClip(ptr_fill + shadowRect.left, ptr_fill + occludingRect.left, color, (uint8)alpha,
3812 					              shadowRect.left, y2);
3813 				}
3814 				if (occludingRect.right < shadowRect.right + 1) {
3815 					blendFillClip(ptr_fill + occludingRect.right, ptr_fill + shadowRect.right + 1, color, (uint8)alpha,
3816 					              occludingRect.right, y2);
3817 				}
3818 			} else {
3819 				blendFillClip(ptr_fill + shadowRect.left, ptr_fill + shadowRect.right + 1, color, (uint8)alpha,
3820 				              shadowRect.left, y2);
3821 			}
3822 
3823 			ptr_fill += pitch;
3824 		}
3825 
3826 		// Make shadow smaller each iteration
3827 		shadowRect.grow(-1);
3828 
3829 		if (_shadowFillMode == kShadowExponential)
3830 			// Multiply with expfactor
3831 			alpha = (alpha * (expFactor << 8)) >> 9;
3832 	}
3833 }
3834 
3835 /******************************************************************************/
3836 
3837 
3838 
3839 #ifndef DISABLE_FANCY_THEMES
3840 
3841 /********************************************************************
3842  * ANTIALIASED PRIMITIVES drawing algorithms - VectorRendererAA
3843  ********************************************************************/
3844 /** LINES **/
3845 template<typename PixelType>
3846 void VectorRendererAA<PixelType>::
3847 drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
3848 	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3849 	int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
3850 	int xdir = (x2 > x1) ? 1 : -1;
3851 	uint16 error_tmp, error_acc, gradient;
3852 	uint8 alpha;
3853 
3854 	*ptr = (PixelType)color;
3855 
3856 	if (dx > dy) {
3857 		gradient = (dy << 16) / dx;
3858 		error_acc = 0;
3859 
3860 		while (--dx) {
3861 			error_tmp = error_acc;
3862 			error_acc += gradient;
3863 
3864 			if (error_acc <= error_tmp)
3865 				ptr += pitch;
3866 
3867 			ptr += xdir;
3868 			alpha = (error_acc >> 8);
3869 
3870 			this->blendPixelPtr(ptr, color, ~alpha);
3871 			this->blendPixelPtr(ptr + pitch, color, alpha);
3872 		}
3873 	} else if (dy != 0) {
3874 		gradient = (dx << 16) / dy;
3875 		error_acc = 0;
3876 
3877 		while (--dy) {
3878 			error_tmp = error_acc;
3879 			error_acc += gradient;
3880 
3881 			if (error_acc <= error_tmp)
3882 				ptr += xdir;
3883 
3884 			ptr += pitch;
3885 			alpha = (error_acc >> 8);
3886 
3887 			this->blendPixelPtr(ptr, color, ~alpha);
3888 			this->blendPixelPtr(ptr + xdir, color, alpha);
3889 		}
3890 	}
3891 
3892 	Base::putPixel(x2, y2, color);
3893 }
3894 
3895 /** TAB ALGORITHM */
3896 template<typename PixelType>
3897 void VectorRendererAA<PixelType>::
3898 drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
3899 	// Don't draw anything for empty rects.
3900 	if (w <= 0 || h <= 0) {
3901 		return;
3902 	}
3903 
3904 	int x, y, px, py;
3905 	int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
3906 	int sw = 0, sp = 0, hp = 0;
3907 
3908 	frac_t T = 0, oldT;
3909 	uint8 a1, a2;
3910 	uint32 rsq = r*r;
3911 
3912 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
3913 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
3914 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
3915 
3916 	int real_radius = r;
3917 
3918 	if (fill_m == Base::kFillDisabled) {
3919 		color = 0;
3920 		while (sw++ < Base::_strokeWidth) {
3921 			colorFill<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
3922 			colorFill<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
3923 			sp += pitch;
3924 
3925 			x = r - (sw - 1);
3926 			y = 0;
3927 			T = 0;
3928 			px = pitch * x;
3929 			py = 0;
3930 
3931 
3932 			while (x > y++) {
3933 				WU_ALGORITHM();
3934 
3935 				// sw == 1: outside, sw = _strokeWidth: inside
3936 				if (sw != Base::_strokeWidth)
3937 					a2 = 255;
3938 
3939 				// inner arc
3940 				WU_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py, a2);
3941 
3942 				if (sw == 1) // outer arc
3943 					WU_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px - pitch, py, a1);
3944 			}
3945 		}
3946 
3947 		int short_h = h - r;
3948 
3949 		ptr_fill += pitch * real_radius;
3950 		while (short_h--) {
3951 			colorFill<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color);
3952 			colorFill<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color);
3953 			ptr_fill += pitch;
3954 		}
3955 
3956 		if (baseLeft) {
3957 			sw = 0;
3958 			ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
3959 			while (sw++ < Base::_strokeWidth) {
3960 				colorFill<PixelType>(ptr_fill - baseLeft, ptr_fill, color);
3961 				ptr_fill += pitch;
3962 			}
3963 		}
3964 
3965 		if (baseRight) {
3966 			sw = 0;
3967 			ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
3968 			while (sw++ < Base::_strokeWidth) {
3969 				colorFill<PixelType>(ptr_fill, ptr_fill + baseRight, color);
3970 				ptr_fill += pitch;
3971 			}
3972 		}
3973 	} else {
3974 		PixelType color1, color2;
3975 		color1 = color2 = color;
3976 
3977 		int long_h = h;
3978 		int short_h = h - real_radius;
3979 		x = real_radius;
3980 		y = 0;
3981 		T = 0;
3982 		px = pitch * x;
3983 		py = 0;
3984 
3985 		Base::precalcGradient(long_h);
3986 
3987 		while (x > y++) {
3988 			WU_ALGORITHM();
3989 
3990 			if (fill_m == Base::kFillGradient) {
3991 				color1 = Base::calcGradient(real_radius - x, long_h);
3992 				color2 = Base::calcGradient(real_radius - y, long_h);
3993 
3994 				Base::gradientFill(ptr_tl - x - py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, real_radius - y);
3995 
3996 				// Only fill each horizontal line once (or we destroy
3997 				// the gradient effect at the edges)
3998 				if (T < oldT || y == 1)
3999 					Base::gradientFill(ptr_tl - y - px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, real_radius - x);
4000 
4001 				WU_DRAWCIRCLE_XCOLOR_TOP(ptr_tr, ptr_tl, x, y, px, py, a1, Base::blendPixelPtr);
4002 			} else {
4003 				colorFill<PixelType>(ptr_tl - x - py + 1, ptr_tr + x - py, color);
4004 				if (T < oldT || y == 1)
4005 					colorFill<PixelType>(ptr_tl - y - px + 1, ptr_tr + y - px, color);
4006 
4007 				WU_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py, a1);
4008 			}
4009 		}
4010 
4011 		ptr_fill += pitch * r;
4012 		while (short_h--) {
4013 			if (fill_m == Base::kFillGradient) {
4014 				Base::gradientFill(ptr_fill, w + 1, x1, real_radius++);
4015 			} else {
4016 				colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color);
4017 			}
4018 			ptr_fill += pitch;
4019 		}
4020 	}
4021 }
4022 
4023 
4024 /** ROUNDED SQUARES **/
4025 template<typename PixelType>
4026 void VectorRendererAA<PixelType>::
4027 drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
4028 	int x, y;
4029 	const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
4030 	int px, py;
4031 
4032 	uint32 rsq = r*r;
4033 	frac_t T = 0, oldT;
4034 	uint8 a1, a2;
4035 
4036 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
4037 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
4038 	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
4039 	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
4040 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
4041 
4042 	int sw = 0;
4043 	int short_h = h - 2 * r;
4044 
4045 	int strokeWidth = Base::_strokeWidth;
4046 
4047 	while (sw++ < strokeWidth) {
4048 		PixelType *ptr_fill3 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + sw - 1);
4049 		this->blendFill(ptr_fill3 + r, ptr_fill3 + w + 1 - r, color, alpha_t); // top
4050 
4051 		PixelType *ptr_fill2 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h - sw + 1);
4052 		this->blendFill(ptr_fill2 + r, ptr_fill2 + w + 1 - r, color, alpha_b); // bottom
4053 
4054 		x = r - (sw - 1);
4055 		y = 0;
4056 		T = 0;
4057 		px = pitch * x;
4058 		py = 0;
4059 
4060 		int alphaStep_tr = ((alpha_t - alpha_r) / (x + 1));
4061 		int alphaStep_br = ((alpha_r - alpha_b) / (x + 1));
4062 		int alphaStep_bl = ((alpha_b - alpha_l) / (x + 1));
4063 		int alphaStep_tl = ((alpha_l - alpha_t) / (x + 1));
4064 
4065 		while (x > y++) {
4066 			WU_ALGORITHM();
4067 
4068 			// sw == 1: outside, sw = _strokeWidth: inside
4069 			// We always draw the outer edge AAed, but the inner edge
4070 			// only when the inside isn't filled
4071 			if (sw != strokeWidth || fill_m != Base::kFillDisabled)
4072 				a2 = 255;
4073 
4074 				// inner arc
4075 				WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a2) >> 16));
4076 				WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a2) >> 16));
4077 				WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a2) >> 16));
4078 				WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a2) >> 16));
4079 
4080 				WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a2) >> 16));
4081 				WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a2) >> 16));
4082 				WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a2) >> 16));
4083 				WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a2) >> 16));
4084 
4085 				// outer arc
4086 				if (sw == 1) {
4087 					WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a1) >> 16));
4088 					WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a1) >> 16));
4089 					WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a1) >> 16));
4090 					WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a1) >> 16));
4091 
4092 					WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a1) >> 16));
4093 					WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a1) >> 16));
4094 					WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a1) >> 16));
4095 					WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a1) >> 16));
4096 				}
4097 			}
4098 
4099 		ptr_fill += pitch * r;
4100 
4101 		while (short_h-- >= -2) {
4102 			this->blendFill(ptr_fill, ptr_fill + Base::_strokeWidth, color, alpha_l); // left
4103 			this->blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, alpha_r); // right
4104 			ptr_fill += pitch;
4105 		}
4106 	}
4107 }
4108 
4109 template<typename PixelType>
4110 void VectorRendererAA<PixelType>::
4111 drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
4112 	w -= 2*Base::_strokeWidth;
4113 	h -= 2*Base::_strokeWidth;
4114 
4115 	// Do not draw empty space rounded squares.
4116 	if (w <= 0 || h <= 0) {
4117 		return;
4118 	}
4119 
4120 	int x, y;
4121 	const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
4122 	int px, py;
4123 
4124 	uint32 rsq = r*r;
4125 	frac_t T = 0, oldT;
4126 	uint8 a1, a2;
4127 
4128 	r -= Base::_strokeWidth;
4129 	x1 += Base::_strokeWidth;
4130 	y1 += Base::_strokeWidth;
4131 	rsq = r*r;
4132 
4133 	PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
4134 	PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
4135 	PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
4136 	PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
4137 	PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
4138 
4139 	int short_h = h - 2 * r;
4140 	x = r;
4141 	y = 0;
4142 	T = 0;
4143 	px = pitch * x;
4144 	py = 0;
4145 
4146 	if (fill_m == Base::kFillGradient) {
4147 
4148 		Base::precalcGradient(h);
4149 
4150 		PixelType color1, color2, color3, color4;
4151 		while (x > y++) {
4152 			WU_ALGORITHM();
4153 
4154 			color1 = Base::calcGradient(r - x, h);
4155 			color2 = Base::calcGradient(r - y, h);
4156 			color3 = Base::calcGradient(h - r + x, h);
4157 			color4 = Base::calcGradient(h - r + y, h);
4158 
4159 			Base::gradientFill(ptr_tl - x - py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, r - y);
4160 
4161 			// Only fill each horizontal line once (or we destroy
4162 			// the gradient effect at the edges)
4163 			if (T < oldT || y == 1)
4164 				Base::gradientFill(ptr_tl - y - px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, r - x);
4165 
4166 			Base::gradientFill(ptr_bl - x + py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, h - r + y);
4167 
4168 			// Only fill each horizontal line once (or we destroy
4169 			// the gradient effect at the edges)
4170 			if (T < oldT || y == 1)
4171 				Base::gradientFill(ptr_bl - y + px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, h - r + x);
4172 
4173 			// This shape is used for dialog backgrounds.
4174 			// If we're drawing on top of an empty overlay background,
4175 			// and the overlay supports alpha, we have to do AA by
4176 			// setting the dest alpha channel, instead of blending with
4177 			// dest color channels.
4178 			if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha))
4179 				WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelPtr);
4180 			else
4181 				WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelDestAlphaPtr);
4182 		}
4183 
4184 		ptr_fill += pitch * r;
4185 		while (short_h-- >= 0) {
4186 			Base::gradientFill(ptr_fill, w + 1, x1, r++);
4187 			ptr_fill += pitch;
4188 		}
4189 
4190 	} else {
4191 
4192 		while (x > 1 + y++) {
4193 			WU_ALGORITHM();
4194 
4195 			colorFill<PixelType>(ptr_tl - x - py + 1, ptr_tr + x - py, color);
4196 			if (T < oldT || y == 1)
4197 				colorFill<PixelType>(ptr_tl - y - px + 1, ptr_tr + y - px, color);
4198 
4199 			colorFill<PixelType>(ptr_bl - x + py + 1, ptr_br + x + py, color);
4200 			if (T < oldT || y == 1)
4201 				colorFill<PixelType>(ptr_bl - y + px + 1, ptr_br + y + px, color);
4202 
4203 			WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1);
4204 		}
4205 
4206 		ptr_fill += pitch * r;
4207 		while (short_h-- >= 0) {
4208 			colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color);
4209 			ptr_fill += pitch;
4210 		}
4211 	}
4212 }
4213 
4214 template<typename PixelType>
4215 void VectorRendererAA<PixelType>::
4216 drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
4217 	const uint8 borderAlpha_t = 0;
4218 	const uint8 borderAlpha_r = 127;
4219 	const uint8 borderAlpha_b = 255;
4220 	const uint8 borderAlpha_l = 63;
4221 
4222 	const uint8 bevelAlpha_t = 255;
4223 	const uint8 bevelAlpha_r = 31;
4224 	const uint8 bevelAlpha_b = 0;
4225 	const uint8 bevelAlpha_l = 127;
4226 
4227 	if (Base::_strokeWidth) {
4228 		if (r != 0 && Base::_bevel > 0) {
4229 			drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
4230 			drawBorderRoundedSquareAlg(x1, y1, r, w, h, Base::_bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
4231 		} else {
4232 			drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
4233 		}
4234 	}
4235 
4236 	// If only border is visible
4237 	if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
4238 		if (fill_m == Base::kFillBackground)
4239 			drawInteriorRoundedSquareAlg(x1, y1, r, w, h, Base::_bgColor, fill_m);
4240 		else
4241 			drawInteriorRoundedSquareAlg(x1, y1, r, w, h, color, fill_m);
4242 	}
4243 }
4244 
4245 /** CIRCLES **/
4246 template<typename PixelType>
4247 void VectorRendererAA<PixelType>::
4248 drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
4249 	int x, y, sw = 0;
4250 	const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
4251 	int px, py;
4252 
4253 	uint32 rsq = r*r;
4254 	frac_t T = 0, oldT;
4255 	uint8 a1, a2;
4256 
4257 	PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
4258 
4259 	if (fill_m == VectorRenderer::kFillDisabled) {
4260 		while (sw++ < Base::_strokeWidth) {
4261 			x = r - (sw - 1);
4262 			y = 0;
4263 			T = 0;
4264 			px = pitch * x;
4265 			py = 0;
4266 
4267 			*(ptr + x) = (PixelType)color;
4268 			*(ptr - x) = (PixelType)color;
4269 			*(ptr + px) = (PixelType)color;
4270 			*(ptr - px) = (PixelType)color;
4271 
4272 			while (x > y++) {
4273 				WU_ALGORITHM();
4274 
4275 				if (sw != 1 && sw != Base::_strokeWidth)
4276 					a2 = a1 = 255;
4277 
4278 				WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, (x - 1), y, (px - pitch), py, a2);
4279 				WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1);
4280 			}
4281 		}
4282 	} else {
4283 		colorFill<PixelType>(ptr - r, ptr + r + 1, color);
4284 		x = r;
4285 		y = 0;
4286 		T = 0;
4287 		px = pitch * x;
4288 		py = 0;
4289 
4290 		while (x > y++) {
4291 			WU_ALGORITHM();
4292 
4293 			colorFill<PixelType>(ptr - x + py, ptr + x + py, color);
4294 			colorFill<PixelType>(ptr - x - py, ptr + x - py, color);
4295 			colorFill<PixelType>(ptr - y + px, ptr + y + px, color);
4296 			colorFill<PixelType>(ptr - y - px, ptr + y - px, color);
4297 
4298 			WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1);
4299 		}
4300 	}
4301 }
4302 
4303 #endif
4304 
4305 }
4306