]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CBlit.h
Add OpenGL3 renderer
[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 inline void GetClip(AbsRectangle &clipping, video::IImage * t)\r
91 {\r
92         clipping.x0 = 0;\r
93         clipping.y0 = 0;\r
94         clipping.x1 = t->getDimension().Width - 1;\r
95         clipping.y1 = t->getDimension().Height - 1;\r
96 }\r
97 \r
98 /*\r
99         return alpha in [0;256] Granularity from 32-Bit ARGB\r
100         add highbit alpha ( alpha > 127 ? + 1 )\r
101 */\r
102 static inline u32 extractAlpha(const u32 c)\r
103 {\r
104         return ( c >> 24 ) + ( c >> 31 );\r
105 }\r
106 \r
107 /*\r
108         return alpha in [0;255] Granularity and 32-Bit ARGB\r
109         add highbit alpha ( alpha > 127 ? + 1 )\r
110 */\r
111 static inline u32 packAlpha(const u32 c)\r
112 {\r
113         return (c > 127 ? c - 1 : c) << 24;\r
114 }\r
115 \r
116 \r
117 /*!\r
118         Scale Color by (1/value)\r
119         value 0 - 256 ( alpha )\r
120 */\r
121 inline u32 PixelLerp32(const u32 source, const u32 value)\r
122 {\r
123         u32 srcRB = source & 0x00FF00FF;\r
124         u32 srcXG = (source & 0xFF00FF00) >> 8;\r
125 \r
126         srcRB *= value;\r
127         srcXG *= value;\r
128 \r
129         srcRB >>= 8;\r
130         //srcXG >>= 8;\r
131 \r
132         srcXG &= 0xFF00FF00;\r
133         srcRB &= 0x00FF00FF;\r
134 \r
135         return srcRB | srcXG;\r
136 }\r
137 \r
138 \r
139 /*!\r
140 */\r
141 static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job )\r
142 {\r
143         if (job->stretch)\r
144         {\r
145                 const f18 wscale = f32_to_f18(job->x_stretch);\r
146                 const f18 hscale = f32_to_f18(job->y_stretch);\r
147 \r
148                 f18 src_y = f18_zero;\r
149 \r
150                 if (job->srcPixelMul == 4)\r
151                 {\r
152                         const u32 *src = (u32*)(job->src);\r
153                         u32 *dst = (u32*)(job->dst);\r
154 \r
155                         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
156                         {\r
157                                 src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
158 \r
159                                 f18 src_x = f18_zero;\r
160                                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
161                                 {\r
162                                         dst[dx] = src[f18_floor(src_x)];\r
163                                 }\r
164                                 dst = (u32*)((u8*)(dst)+job->dstPitch);\r
165                         }\r
166                 }\r
167                 else if (job->srcPixelMul == 2)\r
168                 {\r
169                         const u16 *src = (u16*)(job->src);\r
170                         u16* dst = (u16*)(job->dst);\r
171 \r
172                         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
173                         {\r
174                                 src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
175 \r
176                                 f18 src_x = f18_zero;\r
177                                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
178                                 {\r
179                                         dst[dx] = src[f18_floor(src_x)];\r
180                                 }\r
181                                 dst = (u16*)((u8*)(dst)+job->dstPitch);\r
182                         }\r
183                 }\r
184         }\r
185         else\r
186         {\r
187                 const size_t widthPitch = job->width * job->dstPixelMul;\r
188                 const void *src = (void*) job->src;\r
189                 void *dst = (void*) job->dst;\r
190 \r
191                 for ( u32 dy = 0; dy < job->height; ++dy )\r
192                 {\r
193                         memcpy( dst, src, widthPitch);\r
194 \r
195                         src = (void*) ( (u8*) (src) + job->srcPitch );\r
196                         dst = (void*) ( (u8*) (dst) + job->dstPitch );\r
197                 }\r
198         }\r
199 }\r
200 \r
201 /*!\r
202 */\r
203 static void executeBlit_TextureCopy_32_to_16( const SBlitJob * job )\r
204 {\r
205         const u32 w = job->width;\r
206         const u32 h = job->height;\r
207         const u32 *src = static_cast<const u32*>(job->src);\r
208         u16 *dst = static_cast<u16*>(job->dst);\r
209 \r
210         if (job->stretch)\r
211         {\r
212                 const float wscale = job->x_stretch;\r
213                 const float hscale = job->y_stretch;\r
214 \r
215                 for ( u32 dy = 0; dy < h; ++dy )\r
216                 {\r
217                         const u32 src_y = (u32)(dy*hscale);\r
218                         src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
219 \r
220                         for ( u32 dx = 0; dx < w; ++dx )\r
221                         {\r
222                                 const u32 src_x = (u32)(dx*wscale);\r
223                                 //16 bit Blitter depends on pre-multiplied color\r
224                                 const u32 s = PixelLerp32( src[src_x] | 0xFF000000, extractAlpha( src[src_x] ) );\r
225                                 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );\r
226                         }\r
227                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
228                 }\r
229         }\r
230         else\r
231         {\r
232                 for ( u32 dy = 0; dy != h; ++dy )\r
233                 {\r
234                         for ( u32 dx = 0; dx != w; ++dx )\r
235                         {\r
236                                 //16 bit Blitter depends on pre-multiplied color\r
237                                 const u32 s = PixelLerp32( src[dx] | 0xFF000000, extractAlpha( src[dx] ) );\r
238                                 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );\r
239                         }\r
240 \r
241                         src = (u32*) ( (u8*) (src) + job->srcPitch );\r
242                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
243                 }\r
244         }\r
245 }\r
246 \r
247 /*!\r
248 */\r
249 static void executeBlit_TextureCopy_24_to_16( const SBlitJob * job )\r
250 {\r
251         const u32 w = job->width;\r
252         const u32 h = job->height;\r
253         const u8 *src = static_cast<const u8*>(job->src);\r
254         u16 *dst = static_cast<u16*>(job->dst);\r
255 \r
256         if (job->stretch)\r
257         {\r
258                 const float wscale = job->x_stretch * 3.f;\r
259                 const float hscale = job->y_stretch;\r
260 \r
261                 for ( u32 dy = 0; dy < h; ++dy )\r
262                 {\r
263                         const u32 src_y = (u32)(dy*hscale);\r
264                         src = (u8*)(job->src) + job->srcPitch*src_y;\r
265 \r
266                         for ( u32 dx = 0; dx < w; ++dx )\r
267                         {\r
268                                 const u8* src_x = src+(u32)(dx*wscale);\r
269                                 dst[dx] = video::RGBA16(src_x[0], src_x[1], src_x[2]);\r
270                         }\r
271                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
272                 }\r
273         }\r
274         else\r
275         {\r
276                 for ( u32 dy = 0; dy != h; ++dy )\r
277                 {\r
278                         const u8* s = src;\r
279                         for ( u32 dx = 0; dx != w; ++dx )\r
280                         {\r
281                                 dst[dx] = video::RGBA16(s[0], s[1], s[2]);\r
282                                 s += 3;\r
283                         }\r
284 \r
285                         src = src+job->srcPitch;\r
286                         dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
287                 }\r
288         }\r
289 }\r
290 \r
291 \r
292 /*!\r
293 */\r
294 static void executeBlit_TextureCopy_16_to_32( const SBlitJob * job )\r
295 {\r
296         const u32 w = job->width;\r
297         const u32 h = job->height;\r
298         const u16 *src = static_cast<const u16*>(job->src);\r
299         u32 *dst = static_cast<u32*>(job->dst);\r
300 \r
301         if (job->stretch)\r
302         {\r
303                 const float wscale = job->x_stretch;\r
304                 const float hscale = job->y_stretch;\r
305 \r
306                 for ( u32 dy = 0; dy < h; ++dy )\r
307                 {\r
308                         const u32 src_y = (u32)(dy*hscale);\r
309                         src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
310 \r
311                         for ( u32 dx = 0; dx < w; ++dx )\r
312                         {\r
313                                 const u32 src_x = (u32)(dx*wscale);\r
314                                 dst[dx] = video::A1R5G5B5toA8R8G8B8(src[src_x]);\r
315                         }\r
316                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
317                 }\r
318         }\r
319         else\r
320         {\r
321                 for ( u32 dy = 0; dy != h; ++dy )\r
322                 {\r
323                         for ( u32 dx = 0; dx != w; ++dx )\r
324                         {\r
325                                 dst[dx] = video::A1R5G5B5toA8R8G8B8( src[dx] );\r
326                         }\r
327 \r
328                         src = (u16*) ( (u8*) (src) + job->srcPitch );\r
329                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
330                 }\r
331         }\r
332 }\r
333 \r
334 static void executeBlit_TextureCopy_16_to_24( const SBlitJob * job )\r
335 {\r
336         const u32 w = job->width;\r
337         const u32 h = job->height;\r
338         const u16 *src = static_cast<const u16*>(job->src);\r
339         u8 *dst = static_cast<u8*>(job->dst);\r
340 \r
341         if (job->stretch)\r
342         {\r
343                 const float wscale = job->x_stretch;\r
344                 const float hscale = job->y_stretch;\r
345 \r
346                 for ( u32 dy = 0; dy < h; ++dy )\r
347                 {\r
348                         const u32 src_y = (u32)(dy*hscale);\r
349                         src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );\r
350 \r
351                         for ( u32 dx = 0; dx < w; ++dx )\r
352                         {\r
353                                 const u32 src_x = (u32)(dx*wscale);\r
354                                 u32 color = video::A1R5G5B5toA8R8G8B8(src[src_x]);\r
355                                 u8 * writeTo = &dst[dx * 3];\r
356                                 *writeTo++ = (color >> 16)& 0xFF;\r
357                                 *writeTo++ = (color >> 8) & 0xFF;\r
358                                 *writeTo++ = color & 0xFF;\r
359                         }\r
360                         dst += job->dstPitch;\r
361                 }\r
362         }\r
363         else\r
364         {\r
365                 for ( u32 dy = 0; dy != h; ++dy )\r
366                 {\r
367                         for ( u32 dx = 0; dx != w; ++dx )\r
368                         {\r
369                                 u32 color = video::A1R5G5B5toA8R8G8B8(src[dx]);\r
370                                 u8 * writeTo = &dst[dx * 3];\r
371                                 *writeTo++ = (color >> 16)& 0xFF;\r
372                                 *writeTo++ = (color >> 8) & 0xFF;\r
373                                 *writeTo++ = color & 0xFF;\r
374                         }\r
375 \r
376                         src = (u16*) ( (u8*) (src) + job->srcPitch );\r
377                         dst += job->dstPitch;\r
378                 }\r
379         }\r
380 }\r
381 \r
382 /*!\r
383 */\r
384 static void executeBlit_TextureCopy_24_to_32( const SBlitJob * job )\r
385 {\r
386         const u32 w = job->width;\r
387         const u32 h = job->height;\r
388         const u8 *src = static_cast<const u8*>(job->src);\r
389         u32 *dst = static_cast<u32*>(job->dst);\r
390 \r
391         if (job->stretch)\r
392         {\r
393                 const float wscale = job->x_stretch * 3.f;\r
394                 const float hscale = job->y_stretch;\r
395 \r
396                 for ( u32 dy = 0; dy < h; ++dy )\r
397                 {\r
398                         const u32 src_y = (u32)(dy*hscale);\r
399                         src = (const u8*)job->src+(job->srcPitch*src_y);\r
400 \r
401                         for ( u32 dx = 0; dx < w; ++dx )\r
402                         {\r
403                                 const u8* s = src+(u32)(dx*wscale);\r
404                                 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];\r
405                         }\r
406                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
407                 }\r
408         }\r
409         else\r
410         {\r
411                 for ( u32 dy = 0; dy < job->height; ++dy )\r
412                 {\r
413                         const u8* s = src;\r
414 \r
415                         for ( u32 dx = 0; dx < job->width; ++dx )\r
416                         {\r
417                                 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];\r
418                                 s += 3;\r
419                         }\r
420 \r
421                         src = src + job->srcPitch;\r
422                         dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
423                 }\r
424         }\r
425 }\r
426 \r
427 static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job )\r
428 {\r
429         const u32 w = job->width;\r
430         const u32 h = job->height;\r
431         const u32 *src = static_cast<const u32*>(job->src);\r
432         u8 *dst = static_cast<u8*>(job->dst);\r
433 \r
434         if (job->stretch)\r
435         {\r
436                 const float wscale = job->x_stretch;\r
437                 const float hscale = job->y_stretch;\r
438 \r
439                 for ( u32 dy = 0; dy < h; ++dy )\r
440                 {\r
441                         const u32 src_y = (u32)(dy*hscale);\r
442                         src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);\r
443 \r
444                         for ( u32 dx = 0; dx < w; ++dx )\r
445                         {\r
446                                 const u32 src_x = src[(u32)(dx*wscale)];\r
447                                 u8 * writeTo = &dst[dx * 3];\r
448                                 *writeTo++ = (src_x >> 16)& 0xFF;\r
449                                 *writeTo++ = (src_x >> 8) & 0xFF;\r
450                                 *writeTo++ = src_x & 0xFF;\r
451                         }\r
452                         dst += job->dstPitch;\r
453                 }\r
454         }\r
455         else\r
456         {\r
457                 for ( u32 dy = 0; dy != h; ++dy )\r
458                 {\r
459                         for ( u32 dx = 0; dx != w; ++dx )\r
460                         {\r
461                                 u8 * writeTo = &dst[dx * 3];\r
462                                 *writeTo++ = (src[dx] >> 16)& 0xFF;\r
463                                 *writeTo++ = (src[dx] >> 8) & 0xFF;\r
464                                 *writeTo++ = src[dx] & 0xFF;\r
465                         }\r
466 \r
467                         src = (u32*) ( (u8*) (src) + job->srcPitch );\r
468                         dst += job->dstPitch;\r
469                 }\r
470         }\r
471 }\r
472 \r
473 /*!\r
474 */\r
475 static void executeBlit_TextureBlend_16_to_16( const SBlitJob * job )\r
476 {\r
477         const f18 wscale = f32_to_f18(job->x_stretch);\r
478         const f18 hscale = f32_to_f18(job->y_stretch);\r
479 \r
480         f18 src_y = f18_zero;\r
481         u16 *dst = (u16*)job->dst;\r
482 \r
483         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
484         {\r
485                 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
486                 f18 src_x = f18_zero;\r
487                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
488                 {\r
489                         dst[dx] = PixelBlend16(dst[dx], src[f18_floor(src_x)]);\r
490                 }\r
491                 dst = (u16*)((u8*)(dst)+job->dstPitch);\r
492         }\r
493 }\r
494 \r
495 /*!\r
496 */\r
497 static void executeBlit_TextureBlend_32_to_32( const SBlitJob * job )\r
498 {\r
499         const f18 wscale = f32_to_f18(job->x_stretch);\r
500         const f18 hscale = f32_to_f18(job->y_stretch);\r
501 \r
502         f18 src_y = f18_zero;\r
503         u32 *dst = (u32*)job->dst;\r
504         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
505         {\r
506                 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
507 \r
508                 f18 src_x = f18_zero;\r
509                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
510                 {\r
511                         dst[dx] = PixelBlend32(dst[dx], src[f18_floor(src_x)]);\r
512                 }\r
513                 dst = (u32*)((u8*)(dst)+job->dstPitch);\r
514         }\r
515 }\r
516 \r
517 /*!\r
518 */\r
519 static void executeBlit_TextureBlendColor_16_to_16( const SBlitJob * job )\r
520 {\r
521         const u16 blend = video::A8R8G8B8toA1R5G5B5(job->argb);\r
522 \r
523         const f18 wscale = f32_to_f18(job->x_stretch);\r
524         const f18 hscale = f32_to_f18(job->y_stretch);\r
525 \r
526         f18 src_y = f18_zero;\r
527         u16 *dst = (u16*)job->dst;\r
528         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
529         {\r
530                 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
531                 f18 src_x = f18_zero;\r
532                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
533                 {\r
534                         u16 c0 = src[f18_floor(src_x)];\r
535                         if (0 == (c0 & 0x8000))\r
536                                 continue;\r
537 \r
538                         dst[dx] = PixelMul16_2(c0, blend);\r
539                 }\r
540                 dst = (u16*)((u8*)(dst)+job->dstPitch);\r
541         }\r
542 }\r
543 \r
544 \r
545 /*!\r
546 */\r
547 static void executeBlit_TextureBlendColor_32_to_32( const SBlitJob * job )\r
548 {\r
549         const f18 wscale = f32_to_f18(job->x_stretch);\r
550         const f18 hscale = f32_to_f18(job->y_stretch);\r
551 \r
552         u32* dst = (u32*)job->dst;\r
553         f18 src_y = f18_zero;\r
554         for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)\r
555         {\r
556                 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));\r
557 \r
558                 f18 src_x = f18_zero;\r
559                 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)\r
560                 {\r
561                         dst[dx] = PixelBlend32(dst[dx], PixelMul32_2(src[f18_floor(src_x)], job->argb));\r
562                 }\r
563                 dst = (u32*)((u8*)(dst)+job->dstPitch);\r
564         }\r
565 }\r
566 \r
567 /*!\r
568 */\r
569 static void executeBlit_Color_16_to_16( const SBlitJob * job )\r
570 {\r
571         const u16 c = video::A8R8G8B8toA1R5G5B5(job->argb);\r
572         u16 *dst = (u16*) job->dst;\r
573 \r
574         for ( u32 dy = 0; dy < job->height; ++dy )\r
575         {\r
576                 memset16(dst, c, job->srcPitch);\r
577                 dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
578         }\r
579 }\r
580 \r
581 /*!\r
582 */\r
583 static void executeBlit_Color_32_to_32( const SBlitJob * job )\r
584 {\r
585         u32 *dst = (u32*) job->dst;\r
586 \r
587         for ( u32 dy = 0; dy < job->height; ++dy )\r
588         {\r
589                 memset32( dst, job->argb, job->srcPitch );\r
590                 dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
591         }\r
592 }\r
593 \r
594 /*!\r
595 */\r
596 static void executeBlit_ColorAlpha_16_to_16( const SBlitJob * job )\r
597 {\r
598         u16 *dst = (u16*) job->dst;\r
599 \r
600         const u16 alpha = extractAlpha( job->argb ) >> 3;\r
601         if ( 0 == alpha )\r
602                 return;\r
603         const u32 src = video::A8R8G8B8toA1R5G5B5( job->argb );\r
604 \r
605         for ( u32 dy = 0; dy != job->height; ++dy )\r
606         {\r
607                 for ( u32 dx = 0; dx != job->width; ++dx )\r
608                 {\r
609                         dst[dx] = PixelBlend16( dst[dx], src, alpha );\r
610                 }\r
611                 dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
612         }\r
613 }\r
614 \r
615 /*!\r
616 */\r
617 static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job )\r
618 {\r
619         const u32 alpha = extractAlpha( job->argb );\r
620         if (0 == alpha)\r
621                 return;\r
622 \r
623         u32 *dst = (u32*)job->dst;\r
624         for ( u32 dy = 0; dy < job->height; ++dy )\r
625         {\r
626                 for ( u32 dx = 0; dx < job->width; ++dx )\r
627                 {\r
628                         dst[dx] = PixelBlend32( dst[dx], job->argb, alpha );\r
629                 }\r
630                 dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
631         }\r
632 \r
633 }\r
634 \r
635 /*!\r
636         Pixel =>\r
637                         color = sourceAlpha > 0 ? source, else dest\r
638                         alpha = max(destAlpha, sourceAlpha)\r
639 */\r
640 inline u16 PixelCombine16(const u16 c2, const u16 c1)\r
641 {\r
642         if (video::getAlpha(c1) > 0)\r
643                 return c1;\r
644         else\r
645                 return c2;\r
646 }\r
647 \r
648 /*!\r
649         Combine alpha channels (increases alpha / reduces transparency)\r
650 */\r
651 static void executeBlit_TextureCombineColor_16_to_16( const SBlitJob * job )\r
652 {\r
653         const u32 w = job->width * 2;\r
654         const u32 h = job->height * 2;\r
655         u16* src = (u16*) job->src;\r
656         u16* dst = (u16*) job->dst;\r
657 \r
658         const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );\r
659 \r
660         /*\r
661                 Stretch not supported.\r
662         */\r
663         for ( u32 dy = 0; dy != h; dy++ )\r
664         {\r
665                 for ( u32 dx = 0; dx != w; dx++ )\r
666                 {\r
667                         const u16 src_x = src[dx];\r
668                         const u16 dst_x = dst[dx];\r
669                         dst[dx] = PixelCombine16( dst_x, PixelMul16_2( src_x, jobColor ) );\r
670                 }\r
671                 src = (u16*) ( (u8*) (src) + job->srcPitch );\r
672                 dst = (u16*) ( (u8*) (dst) + job->dstPitch );\r
673         }\r
674 }\r
675 \r
676 /*!\r
677         Combine alpha channels (increases alpha / reduces transparency)\r
678 */\r
679 static void executeBlit_TextureCombineColor_16_to_24( const SBlitJob * job )\r
680 {\r
681         const u32 w = job->width;\r
682         const u32 h = job->height;\r
683         const u16 *src = static_cast<const u16*>(job->src);\r
684         u8 *dst = static_cast<u8*>(job->dst);\r
685 \r
686         const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );\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 = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[src_x]), jobColor);\r
702                                 u8 * writeTo = &dst[dx * 3];\r
703                                 if ( video::getAlpha(src[src_x]) > 0 ) // only overlay if source has visible alpha (alpha == 1)\r
704                                 {\r
705                                         *writeTo++ = (color >> 16)& 0xFF;\r
706                                         *writeTo++ = (color >> 8) & 0xFF;\r
707                                         *writeTo++ = color & 0xFF;\r
708                                 }\r
709                         }\r
710                         dst += job->dstPitch;\r
711                 }\r
712         }\r
713         else\r
714         {\r
715                 for ( u32 dy = 0; dy != h; ++dy )\r
716                 {\r
717                         for ( u32 dx = 0; dx != w; ++dx )\r
718                         {\r
719                                 u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[dx]), jobColor);\r
720                                 u8 * writeTo = &dst[dx * 3];\r
721                                 if ( video::getAlpha(src[dx]) > 0 ) // only overlay if source has visible alpha (alpha == 1)\r
722                                 {\r
723                                         *writeTo++ = (color >> 16)& 0xFF;\r
724                                         *writeTo++ = (color >> 8) & 0xFF;\r
725                                         *writeTo++ = color & 0xFF;\r
726                                 }\r
727                         }\r
728 \r
729                         src = (u16*) ( (u8*) (src) + job->srcPitch );\r
730                         dst += job->dstPitch;\r
731                 }\r
732         }\r
733 }\r
734 \r
735 /*!\r
736         Pixel =>\r
737                         color = dest * ( 1 - SourceAlpha ) + source * SourceAlpha,\r
738                         alpha = destAlpha * ( 1 - SourceAlpha ) + sourceAlpha\r
739 \r
740         where "1" means "full scale" (255)\r
741 */\r
742 inline u32 PixelCombine32(const u32 c2, const u32 c1)\r
743 {\r
744         // alpha test\r
745         u32 alpha = c1 & 0xFF000000;\r
746 \r
747         if (0 == alpha)\r
748                 return c2;\r
749         if (0xFF000000 == alpha)\r
750         {\r
751                 return c1;\r
752         }\r
753 \r
754         alpha >>= 24;\r
755 \r
756         // add highbit alpha, if ( alpha > 127 ) alpha += 1;\r
757         // stretches [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8\r
758         alpha += (alpha >> 7);\r
759 \r
760         u32 srcRB = c1 & 0x00FF00FF;\r
761         u32 srcXG = c1 & 0x0000FF00;\r
762 \r
763         u32 dstRB = c2 & 0x00FF00FF;\r
764         u32 dstXG = c2 & 0x0000FF00;\r
765 \r
766 \r
767         u32 rb = srcRB - dstRB;\r
768         u32 xg = srcXG - dstXG;\r
769 \r
770         rb *= alpha;\r
771         xg *= alpha;\r
772         rb >>= 8;\r
773         xg >>= 8;\r
774 \r
775         rb += dstRB;\r
776         xg += dstXG;\r
777 \r
778         rb &= 0x00FF00FF;\r
779         xg &= 0x0000FF00;\r
780 \r
781         u32 sa = c1 >> 24;\r
782         u32 da = c2 >> 24;\r
783         u32 blendAlpha_fix8 = (sa * 256 + da * (256 - alpha)) >> 8;\r
784         return blendAlpha_fix8 << 24 | rb | xg;\r
785 }\r
786 \r
787 /*!\r
788         Combine alpha channels (increases alpha / reduces transparency)\r
789         Destination alpha is treated as full 255\r
790 */\r
791 static void executeBlit_TextureCombineColor_32_to_24( const SBlitJob * job )\r
792 {\r
793         const u32 w = job->width;\r
794         const u32 h = job->height;\r
795         const u32 *src = static_cast<const u32*>(job->src);\r
796         u8 *dst = static_cast<u8*>(job->dst);\r
797 \r
798         if (job->stretch)\r
799         {\r
800                 const float wscale = job->x_stretch;\r
801                 const float hscale = job->y_stretch;\r
802 \r
803                 for ( u32 dy = 0; dy < h; ++dy )\r
804                 {\r
805                         const u32 src_y = (u32)(dy*hscale);\r
806                         src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);\r
807 \r
808                         for ( u32 dx = 0; dx < w; ++dx )\r
809                         {\r
810                                 const u32 src_x = src[(u32)(dx*wscale)];\r
811                                 u8* writeTo = &dst[dx * 3];\r
812                                 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];\r
813                                 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src_x, job->argb ) );\r
814                                 *writeTo++ = (combo >> 16) & 0xFF;\r
815                                 *writeTo++ = (combo >> 8) & 0xFF;\r
816                                 *writeTo++ = combo & 0xFF;\r
817                         }\r
818                         dst += job->dstPitch;\r
819                 }\r
820         }\r
821         else\r
822         {\r
823                 for ( u32 dy = 0; dy != h; ++dy )\r
824                 {\r
825                         for ( u32 dx = 0; dx != w; ++dx )\r
826                         {\r
827                                 u8* writeTo = &dst[dx * 3];\r
828                                 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];\r
829                                 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src[dx], job->argb ) );\r
830                                 *writeTo++ = (combo >> 16) & 0xFF;\r
831                                 *writeTo++ = (combo >> 8) & 0xFF;\r
832                                 *writeTo++ = combo & 0xFF;\r
833                         }\r
834 \r
835                         src = (u32*) ( (u8*) (src) + job->srcPitch );\r
836                         dst += job->dstPitch;\r
837                 }\r
838         }\r
839 }\r
840 \r
841 /*!\r
842         Combine alpha channels (increases alpha / reduces transparency)\r
843 */\r
844 static void executeBlit_TextureCombineColor_32_to_32( const SBlitJob * job )\r
845 {\r
846         u32 *src = (u32*) job->src;\r
847         u32 *dst = (u32*) job->dst;\r
848 \r
849         for ( u32 dy = 0; dy != job->height; ++dy )\r
850         {\r
851                 for (u32 dx = 0; dx != job->width; ++dx )\r
852                 {\r
853                         dst[dx] = PixelCombine32( dst[dx], PixelMul32_2( src[dx], job->argb ) );\r
854                 }\r
855                 src = (u32*) ( (u8*) (src) + job->srcPitch );\r
856                 dst = (u32*) ( (u8*) (dst) + job->dstPitch );\r
857         }\r
858 }\r
859 \r
860 // Blitter Operation\r
861 enum eBlitter\r
862 {\r
863         BLITTER_INVALID = 0,\r
864         BLITTER_COLOR,\r
865         BLITTER_COLOR_ALPHA,\r
866         BLITTER_TEXTURE,\r
867         BLITTER_TEXTURE_ALPHA_BLEND,\r
868         BLITTER_TEXTURE_ALPHA_COLOR_BLEND,\r
869         BLITTER_TEXTURE_COMBINE_ALPHA,\r
870 };\r
871 \r
872 typedef void (*tExecuteBlit) ( const SBlitJob * job );\r
873 \r
874 \r
875 /*!\r
876 */\r
877 struct blitterTable\r
878 {\r
879         eBlitter operation;\r
880         s32 destFormat;\r
881         s32 sourceFormat;\r
882         tExecuteBlit func;\r
883 };\r
884 \r
885 static const blitterTable blitTable[] =\r
886 {\r
887         { BLITTER_TEXTURE, -2, -2, executeBlit_TextureCopy_x_to_x },\r
888         { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_16 },\r
889         { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },\r
890         { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_32 },\r
891         { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },\r
892         { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_24 },\r
893         { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_24 },\r
894         { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlend_16_to_16 },\r
895         { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlend_32_to_32 },\r
896         { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlendColor_16_to_16 },\r
897         { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlendColor_32_to_32 },\r
898         { BLITTER_COLOR, video::ECF_A1R5G5B5, -1, executeBlit_Color_16_to_16 },\r
899         { BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 },\r
900         { BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 },\r
901         { BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 },\r
902         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_32 },\r
903         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },\r
904         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_24 },\r
905         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_x_to_x },\r
906         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },\r
907         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_16 },\r
908         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },\r
909         { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_24 },\r
910         { BLITTER_INVALID, -1, -1, 0 }\r
911 };\r
912 \r
913 \r
914 static inline tExecuteBlit getBlitter2( eBlitter operation,const video::IImage * dest,const video::IImage * source )\r
915 {\r
916         video::ECOLOR_FORMAT sourceFormat = (video::ECOLOR_FORMAT) ( source ? source->getColorFormat() : -1 );\r
917         video::ECOLOR_FORMAT destFormat = (video::ECOLOR_FORMAT) ( dest ? dest->getColorFormat() : -1 );\r
918 \r
919         const blitterTable * b = blitTable;\r
920 \r
921         while ( b->operation != BLITTER_INVALID )\r
922         {\r
923                 if ( b->operation == operation )\r
924                 {\r
925                         if (( b->destFormat == -1 || b->destFormat == destFormat ) &&\r
926                                 ( b->sourceFormat == -1 || b->sourceFormat == sourceFormat ) )\r
927                                         return b->func;\r
928                         else\r
929                         if ( b->destFormat == -2 && ( sourceFormat == destFormat ) )\r
930                                         return b->func;\r
931                 }\r
932                 b += 1;\r
933         }\r
934         return 0;\r
935 }\r
936 \r
937 \r
938 // bounce clipping to texture\r
939 inline void setClip(AbsRectangle &out, const core::rect<s32> *clip,\r
940         const video::IImage* tex, s32 passnative, const core::dimension2d<u32>* tex_org)\r
941 {\r
942         if (0 == tex)\r
943         {\r
944                 if (clip && passnative)\r
945                 {\r
946                         out.x0 = clip->UpperLeftCorner.X;\r
947                         out.x1 = clip->LowerRightCorner.X;\r
948                         out.y0 = clip->UpperLeftCorner.Y;\r
949                         out.y1 = clip->LowerRightCorner.Y;\r
950                 }\r
951                 else\r
952                 {\r
953                         out.x0 = 0;\r
954                         out.x1 = 0;\r
955                         out.y0 = 0;\r
956                         out.y1 = 0;\r
957                 }\r
958                 return;\r
959         }\r
960 \r
961         const s32 w = tex->getDimension().Width;\r
962         const s32 h = tex->getDimension().Height;\r
963 \r
964         //driver could have changed texture size.\r
965         if (clip && tex_org && ((u32)w != tex_org->Width || (u32)h != tex_org->Height))\r
966         {\r
967                 out.x0 = core::s32_clamp((clip->UpperLeftCorner.X*w) / tex_org->Width, 0, w - 1);\r
968                 out.x1 = core::s32_clamp((clip->LowerRightCorner.X*w) / tex_org->Width, out.x0, w);\r
969                 out.y0 = core::s32_clamp((clip->UpperLeftCorner.Y*h) / tex_org->Height, 0, h - 1);\r
970                 out.y1 = core::s32_clamp((clip->LowerRightCorner.Y*h) / tex_org->Height, out.y0, h);\r
971         }\r
972         else if (clip)\r
973         {\r
974                 //y-1 to prevent starting on illegal memory (not ideal!).\r
975                 out.x0 = core::s32_clamp(clip->UpperLeftCorner.X, 0, w - 1);\r
976                 out.x1 = core::s32_clamp(clip->LowerRightCorner.X, passnative ? 0 : out.x0, w);\r
977                 out.y0 = core::s32_clamp(clip->UpperLeftCorner.Y, 0, h - 1);\r
978                 out.y1 = core::s32_clamp(clip->LowerRightCorner.Y, passnative ? 0 : out.y0, h);\r
979         }\r
980         else\r
981         {\r
982                 out.x0 = 0;\r
983                 out.y0 = 0;\r
984                 out.x1 = w;\r
985                 out.y1 = h;\r
986         }\r
987 \r
988 }\r
989 \r
990 /*!\r
991         a generic 2D Blitter\r
992 */\r
993 static s32 Blit(eBlitter operation,\r
994                 video::IImage * dest,\r
995                 const core::rect<s32> *destClipping,\r
996                 const core::position2d<s32> *destPos,\r
997                 video::IImage * const source,\r
998                 const core::rect<s32> *sourceClipping,\r
999                 u32 argb)\r
1000 {\r
1001         tExecuteBlit blitter = getBlitter2( operation, dest, source );\r
1002         if ( 0 == blitter )\r
1003         {\r
1004                 return 0;\r
1005         }\r
1006 \r
1007         // Clipping\r
1008         AbsRectangle sourceClip;\r
1009         AbsRectangle destClip;\r
1010         AbsRectangle v;\r
1011 \r
1012         SBlitJob job;\r
1013 \r
1014         setClip ( sourceClip, sourceClipping, source, 1,0 );\r
1015         setClip ( destClip, destClipping, dest, 0,0 );\r
1016 \r
1017         v.x0 = destPos ? destPos->X : 0;\r
1018         v.y0 = destPos ? destPos->Y : 0;\r
1019         v.x1 = v.x0 + ( sourceClip.x1 - sourceClip.x0 );\r
1020         v.y1 = v.y0 + ( sourceClip.y1 - sourceClip.y0 );\r
1021 \r
1022         if ( !intersect( job.Dest, destClip, v ) )\r
1023                 return 0;\r
1024 \r
1025         job.width = job.Dest.x1 - job.Dest.x0;\r
1026         job.height = job.Dest.y1 - job.Dest.y0;\r
1027 \r
1028         job.Source.x0 = sourceClip.x0 + ( job.Dest.x0 - v.x0 );\r
1029         job.Source.x1 = job.Source.x0 + job.width;\r
1030         job.Source.y0 = sourceClip.y0 + ( job.Dest.y0 - v.y0 );\r
1031         job.Source.y1 = job.Source.y0 + job.height;\r
1032 \r
1033         job.argb = argb;\r
1034 \r
1035         job.stretch = false;\r
1036         job.x_stretch = 1.f;\r
1037         job.y_stretch = 1.f;\r
1038 \r
1039         if ( source )\r
1040         {\r
1041                 job.srcPitch = source->getPitch();\r
1042                 job.srcPixelMul = source->getBytesPerPixel();\r
1043                 job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );\r
1044         }\r
1045         else\r
1046         {\r
1047                 // use srcPitch for color operation on dest\r
1048                 job.srcPitch = job.width * dest->getBytesPerPixel();\r
1049         }\r
1050 \r
1051         job.dstPitch = dest->getPitch();\r
1052         job.dstPixelMul = dest->getBytesPerPixel();\r
1053         job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );\r
1054 \r
1055         blitter( &job );\r
1056 \r
1057         return 1;\r
1058 }\r
1059 \r
1060 }\r
1061 \r
1062 #endif\r
1063 \r