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