]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CBlit.h
Merging r6128 through r6139 from trunk to ogl-es branch.
[irrlicht.git] / source / Irrlicht / CBlit.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef _C_BLIT_H_INCLUDED_\r
6 #define _C_BLIT_H_INCLUDED_\r
7 \r
8 #include "SoftwareDriver2_helper.h"\r
9 \r
10 namespace irr\r
11 {\r
12 \r
13 //! f18 - fixpoint 14.18 limit to 16k Textures\r
14 #define CBLIT_USE_FIXPOINT18\r
15 \r
16 #if defined(CBLIT_USE_FIXPOINT18)\r
17         typedef int f18;\r
18         #define f18_one 262144\r
19         #define f18_zero 0\r
20         #define f32_to_f18(x)((f18)floorf(((x) * 262144.f) + 0.f))\r
21         #define f32_to_f32(x)(x)\r
22         #define f18_floor(x) ((x)>>18)\r
23         #define f18_round(x) ((x+131.072)>>18)\r
24 #else\r
25         typedef float f18;\r
26         #define f18_one 1.f\r
27         #define f18_zero_dot_five 0.5f\r
28         #define f18_zero 0.f\r
29         #define f32_to_f18(x)(x)\r
30         #define f32_to_f32(x)(x)\r
31         #define f18_floor(x) ((int)(x))\r
32         #define f18_round(x) ((int)(x+0.5f))\r
33 #endif\r
34 \r
35         struct SBlitJob\r
36         {\r
37                 AbsRectangle Dest;\r
38                 AbsRectangle Source;\r
39 \r
40                 u32 argb;\r
41 \r
42                 const void* src;\r
43                 void* dst;\r
44 \r
45                 u32 width;              //draw size\r
46                 u32 height;\r
47 \r
48                 u32 srcPixelMul; //pixel byte size\r
49                 u32 dstPixelMul;\r
50 \r
51                 int srcPitch;   //scanline byte size. allow negative for mirror\r
52                 u32 dstPitch;\r
53 \r
54                 bool stretch;\r
55                 f32 x_stretch;\r
56                 f32 y_stretch;\r
57         };\r
58 \r
59         // Bitfields Cohen Sutherland\r
60         enum eClipCode\r
61         {\r
62                 CLIPCODE_EMPTY  =       0,\r
63                 CLIPCODE_BOTTOM =       1,\r
64                 CLIPCODE_TOP    =       2,\r
65                 CLIPCODE_LEFT   =       4,\r
66                 CLIPCODE_RIGHT  =       8\r
67         };\r
68 \r
69 inline u32 GetClipCode( const AbsRectangle &r, const core::position2d<s32> &p )\r
70 {\r
71         u32 code = CLIPCODE_EMPTY;\r
72 \r
73         if ( p.X < r.x0 )\r
74                 code = CLIPCODE_LEFT;\r
75         else\r
76         if ( p.X > r.x1 )\r
77                 code = CLIPCODE_RIGHT;\r
78 \r
79         if ( p.Y < r.y0 )\r
80                 code |= CLIPCODE_TOP;\r
81         else\r
82         if ( p.Y > r.y1 )\r
83                 code |= CLIPCODE_BOTTOM;\r
84 \r
85         return code;\r
86 }\r
87 \r
88 \r
89 /*!\r
90         Cohen Sutherland clipping\r
91         @return: 1 if valid\r
92 */\r
93 \r
94 static int ClipLine(const AbsRectangle &clipping,\r
95                         core::position2d<s32> &p0,\r
96                         core::position2d<s32> &p1,\r
97                         const core::position2d<s32>& p0_in,\r
98                         const core::position2d<s32>& p1_in)\r
99 {\r
100         u32 code0;\r
101         u32 code1;\r
102         u32 code;\r
103 \r
104         p0 = p0_in;\r
105         p1 = p1_in;\r
106 \r
107         code0 = GetClipCode( clipping, p0 );\r
108         code1 = GetClipCode( clipping, p1 );\r
109 \r
110         // trivial accepted\r
111         while ( code0 | code1 )\r
112         {\r
113                 s32 x=0;\r
114                 s32 y=0;\r
115 \r
116                 // trivial reject\r
117                 if ( code0 & code1 )\r
118                         return 0;\r
119 \r
120                 if ( code0 )\r
121                 {\r
122                         // clip first point\r
123                         code = code0;\r
124                 }\r
125                 else\r
126                 {\r
127                         // clip last point\r
128                         code = code1;\r
129                 }\r
130 \r
131                 if ( (code & CLIPCODE_BOTTOM) == CLIPCODE_BOTTOM )\r
132                 {\r
133                         // clip bottom viewport\r
134                         y = clipping.y1;\r
135                         x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y );\r
136                 }\r
137                 else\r
138                 if ( (code & CLIPCODE_TOP) == CLIPCODE_TOP )\r
139                 {\r
140                         // clip to viewport\r
141                         y = clipping.y0;\r
142                         x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y );\r
143                 }\r
144                 else\r
145                 if ( (code & CLIPCODE_RIGHT) == CLIPCODE_RIGHT )\r
146                 {\r
147                         // clip right viewport\r
148                         x = clipping.x1;\r
149                         y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X );\r
150                 }\r
151                 else\r
152                 if ( (code & CLIPCODE_LEFT) == CLIPCODE_LEFT )\r
153                 {\r
154                         // clip left viewport\r
155                         x = clipping.x0;\r
156                         y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X );\r
157                 }\r
158 \r
159                 if ( code == code0 )\r
160                 {\r
161                         // modify first point\r
162                         p0.X = x;\r
163                         p0.Y = y;\r
164                         code0 = GetClipCode( clipping, p0 );\r
165                 }\r
166                 else\r
167                 {\r
168                         // modify second point\r
169                         p1.X = x;\r
170                         p1.Y = y;\r
171                         code1 = GetClipCode( clipping, p1 );\r
172                 }\r
173         }\r
174 \r
175         return 1;\r
176 }\r
177 \r
178 /*\r
179 */\r
180 inline void GetClip(AbsRectangle &clipping, video::IImage * t)\r
181 {\r
182         clipping.x0 = 0;\r
183         clipping.y0 = 0;\r
184         clipping.x1 = t->getDimension().Width - 1;\r
185         clipping.y1 = t->getDimension().Height - 1;\r
186 }\r
187 \r
188 /*\r
189         return alpha in [0;256] Granularity from 32-Bit ARGB\r
190         add highbit alpha ( alpha > 127 ? + 1 )\r
191 */\r
192 static inline u32 extractAlpha(const u32 c)\r
193 {\r
194         return ( c >> 24 ) + ( c >> 31 );\r
195 }\r
196 \r
197 /*\r
198         return alpha in [0;255] Granularity and 32-Bit ARGB\r
199         add highbit alpha ( alpha > 127 ? + 1 )\r
200 */\r
201 static inline u32 packAlpha(const u32 c)\r
202 {\r
203         return (c > 127 ? c - 1 : c) << 24;\r
204 }\r
205 \r
206 \r
207 /*!\r
208         Scale Color by (1/value)\r
209         value 0 - 256 ( alpha )\r
210 */\r
211 inline u32 PixelLerp32(const u32 source, const u32 value)\r
212 {\r
213         u32 srcRB = source & 0x00FF00FF;\r
214         u32 srcXG = (source & 0xFF00FF00) >> 8;\r
215 \r
216         srcRB *= value;\r
217         srcXG *= value;\r
218 \r
219         srcRB >>= 8;\r
220         //srcXG >>= 8;\r
221 \r
222         srcXG &= 0xFF00FF00;\r
223         srcRB &= 0x00FF00FF;\r
224 \r
225         return srcRB | srcXG;\r
226 }\r
227 \r
228 \r
229 /*\r
230 */\r
231 static void RenderLine32_Decal(video::IImage *t,\r
232                                 const core::position2d<s32> &p0,\r
233                                 const core::position2d<s32> &p1,\r
234                                 u32 argb )\r
235 {\r
236         s32 dx = p1.X - p0.X;\r
237         s32 dy = p1.Y - p0.Y;\r
238 \r
239         s32 c;\r
240         s32 m;\r
241         s32 d = 0;\r
242         s32 run;\r
243 \r
244         s32 xInc = 4;\r
245         s32 yInc = (s32) t->getPitch();\r
246 \r
247         if ( dx < 0 )\r
248         {\r
249                 xInc = -xInc;\r
250                 dx = -dx;\r
251         }\r
252 \r
253         if ( dy < 0 )\r
254         {\r
255                 yInc = -yInc;\r
256                 dy = -dy;\r
257         }\r
258 \r
259         u32 *dst;\r
260         dst = (u32*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 4 ) );\r
261 \r
262         if ( dy > dx )\r
263         {\r
264                 s32 tmp;\r
265                 tmp = dx;\r
266                 dx = dy;\r
267                 dy = tmp;\r
268                 tmp = xInc;\r
269                 xInc = yInc;\r
270                 yInc = tmp;\r
271         }\r
272 \r
273         c = dx << 1;\r
274         m = dy << 1;\r
275 \r
276         run = dx;\r
277         do\r
278         {\r
279                 *dst = argb;\r
280 \r
281                 dst = (u32*) ( (u8*) dst + xInc );      // x += xInc\r
282                 d += m;\r
283                 if ( d > dx )\r
284                 {\r
285                         dst = (u32*) ( (u8*) dst + yInc );      // y += yInc\r
286                         d -= c;\r
287                 }\r
288                 run -= 1;\r
289         } while (run>=0);\r
290 }\r
291 \r
292 \r
293 /*\r
294 */\r
295 static void RenderLine32_Blend(video::IImage *t,\r
296                                 const core::position2d<s32> &p0,\r
297                                 const core::position2d<s32> &p1,\r
298                                 u32 argb, u32 alpha)\r
299 {\r
300         s32 dx = p1.X - p0.X;\r
301         s32 dy = p1.Y - p0.Y;\r
302 \r
303         s32 c;\r
304         s32 m;\r
305         s32 d = 0;\r
306         s32 run;\r
307 \r
308         s32 xInc = 4;\r
309         s32 yInc = (s32) t->getPitch();\r
310 \r
311         if ( dx < 0 )\r
312         {\r
313                 xInc = -xInc;\r
314                 dx = -dx;\r
315         }\r
316 \r
317         if ( dy < 0 )\r
318         {\r
319                 yInc = -yInc;\r
320                 dy = -dy;\r
321         }\r
322 \r
323         u32 *dst;\r
324         dst = (u32*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 4 ) );\r
325 \r
326         if ( dy > dx )\r
327         {\r
328                 s32 tmp;\r
329                 tmp = dx;\r
330                 dx = dy;\r
331                 dy = tmp;\r
332                 tmp = xInc;\r
333                 xInc = yInc;\r
334                 yInc = tmp;\r
335         }\r
336 \r
337         c = dx << 1;\r
338         m = dy << 1;\r
339 \r
340         run = dx;\r
341         const u32 packA = packAlpha ( alpha );\r
342         do\r
343         {\r
344                 *dst = packA | PixelBlend32( *dst, argb, alpha );\r
345 \r
346                 dst = (u32*) ( (u8*) dst + xInc );      // x += xInc\r
347                 d += m;\r
348                 if ( d > dx )\r
349                 {\r
350                         dst = (u32*) ( (u8*) dst + yInc );      // y += yInc\r
351                         d -= c;\r
352                 }\r
353                 run -= 1;\r
354         } while (run>=0);\r
355 }\r
356 \r
357 /*\r
358 */\r
359 static void RenderLine16_Decal(video::IImage *t,\r
360                                 const core::position2d<s32> &p0,\r
361                                 const core::position2d<s32> &p1,\r
362                                 u32 argb )\r
363 {\r
364         s32 dx = p1.X - p0.X;\r
365         s32 dy = p1.Y - p0.Y;\r
366 \r
367         s32 c;\r
368         s32 m;\r
369         s32 d = 0;\r
370         s32 run;\r
371 \r
372         s32 xInc = 2;\r
373         s32 yInc = (s32) t->getPitch();\r
374 \r
375         if ( dx < 0 )\r
376         {\r
377                 xInc = -xInc;\r
378                 dx = -dx;\r
379         }\r
380 \r
381         if ( dy < 0 )\r
382         {\r
383                 yInc = -yInc;\r
384                 dy = -dy;\r
385         }\r
386 \r
387         u16 *dst;\r
388         dst = (u16*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 2 ) );\r
389 \r
390         if ( dy > dx )\r
391         {\r
392                 s32 tmp;\r
393                 tmp = dx;\r
394                 dx = dy;\r
395                 dy = tmp;\r
396                 tmp = xInc;\r
397                 xInc = yInc;\r
398                 yInc = tmp;\r
399         }\r
400 \r
401         c = dx << 1;\r
402         m = dy << 1;\r
403 \r
404         run = dx;\r
405         do\r
406         {\r
407                 *dst = (u16)argb;\r
408 \r
409                 dst = (u16*) ( (u8*) dst + xInc );      // x += xInc\r
410                 d += m;\r
411                 if ( d > dx )\r
412                 {\r
413                         dst = (u16*) ( (u8*) dst + yInc );      // y += yInc\r
414                         d -= c;\r
415                 }\r
416                 run -= 1;\r
417         } while (run>=0);\r
418 }\r
419 \r
420 /*\r
421 */\r
422 static void RenderLine16_Blend(video::IImage *t,\r
423                                 const core::position2d<s32> &p0,\r
424                                 const core::position2d<s32> &p1,\r
425                                 u16 argb,\r
426                                 u16 alpha)\r
427 {\r
428         s32 dx = p1.X - p0.X;\r
429         s32 dy = p1.Y - p0.Y;\r
430 \r
431         s32 c;\r
432         s32 m;\r
433         s32 d = 0;\r
434         s32 run;\r
435 \r
436         s32 xInc = 2;\r
437         s32 yInc = (s32) t->getPitch();\r
438 \r
439         if ( dx < 0 )\r
440         {\r
441                 xInc = -xInc;\r
442                 dx = -dx;\r
443         }\r
444 \r
445         if ( dy < 0 )\r
446         {\r
447                 yInc = -yInc;\r
448                 dy = -dy;\r
449         }\r
450 \r
451         u16 *dst;\r
452         dst = (u16*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 2 ) );\r
453 \r
454         if ( dy > dx )\r
455         {\r
456                 s32 tmp;\r
457                 tmp = dx;\r
458                 dx = dy;\r
459                 dy = tmp;\r
460                 tmp = xInc;\r
461                 xInc = yInc;\r
462                 yInc = tmp;\r
463         }\r
464 \r
465         c = dx << 1;\r
466         m = dy << 1;\r
467 \r
468         run = dx;\r
469         const u16 packA = alpha ? 0x8000 : 0;\r
470         do\r
471         {\r
472                 *dst = packA | PixelBlend16( *dst, argb, alpha );\r
473 \r
474                 dst = (u16*) ( (u8*) dst + xInc );      // x += xInc\r
475                 d += m;\r
476                 if ( d > dx )\r
477                 {\r
478                         dst = (u16*) ( (u8*) dst + yInc );      // y += yInc\r
479                         d -= c;\r
480                 }\r
481                 run -= 1;\r
482         } while (run>=0);\r
483 }\r
484 \r
485 \r
486 /*!\r
487 */\r
488 static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job )\r
489 {\r
490         if (job->stretch)\r
491         {\r
492                 const f18 wscale = f32_to_f18(job->x_stretch);\r
493                 const f18 hscale = f32_to_f18(job->y_stretch);\r
494 \r
495                 f18 src_y = f18_zero;\r
496 \r
497                 if (job->srcPixelMul == 4)\r
498                 {\r
499                         const u32 *src = (u32*)(job->src);\r
500                         u32 *dst = (u32*)(job->dst);\r
501 \r
502                         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
503                         {\r
504                                 src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
505 \r
506                                 f18 src_x = f18_zero;\r
507                                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
508                                 {\r
509                                         dst[dx] = src[f18_floor(src_x)];\r
510                                 }\r
511                                 dst = (u32*)((u8*)(dst)+job->dstPitch);\r
512                         }\r
513                 }\r
514                 else if (job->srcPixelMul == 2)\r
515                 {\r
516                         const u16 *src = (u16*)(job->src);\r
517                         u16* dst = (u16*)(job->dst);\r
518 \r
519                         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
520                         {\r
521                                 src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
522 \r
523                                 f18 src_x = f18_zero;\r
524                                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
525                                 {\r
526                                         dst[dx] = src[f18_floor(src_x)];\r
527                                 }\r
528                                 dst = (u16*)((u8*)(dst)+job->dstPitch);\r
529                         }\r
530                 }\r
531         }\r
532         else\r
533         {\r
534                 const size_t widthPitch = job->width * job->dstPixelMul;\r
535                 const void *src = (void*) job->src;\r
536                 void *dst = (void*) job->dst;\r
537 \r
538                 for ( u32 dy = 0; dy < job->height; ++dy )\r
539                 {\r
540                         memcpy( dst, src, widthPitch);\r
541 \r
542                         src = (void*) ( (u8*) (src) + job->srcPitch );\r
543                         dst = (void*) ( (u8*) (dst) + job->dstPitch );\r
544                 }\r
545         }\r
546 }\r
547 \r
548 /*!\r
549 */\r
550 static void executeBlit_TextureCopy_32_to_16( const SBlitJob * job )\r
551 {\r
552         const u32 w = job->width;\r
553         const u32 h = job->height;\r
554         const u32 *src = static_cast<const u32*>(job->src);\r
555         u16 *dst = static_cast<u16*>(job->dst);\r
556 \r
557         if (job->stretch)\r
558         {\r
559                 const float wscale = job->x_stretch;\r
560                 const float hscale = job->y_stretch;\r
561 \r
562                 for ( u32 dy = 0; dy < h; ++dy )\r
563                 {\r
564                         const u32 src_y = (u32)(dy*hscale);\r
565                         src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
566 \r
567                         for ( u32 dx = 0; dx < w; ++dx )\r
568                         {\r
569                                 const u32 src_x = (u32)(dx*wscale);\r
570                                 //16 bit Blitter depends on pre-multiplied color\r
571                                 const u32 s = PixelLerp32( src[src_x] | 0xFF000000, extractAlpha( src[src_x] ) );\r
572                                 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );\r
573                         }\r
574                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
575                 }\r
576         }\r
577         else\r
578         {\r
579                 for ( u32 dy = 0; dy != h; ++dy )\r
580                 {\r
581                         for ( u32 dx = 0; dx != w; ++dx )\r
582                         {\r
583                                 //16 bit Blitter depends on pre-multiplied color\r
584                                 const u32 s = PixelLerp32( src[dx] | 0xFF000000, extractAlpha( src[dx] ) );\r
585                                 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );\r
586                         }\r
587 \r
588                         src = (u32*) ( (u8*) (src) + job->srcPitch );\r
589                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
590                 }\r
591         }\r
592 }\r
593 \r
594 /*!\r
595 */\r
596 static void executeBlit_TextureCopy_24_to_16( const SBlitJob * job )\r
597 {\r
598         const u32 w = job->width;\r
599         const u32 h = job->height;\r
600         const u8 *src = static_cast<const u8*>(job->src);\r
601         u16 *dst = static_cast<u16*>(job->dst);\r
602 \r
603         if (job->stretch)\r
604         {\r
605                 const float wscale = job->x_stretch * 3.f;\r
606                 const float hscale = job->y_stretch;\r
607 \r
608                 for ( u32 dy = 0; dy < h; ++dy )\r
609                 {\r
610                         const u32 src_y = (u32)(dy*hscale);\r
611                         src = (u8*)(job->src) + job->srcPitch*src_y;\r
612 \r
613                         for ( u32 dx = 0; dx < w; ++dx )\r
614                         {\r
615                                 const u8* src_x = src+(u32)(dx*wscale);\r
616                                 dst[dx] = video::RGBA16(src_x[0], src_x[1], src_x[2]);\r
617                         }\r
618                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
619                 }\r
620         }\r
621         else\r
622         {\r
623                 for ( u32 dy = 0; dy != h; ++dy )\r
624                 {\r
625                         const u8* s = src;\r
626                         for ( u32 dx = 0; dx != w; ++dx )\r
627                         {\r
628                                 dst[dx] = video::RGBA16(s[0], s[1], s[2]);\r
629                                 s += 3;\r
630                         }\r
631 \r
632                         src = src+job->srcPitch;\r
633                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
634                 }\r
635         }\r
636 }\r
637 \r
638 \r
639 /*!\r
640 */\r
641 static void executeBlit_TextureCopy_16_to_32( const SBlitJob * job )\r
642 {\r
643         const u32 w = job->width;\r
644         const u32 h = job->height;\r
645         const u16 *src = static_cast<const u16*>(job->src);\r
646         u32 *dst = static_cast<u32*>(job->dst);\r
647 \r
648         if (job->stretch)\r
649         {\r
650                 const float wscale = job->x_stretch;\r
651                 const float hscale = job->y_stretch;\r
652 \r
653                 for ( u32 dy = 0; dy < h; ++dy )\r
654                 {\r
655                         const u32 src_y = (u32)(dy*hscale);\r
656                         src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
657 \r
658                         for ( u32 dx = 0; dx < w; ++dx )\r
659                         {\r
660                                 const u32 src_x = (u32)(dx*wscale);\r
661                                 dst[dx] = video::A1R5G5B5toA8R8G8B8(src[src_x]);\r
662                         }\r
663                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
664                 }\r
665         }\r
666         else\r
667         {\r
668                 for ( u32 dy = 0; dy != h; ++dy )\r
669                 {\r
670                         for ( u32 dx = 0; dx != w; ++dx )\r
671                         {\r
672                                 dst[dx] = video::A1R5G5B5toA8R8G8B8( src[dx] );\r
673                         }\r
674 \r
675                         src = (u16*) ( (u8*) (src) + job->srcPitch );\r
676                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
677                 }\r
678         }\r
679 }\r
680 \r
681 static void executeBlit_TextureCopy_16_to_24( const SBlitJob * job )\r
682 {\r
683         const u32 w = job->width;\r
684         const u32 h = job->height;\r
685         const u16 *src = static_cast<const u16*>(job->src);\r
686         u8 *dst = static_cast<u8*>(job->dst);\r
687 \r
688         if (job->stretch)\r
689         {\r
690                 const float wscale = job->x_stretch;\r
691                 const float hscale = job->y_stretch;\r
692 \r
693                 for ( u32 dy = 0; dy < h; ++dy )\r
694                 {\r
695                         const u32 src_y = (u32)(dy*hscale);\r
696                         src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
697 \r
698                         for ( u32 dx = 0; dx < w; ++dx )\r
699                         {\r
700                                 const u32 src_x = (u32)(dx*wscale);\r
701                                 u32 color = video::A1R5G5B5toA8R8G8B8(src[src_x]);\r
702                                 u8 * writeTo = &dst[dx * 3];\r
703                                 *writeTo++ = (color >> 16)& 0xFF;\r
704                                 *writeTo++ = (color >> 8) & 0xFF;\r
705                                 *writeTo++ = color & 0xFF;\r
706                         }\r
707                         dst += job->dstPitch;\r
708                 }\r
709         }\r
710         else\r
711         {\r
712                 for ( u32 dy = 0; dy != h; ++dy )\r
713                 {\r
714                         for ( u32 dx = 0; dx != w; ++dx )\r
715                         {\r
716                                 u32 color = video::A1R5G5B5toA8R8G8B8(src[dx]);\r
717                                 u8 * writeTo = &dst[dx * 3];\r
718                                 *writeTo++ = (color >> 16)& 0xFF;\r
719                                 *writeTo++ = (color >> 8) & 0xFF;\r
720                                 *writeTo++ = color & 0xFF;\r
721                         }\r
722 \r
723                         src = (u16*) ( (u8*) (src) + job->srcPitch );\r
724                         dst += job->dstPitch;\r
725                 }\r
726         }\r
727 }\r
728 \r
729 /*!\r
730 */\r
731 static void executeBlit_TextureCopy_24_to_32( const SBlitJob * job )\r
732 {\r
733         const u32 w = job->width;\r
734         const u32 h = job->height;\r
735         const u8 *src = static_cast<const u8*>(job->src);\r
736         u32 *dst = static_cast<u32*>(job->dst);\r
737 \r
738         if (job->stretch)\r
739         {\r
740                 const float wscale = job->x_stretch * 3.f;\r
741                 const float hscale = job->y_stretch;\r
742 \r
743                 for ( u32 dy = 0; dy < h; ++dy )\r
744                 {\r
745                         const u32 src_y = (u32)(dy*hscale);\r
746                         src = (const u8*)job->src+(job->srcPitch*src_y);\r
747 \r
748                         for ( u32 dx = 0; dx < w; ++dx )\r
749                         {\r
750                                 const u8* s = src+(u32)(dx*wscale);\r
751                                 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];\r
752                         }\r
753                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
754                 }\r
755         }\r
756         else\r
757         {\r
758                 for ( u32 dy = 0; dy < job->height; ++dy )\r
759                 {\r
760                         const u8* s = src;\r
761 \r
762                         for ( u32 dx = 0; dx < job->width; ++dx )\r
763                         {\r
764                                 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];\r
765                                 s += 3;\r
766                         }\r
767 \r
768                         src = src + job->srcPitch;\r
769                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
770                 }\r
771         }\r
772 }\r
773 \r
774 static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job )\r
775 {\r
776         const u32 w = job->width;\r
777         const u32 h = job->height;\r
778         const u32 *src = static_cast<const u32*>(job->src);\r
779         u8 *dst = static_cast<u8*>(job->dst);\r
780 \r
781         if (job->stretch)\r
782         {\r
783                 const float wscale = job->x_stretch;\r
784                 const float hscale = job->y_stretch;\r
785 \r
786                 for ( u32 dy = 0; dy < h; ++dy )\r
787                 {\r
788                         const u32 src_y = (u32)(dy*hscale);\r
789                         src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);\r
790 \r
791                         for ( u32 dx = 0; dx < w; ++dx )\r
792                         {\r
793                                 const u32 src_x = src[(u32)(dx*wscale)];\r
794                                 u8 * writeTo = &dst[dx * 3];\r
795                                 *writeTo++ = (src_x >> 16)& 0xFF;\r
796                                 *writeTo++ = (src_x >> 8) & 0xFF;\r
797                                 *writeTo++ = src_x & 0xFF;\r
798                         }\r
799                         dst += job->dstPitch;\r
800                 }\r
801         }\r
802         else\r
803         {\r
804                 for ( u32 dy = 0; dy != h; ++dy )\r
805                 {\r
806                         for ( u32 dx = 0; dx != w; ++dx )\r
807                         {\r
808                                 u8 * writeTo = &dst[dx * 3];\r
809                                 *writeTo++ = (src[dx] >> 16)& 0xFF;\r
810                                 *writeTo++ = (src[dx] >> 8) & 0xFF;\r
811                                 *writeTo++ = src[dx] & 0xFF;\r
812                         }\r
813 \r
814                         src = (u32*) ( (u8*) (src) + job->srcPitch );\r
815                         dst += job->dstPitch;\r
816                 }\r
817         }\r
818 }\r
819 \r
820 /*!\r
821 */\r
822 static void executeBlit_TextureBlend_16_to_16( const SBlitJob * job )\r
823 {\r
824         const f18 wscale = f32_to_f18(job->x_stretch);\r
825         const f18 hscale = f32_to_f18(job->y_stretch);\r
826 \r
827         f18 src_y = f18_zero;\r
828         u16 *dst = (u16*)job->dst;\r
829 \r
830         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
831         {\r
832                 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
833                 f18 src_x = f18_zero;\r
834                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
835                 {\r
836                         dst[dx] = PixelBlend16(dst[dx], src[f18_floor(src_x)]);\r
837                 }\r
838                 dst = (u16*)((u8*)(dst)+job->dstPitch);\r
839         }\r
840 }\r
841 \r
842 /*!\r
843 */\r
844 static void executeBlit_TextureBlend_32_to_32( const SBlitJob * job )\r
845 {\r
846         const f18 wscale = f32_to_f18(job->x_stretch);\r
847         const f18 hscale = f32_to_f18(job->y_stretch);\r
848 \r
849         f18 src_y = f18_zero;\r
850         u32 *dst = (u32*)job->dst;\r
851         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
852         {\r
853                 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
854 \r
855                 f18 src_x = f18_zero;\r
856                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
857                 {\r
858                         dst[dx] = PixelBlend32(dst[dx], src[f18_floor(src_x)]);\r
859                 }\r
860                 dst = (u32*)((u8*)(dst)+job->dstPitch);\r
861         }\r
862 }\r
863 \r
864 /*!\r
865 */\r
866 static void executeBlit_TextureBlendColor_16_to_16( const SBlitJob * job )\r
867 {\r
868         const u16 blend = video::A8R8G8B8toA1R5G5B5(job->argb);\r
869 \r
870         const f18 wscale = f32_to_f18(job->x_stretch);\r
871         const f18 hscale = f32_to_f18(job->y_stretch);\r
872 \r
873         f18 src_y = f18_zero;\r
874         u16 *dst = (u16*)job->dst;\r
875         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
876         {\r
877                 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
878                 f18 src_x = f18_zero;\r
879                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
880                 {\r
881                         u16 c0 = src[f18_floor(src_x)];\r
882                         if (0 == (c0 & 0x8000))\r
883                                 continue;\r
884 \r
885                         dst[dx] = PixelMul16_2(c0, blend);\r
886                 }\r
887                 dst = (u16*)((u8*)(dst)+job->dstPitch);\r
888         }\r
889 }\r
890 \r
891 \r
892 /*!\r
893 */\r
894 static void executeBlit_TextureBlendColor_32_to_32( const SBlitJob * job )\r
895 {\r
896         const f18 wscale = f32_to_f18(job->x_stretch);\r
897         const f18 hscale = f32_to_f18(job->y_stretch);\r
898 \r
899         u32* dst = (u32*)job->dst;\r
900         f18 src_y = f18_zero;\r
901         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
902         {\r
903                 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
904 \r
905                 f18 src_x = f18_zero;\r
906                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
907                 {\r
908                         dst[dx] = PixelBlend32(dst[dx], PixelMul32_2(src[f18_floor(src_x)], job->argb));\r
909                 }\r
910                 dst = (u32*)((u8*)(dst)+job->dstPitch);\r
911         }\r
912 }\r
913 \r
914 /*!\r
915 */\r
916 static void executeBlit_Color_16_to_16( const SBlitJob * job )\r
917 {\r
918         const u16 c = video::A8R8G8B8toA1R5G5B5(job->argb);\r
919         u16 *dst = (u16*) job->dst;\r
920 \r
921         for ( u32 dy = 0; dy < job->height; ++dy )\r
922         {\r
923                 memset16(dst, c, job->srcPitch);\r
924                 dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
925         }\r
926 }\r
927 \r
928 /*!\r
929 */\r
930 static void executeBlit_Color_32_to_32( const SBlitJob * job )\r
931 {\r
932         u32 *dst = (u32*) job->dst;\r
933 \r
934         for ( u32 dy = 0; dy < job->height; ++dy )\r
935         {\r
936                 memset32( dst, job->argb, job->srcPitch );\r
937                 dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
938         }\r
939 }\r
940 \r
941 /*!\r
942 */\r
943 static void executeBlit_ColorAlpha_16_to_16( const SBlitJob * job )\r
944 {\r
945         u16 *dst = (u16*) job->dst;\r
946 \r
947         const u16 alpha = extractAlpha( job->argb ) >> 3;\r
948         if ( 0 == alpha )\r
949                 return;\r
950         const u32 src = video::A8R8G8B8toA1R5G5B5( job->argb );\r
951 \r
952         for ( u32 dy = 0; dy != job->height; ++dy )\r
953         {\r
954                 for ( u32 dx = 0; dx != job->width; ++dx )\r
955                 {\r
956                         dst[dx] = PixelBlend16( dst[dx], src, alpha );\r
957                 }\r
958                 dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
959         }\r
960 }\r
961 \r
962 /*!\r
963 */\r
964 static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job )\r
965 {\r
966         const u32 alpha = extractAlpha( job->argb );\r
967         if (0 == alpha)\r
968                 return;\r
969 \r
970         u32 *dst = (u32*)job->dst;\r
971         for ( u32 dy = 0; dy < job->height; ++dy )\r
972         {\r
973                 for ( u32 dx = 0; dx < job->width; ++dx )\r
974                 {\r
975                         dst[dx] = PixelBlend32( dst[dx], job->argb, alpha );\r
976                 }\r
977                 dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
978         }\r
979 \r
980 }\r
981 \r
982 /*!\r
983         Pixel =>\r
984                         color = sourceAlpha > 0 ? source, else dest\r
985                         alpha = max(destAlpha, sourceAlpha)\r
986 */\r
987 inline u16 PixelCombine16(const u16 c2, const u16 c1)\r
988 {\r
989         if (video::getAlpha(c1) > 0)\r
990                 return c1;\r
991         else\r
992                 return c2;\r
993 }\r
994 \r
995 /*!\r
996         Combine alpha channels (increases alpha / reduces transparency)\r
997 */\r
998 static void executeBlit_TextureCombineColor_16_to_16( const SBlitJob * job )\r
999 {\r
1000         const u32 w = job->width * 2;\r
1001         const u32 h = job->height * 2;\r
1002         u16* src = (u16*) job->src;\r
1003         u16* dst = (u16*) job->dst;\r
1004 \r
1005         const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );\r
1006 \r
1007         /*\r
1008                 Stretch not supported.\r
1009         */\r
1010         for ( u32 dy = 0; dy != h; dy++ )\r
1011         {\r
1012                 for ( u32 dx = 0; dx != w; dx++ )\r
1013                 {\r
1014                         const u16 src_x = src[dx];\r
1015                         const u16 dst_x = dst[dx];\r
1016                         dst[dx] = PixelCombine16( dst_x, PixelMul16_2( src_x, jobColor ) );\r
1017                 }\r
1018                 src = (u16*) ( (u8*) (src) + job->srcPitch );\r
1019                 dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
1020         }\r
1021 }\r
1022 \r
1023 /*!\r
1024         Combine alpha channels (increases alpha / reduces transparency)\r
1025 */\r
1026 static void executeBlit_TextureCombineColor_16_to_24( const SBlitJob * job )\r
1027 {\r
1028         const u32 w = job->width;\r
1029         const u32 h = job->height;\r
1030         const u16 *src = static_cast<const u16*>(job->src);\r
1031         u8 *dst = static_cast<u8*>(job->dst);\r
1032 \r
1033         const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );\r
1034 \r
1035         if (job->stretch)\r
1036         {\r
1037                 const float wscale = job->x_stretch;\r
1038                 const float hscale = job->y_stretch;\r
1039 \r
1040                 for ( u32 dy = 0; dy < h; ++dy )\r
1041                 {\r
1042                         const u32 src_y = (u32)(dy*hscale);\r
1043                         src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
1044 \r
1045                         for ( u32 dx = 0; dx < w; ++dx )\r
1046                         {\r
1047                                 const u32 src_x = (u32)(dx*wscale);\r
1048                                 u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[src_x]), jobColor);\r
1049                                 u8 * writeTo = &dst[dx * 3];\r
1050                                 if ( video::getAlpha(src[src_x]) > 0 ) // only overlay if source has visible alpha (alpha == 1)\r
1051                                 {\r
1052                                         *writeTo++ = (color >> 16)& 0xFF;\r
1053                                         *writeTo++ = (color >> 8) & 0xFF;\r
1054                                         *writeTo++ = color & 0xFF;\r
1055                                 }\r
1056                         }\r
1057                         dst += job->dstPitch;\r
1058                 }\r
1059         }\r
1060         else\r
1061         {\r
1062                 for ( u32 dy = 0; dy != h; ++dy )\r
1063                 {\r
1064                         for ( u32 dx = 0; dx != w; ++dx )\r
1065                         {\r
1066                                 u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[dx]), jobColor);\r
1067                                 u8 * writeTo = &dst[dx * 3];\r
1068                                 if ( video::getAlpha(src[dx]) > 0 ) // only overlay if source has visible alpha (alpha == 1)\r
1069                                 {\r
1070                                         *writeTo++ = (color >> 16)& 0xFF;\r
1071                                         *writeTo++ = (color >> 8) & 0xFF;\r
1072                                         *writeTo++ = color & 0xFF;\r
1073                                 }\r
1074                         }\r
1075 \r
1076                         src = (u16*) ( (u8*) (src) + job->srcPitch );\r
1077                         dst += job->dstPitch;\r
1078                 }\r
1079         }\r
1080 }\r
1081 \r
1082 /*!\r
1083         Pixel =>\r
1084                         color = dest * ( 1 - SourceAlpha ) + source * SourceAlpha,\r
1085                         alpha = destAlpha * ( 1 - SourceAlpha ) + sourceAlpha\r
1086 \r
1087         where "1" means "full scale" (255)\r
1088 */\r
1089 inline u32 PixelCombine32(const u32 c2, const u32 c1)\r
1090 {\r
1091         // alpha test\r
1092         u32 alpha = c1 & 0xFF000000;\r
1093 \r
1094         if (0 == alpha)\r
1095                 return c2;\r
1096         if (0xFF000000 == alpha)\r
1097         {\r
1098                 return c1;\r
1099         }\r
1100 \r
1101         alpha >>= 24;\r
1102 \r
1103         // add highbit alpha, if ( alpha > 127 ) alpha += 1;\r
1104         // stretches [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8\r
1105         alpha += (alpha >> 7);\r
1106 \r
1107         u32 srcRB = c1 & 0x00FF00FF;\r
1108         u32 srcXG = c1 & 0x0000FF00;\r
1109 \r
1110         u32 dstRB = c2 & 0x00FF00FF;\r
1111         u32 dstXG = c2 & 0x0000FF00;\r
1112 \r
1113 \r
1114         u32 rb = srcRB - dstRB;\r
1115         u32 xg = srcXG - dstXG;\r
1116 \r
1117         rb *= alpha;\r
1118         xg *= alpha;\r
1119         rb >>= 8;\r
1120         xg >>= 8;\r
1121 \r
1122         rb += dstRB;\r
1123         xg += dstXG;\r
1124 \r
1125         rb &= 0x00FF00FF;\r
1126         xg &= 0x0000FF00;\r
1127 \r
1128         u32 sa = c1 >> 24;\r
1129         u32 da = c2 >> 24;\r
1130         u32 blendAlpha_fix8 = (sa * 256 + da * (256 - alpha)) >> 8;\r
1131         return blendAlpha_fix8 << 24 | rb | xg;\r
1132 }\r
1133 \r
1134 /*!\r
1135         Combine alpha channels (increases alpha / reduces transparency)\r
1136         Destination alpha is treated as full 255\r
1137 */\r
1138 static void executeBlit_TextureCombineColor_32_to_24( const SBlitJob * job )\r
1139 {\r
1140         const u32 w = job->width;\r
1141         const u32 h = job->height;\r
1142         const u32 *src = static_cast<const u32*>(job->src);\r
1143         u8 *dst = static_cast<u8*>(job->dst);\r
1144 \r
1145         if (job->stretch)\r
1146         {\r
1147                 const float wscale = job->x_stretch;\r
1148                 const float hscale = job->y_stretch;\r
1149 \r
1150                 for ( u32 dy = 0; dy < h; ++dy )\r
1151                 {\r
1152                         const u32 src_y = (u32)(dy*hscale);\r
1153                         src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);\r
1154 \r
1155                         for ( u32 dx = 0; dx < w; ++dx )\r
1156                         {\r
1157                                 const u32 src_x = src[(u32)(dx*wscale)];\r
1158                                 u8* writeTo = &dst[dx * 3];\r
1159                                 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];\r
1160                                 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src_x, job->argb ) );\r
1161                                 *writeTo++ = (combo >> 16) & 0xFF;\r
1162                                 *writeTo++ = (combo >> 8) & 0xFF;\r
1163                                 *writeTo++ = combo & 0xFF;\r
1164                         }\r
1165                         dst += job->dstPitch;\r
1166                 }\r
1167         }\r
1168         else\r
1169         {\r
1170                 for ( u32 dy = 0; dy != h; ++dy )\r
1171                 {\r
1172                         for ( u32 dx = 0; dx != w; ++dx )\r
1173                         {\r
1174                                 u8* writeTo = &dst[dx * 3];\r
1175                                 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];\r
1176                                 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src[dx], job->argb ) );\r
1177                                 *writeTo++ = (combo >> 16) & 0xFF;\r
1178                                 *writeTo++ = (combo >> 8) & 0xFF;\r
1179                                 *writeTo++ = combo & 0xFF;\r
1180                         }\r
1181 \r
1182                         src = (u32*) ( (u8*) (src) + job->srcPitch );\r
1183                         dst += job->dstPitch;\r
1184                 }\r
1185         }\r
1186 }\r
1187 \r
1188 /*!\r
1189         Combine alpha channels (increases alpha / reduces transparency)\r
1190 */\r
1191 static void executeBlit_TextureCombineColor_32_to_32( const SBlitJob * job )\r
1192 {\r
1193         u32 *src = (u32*) job->src;\r
1194         u32 *dst = (u32*) job->dst;\r
1195 \r
1196         for ( u32 dy = 0; dy != job->height; ++dy )\r
1197         {\r
1198                 for (u32 dx = 0; dx != job->width; ++dx )\r
1199                 {\r
1200                         dst[dx] = PixelCombine32( dst[dx], PixelMul32_2( src[dx], job->argb ) );\r
1201                 }\r
1202                 src = (u32*) ( (u8*) (src) + job->srcPitch );\r
1203                 dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
1204         }\r
1205 }\r
1206 \r
1207 // Blitter Operation\r
1208 enum eBlitter\r
1209 {\r
1210         BLITTER_INVALID = 0,\r
1211         BLITTER_COLOR,\r
1212         BLITTER_COLOR_ALPHA,\r
1213         BLITTER_TEXTURE,\r
1214         BLITTER_TEXTURE_ALPHA_BLEND,\r
1215         BLITTER_TEXTURE_ALPHA_COLOR_BLEND,\r
1216         BLITTER_TEXTURE_COMBINE_ALPHA,\r
1217 };\r
1218 \r
1219 typedef void (*tExecuteBlit) ( const SBlitJob * job );\r
1220 \r
1221 \r
1222 /*!\r
1223 */\r
1224 struct blitterTable\r
1225 {\r
1226         eBlitter operation;\r
1227         s32 destFormat;\r
1228         s32 sourceFormat;\r
1229         tExecuteBlit func;\r
1230 };\r
1231 \r
1232 static const blitterTable blitTable[] =\r
1233 {\r
1234         { BLITTER_TEXTURE, -2, -2, executeBlit_TextureCopy_x_to_x },\r
1235         { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_16 },\r
1236         { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },\r
1237         { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_32 },\r
1238         { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },\r
1239         { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_24 },\r
1240         { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_24 },\r
1241         { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlend_16_to_16 },\r
1242         { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlend_32_to_32 },\r
1243         { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlendColor_16_to_16 },\r
1244         { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlendColor_32_to_32 },\r
1245         { BLITTER_COLOR, video::ECF_A1R5G5B5, -1, executeBlit_Color_16_to_16 },\r
1246         { BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 },\r
1247         { BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 },\r
1248         { BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 },\r
1249         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_32 },\r
1250         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },\r
1251         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_24 },\r
1252         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_x_to_x },\r
1253         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },\r
1254         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_16 },\r
1255         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },\r
1256         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_24 },\r
1257         { BLITTER_INVALID, -1, -1, 0 }\r
1258 };\r
1259 \r
1260 \r
1261 static inline tExecuteBlit getBlitter2( eBlitter operation,const video::IImage * dest,const video::IImage * source )\r
1262 {\r
1263         video::ECOLOR_FORMAT sourceFormat = (video::ECOLOR_FORMAT) ( source ? source->getColorFormat() : -1 );\r
1264         video::ECOLOR_FORMAT destFormat = (video::ECOLOR_FORMAT) ( dest ? dest->getColorFormat() : -1 );\r
1265 \r
1266         const blitterTable * b = blitTable;\r
1267 \r
1268         while ( b->operation != BLITTER_INVALID )\r
1269         {\r
1270                 if ( b->operation == operation )\r
1271                 {\r
1272                         if (( b->destFormat == -1 || b->destFormat == destFormat ) &&\r
1273                                 ( b->sourceFormat == -1 || b->sourceFormat == sourceFormat ) )\r
1274                                         return b->func;\r
1275                         else\r
1276                         if ( b->destFormat == -2 && ( sourceFormat == destFormat ) )\r
1277                                         return b->func;\r
1278                 }\r
1279                 b += 1;\r
1280         }\r
1281         return 0;\r
1282 }\r
1283 \r
1284 \r
1285 // bounce clipping to texture\r
1286 inline void setClip(AbsRectangle &out, const core::rect<s32> *clip,\r
1287         const video::IImage* tex, s32 passnative, const core::dimension2d<u32>* tex_org)\r
1288 {\r
1289         if (0 == tex)\r
1290         {\r
1291                 if (clip && passnative)\r
1292                 {\r
1293                         out.x0 = clip->UpperLeftCorner.X;\r
1294                         out.x1 = clip->LowerRightCorner.X;\r
1295                         out.y0 = clip->UpperLeftCorner.Y;\r
1296                         out.y1 = clip->LowerRightCorner.Y;\r
1297                 }\r
1298                 else\r
1299                 {\r
1300                         out.x0 = 0;\r
1301                         out.x1 = 0;\r
1302                         out.y0 = 0;\r
1303                         out.y1 = 0;\r
1304                 }\r
1305                 return;\r
1306         }\r
1307 \r
1308         const s32 w = tex->getDimension().Width;\r
1309         const s32 h = tex->getDimension().Height;\r
1310 \r
1311         //driver could have changed texture size.\r
1312         if (clip && tex_org && ((u32)w != tex_org->Width || (u32)h != tex_org->Height))\r
1313         {\r
1314                 out.x0 = core::s32_clamp((clip->UpperLeftCorner.X*w) / tex_org->Width, 0, w - 1);\r
1315                 out.x1 = core::s32_clamp((clip->LowerRightCorner.X*w) / tex_org->Width, out.x0, w);\r
1316                 out.y0 = core::s32_clamp((clip->UpperLeftCorner.Y*h) / tex_org->Height, 0, h - 1);\r
1317                 out.y1 = core::s32_clamp((clip->LowerRightCorner.Y*h) / tex_org->Height, out.y0, h);\r
1318         }\r
1319         else if (clip)\r
1320         {\r
1321                 //y-1 to prevent starting on illegal memory (not ideal!).\r
1322                 out.x0 = core::s32_clamp(clip->UpperLeftCorner.X, 0, w - 1);\r
1323                 out.x1 = core::s32_clamp(clip->LowerRightCorner.X, passnative ? 0 : out.x0, w);\r
1324                 out.y0 = core::s32_clamp(clip->UpperLeftCorner.Y, 0, h - 1);\r
1325                 out.y1 = core::s32_clamp(clip->LowerRightCorner.Y, passnative ? 0 : out.y0, h);\r
1326         }\r
1327         else\r
1328         {\r
1329                 out.x0 = 0;\r
1330                 out.y0 = 0;\r
1331                 out.x1 = w;\r
1332                 out.y1 = h;\r
1333         }\r
1334 \r
1335 }\r
1336 \r
1337 /*!\r
1338         a generic 2D Blitter\r
1339 */\r
1340 static s32 Blit(eBlitter operation,\r
1341                 video::IImage * dest,\r
1342                 const core::rect<s32> *destClipping,\r
1343                 const core::position2d<s32> *destPos,\r
1344                 video::IImage * const source,\r
1345                 const core::rect<s32> *sourceClipping,\r
1346                 u32 argb)\r
1347 {\r
1348         tExecuteBlit blitter = getBlitter2( operation, dest, source );\r
1349         if ( 0 == blitter )\r
1350         {\r
1351                 return 0;\r
1352         }\r
1353 \r
1354         // Clipping\r
1355         AbsRectangle sourceClip;\r
1356         AbsRectangle destClip;\r
1357         AbsRectangle v;\r
1358 \r
1359         SBlitJob job;\r
1360 \r
1361         setClip ( sourceClip, sourceClipping, source, 1,0 );\r
1362         setClip ( destClip, destClipping, dest, 0,0 );\r
1363 \r
1364         v.x0 = destPos ? destPos->X : 0;\r
1365         v.y0 = destPos ? destPos->Y : 0;\r
1366         v.x1 = v.x0 + ( sourceClip.x1 - sourceClip.x0 );\r
1367         v.y1 = v.y0 + ( sourceClip.y1 - sourceClip.y0 );\r
1368 \r
1369         if ( !intersect( job.Dest, destClip, v ) )\r
1370                 return 0;\r
1371 \r
1372         job.width = job.Dest.x1 - job.Dest.x0;\r
1373         job.height = job.Dest.y1 - job.Dest.y0;\r
1374 \r
1375         job.Source.x0 = sourceClip.x0 + ( job.Dest.x0 - v.x0 );\r
1376         job.Source.x1 = job.Source.x0 + job.width;\r
1377         job.Source.y0 = sourceClip.y0 + ( job.Dest.y0 - v.y0 );\r
1378         job.Source.y1 = job.Source.y0 + job.height;\r
1379 \r
1380         job.argb = argb;\r
1381 \r
1382         job.stretch = false;\r
1383         job.x_stretch = 1.f;\r
1384         job.y_stretch = 1.f;\r
1385 \r
1386         if ( source )\r
1387         {\r
1388                 job.srcPitch = source->getPitch();\r
1389                 job.srcPixelMul = source->getBytesPerPixel();\r
1390                 job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );\r
1391         }\r
1392         else\r
1393         {\r
1394                 // use srcPitch for color operation on dest\r
1395                 job.srcPitch = job.width * dest->getBytesPerPixel();\r
1396         }\r
1397 \r
1398         job.dstPitch = dest->getPitch();\r
1399         job.dstPixelMul = dest->getBytesPerPixel();\r
1400         job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );\r
1401 \r
1402         blitter( &job );\r
1403 \r
1404         return 1;\r
1405 }\r
1406 \r
1407 #if defined(SOFTWARE_DRIVER_2_2D_AS_2D)\r
1408 static s32 StretchBlit(eBlitter operation,\r
1409                 video::IImage* dest, const core::rect<s32>* destClipping,const core::rect<s32> *destRect,\r
1410                 video::IImage* const source,const core::rect<s32> *srcRect, const core::dimension2d<u32>* source_org,\r
1411                 u32 argb)\r
1412 {\r
1413         tExecuteBlit blitter = getBlitter2( operation, dest, source );\r
1414         if ( 0 == blitter )\r
1415         {\r
1416                 return 0;\r
1417         }\r
1418 \r
1419         SBlitJob job;\r
1420 \r
1421         AbsRectangle destClip;\r
1422         AbsRectangle v;\r
1423         setClip(destClip, destClipping, dest, 0, 0);\r
1424         setClip(v, destRect, 0, 1, 0);\r
1425         if (!intersect(job.Dest, destClip, v))\r
1426                 return 0;\r
1427 \r
1428         // Clipping\r
1429         setClip ( job.Source, srcRect, source, 1, source_org);\r
1430 \r
1431         job.width = job.Dest.x1-job.Dest.x0;\r
1432         job.height = job.Dest.y1-job.Dest.y0;\r
1433 \r
1434         job.argb = argb;\r
1435 \r
1436         // use original dest size, despite any clipping\r
1437         const int dst_w = v.x1 - v.x0; // destRect->getWidth();\r
1438         const int dst_h = v.y1 - v.y0; // destRect->getHeight();\r
1439         const int src_w = job.Source.x1 - job.Source.x0;\r
1440         const int src_h = job.Source.y1 - job.Source.y0;\r
1441 \r
1442         job.stretch = dst_w != src_w || dst_h != src_h;\r
1443         job.x_stretch = dst_w ? (float)src_w / (float)dst_w : 1.f;\r
1444         job.y_stretch = dst_h ? (float)src_h / (float)dst_h : 1.f;\r
1445 \r
1446 \r
1447         if ( source )\r
1448         {\r
1449                 job.srcPitch = source->getPitch();\r
1450                 job.srcPixelMul = source->getBytesPerPixel();\r
1451 \r
1452                 //dest-clippling. advance source. loosing subpixel precision\r
1453                 job.Source.x0 += (s32)floorf(job.x_stretch * (job.Dest.x0 - v.x0));\r
1454                 job.Source.y0 += (s32)floorf(job.y_stretch * (job.Dest.y0 - v.y0));\r
1455 \r
1456                 job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );\r
1457         }\r
1458         else\r
1459         {\r
1460                 // use srcPitch for color operation on dest\r
1461                 job.srcPitch = job.width * dest->getBytesPerPixel();\r
1462         }\r
1463 \r
1464         job.dstPitch = dest->getPitch();\r
1465         job.dstPixelMul = dest->getBytesPerPixel();\r
1466         job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );\r
1467 \r
1468         blitter( &job );\r
1469 \r
1470         return 1;\r
1471 }\r
1472 #endif\r
1473 \r
1474 // Methods for Software drivers\r
1475 //! draws a rectangle\r
1476 static void drawRectangle(video::IImage* img, const core::rect<s32>& rect, const video::SColor &color)\r
1477 {\r
1478         Blit(color.getAlpha() == 0xFF ? BLITTER_COLOR : BLITTER_COLOR_ALPHA,\r
1479                         img, 0, &rect.UpperLeftCorner, 0, &rect, color.color);\r
1480 }\r
1481 \r
1482 \r
1483 //! draws a line from to with color\r
1484 static void drawLine(video::IImage* img, const core::position2d<s32>& from,\r
1485                                         const core::position2d<s32>& to, const video::SColor &color)\r
1486 {\r
1487         AbsRectangle clip;\r
1488         GetClip(clip, img);\r
1489 \r
1490         core::position2d<s32> p[2];\r
1491         if (ClipLine( clip, p[0], p[1], from, to))\r
1492         {\r
1493                 u32 alpha = extractAlpha(color.color);\r
1494 \r
1495                 switch(img->getColorFormat())\r
1496                 {\r
1497                 case video::ECF_A1R5G5B5:\r
1498                                 if (alpha == 256)\r
1499                                 {\r
1500                                         RenderLine16_Decal(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color));\r
1501                                 }\r
1502                                 else\r
1503                                 {\r
1504                                         RenderLine16_Blend(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color), alpha >> 3);\r
1505                                 }\r
1506                                 break;\r
1507                 case video::ECF_A8R8G8B8:\r
1508                                 if (alpha == 256)\r
1509                                 {\r
1510                                         RenderLine32_Decal(img, p[0], p[1], color.color);\r
1511                                 }\r
1512                                 else\r
1513                                 {\r
1514                                         RenderLine32_Blend(img, p[0], p[1], color.color, alpha);\r
1515                                 }\r
1516                                 break;\r
1517                 default:\r
1518                                 break;\r
1519                 }\r
1520         }\r
1521 }\r
1522 \r
1523 \r
1524 }\r
1525 \r
1526 #endif\r
1527 \r