xref: /reactos/win32ss/gdi/dib/dib24bpp.c (revision c2c66aff)
1 /*
2  * PROJECT:         Win32 subsystem
3  * LICENSE:         See COPYING in the top level directory
4  * FILE:            win32ss/gdi/dib/dib24bpp.c
5  * PURPOSE:         Device Independant Bitmap functions, 24bpp
6  * PROGRAMMERS:     Jason Filby
7  *                  Thomas Bluemel
8  *                  Gregor Anich
9  */
10 
11 #include <win32k.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 VOID
17 DIB_24BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
18 {
19   PBYTE addr = (PBYTE)SurfObj->pvScan0 + (y * SurfObj->lDelta) + (x << 1) + x;
20   *(PUSHORT)(addr) = c & 0xFFFF;
21   *(addr + 2) = (c >> 16) & 0xFF;
22 }
23 
24 ULONG
25 DIB_24BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
26 {
27   PBYTE addr = (PBYTE)SurfObj->pvScan0 + y * SurfObj->lDelta + (x << 1) + x;
28   return *(PUSHORT)(addr) + (*(addr + 2) << 16);
29 }
30 
31 
32 
33 VOID
34 DIB_24BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
35 {
36   PBYTE addr = (PBYTE)SurfObj->pvScan0 + y1 * SurfObj->lDelta + (x << 1) + x;
37   LONG lDelta = SurfObj->lDelta;
38 
39   c &= 0xFFFFFF;
40   while(y1++ < y2)
41   {
42     *(PUSHORT)(addr) = c & 0xFFFF;
43     *(addr + 2) = (BYTE)(c >> 16);
44 
45     addr += lDelta;
46   }
47 }
48 
49 BOOLEAN
50 DIB_24BPP_BitBltSrcCopy(PBLTINFO BltInfo)
51 {
52   LONG     i, j, sx, sy, xColor, f1;
53   PBYTE    SourceBits, DestBits, SourceLine, DestLine;
54   PBYTE    SourceBits_4BPP, SourceLine_4BPP;
55   PWORD    SourceBits_16BPP, SourceLine_16BPP;
56 
57   DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + (BltInfo->DestRect.top * BltInfo->DestSurface->lDelta) + BltInfo->DestRect.left * 3;
58 
59   switch(BltInfo->SourceSurface->iBitmapFormat)
60   {
61     case BMF_1BPP:
62       sx = BltInfo->SourcePoint.x;
63       sy = BltInfo->SourcePoint.y;
64 
65       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
66       {
67         sx = BltInfo->SourcePoint.x;
68         for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
69         {
70           if(DIB_1BPP_GetPixel(BltInfo->SourceSurface, sx, sy) == 0)
71           {
72             DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 0));
73           } else {
74             DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, 1));
75           }
76           sx++;
77         }
78         sy++;
79       }
80       break;
81 
82     case BMF_4BPP:
83       SourceBits_4BPP = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + (BltInfo->SourcePoint.x >> 1);
84 
85       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
86       {
87         SourceLine_4BPP = SourceBits_4BPP;
88         DestLine = DestBits;
89         sx = BltInfo->SourcePoint.x;
90         f1 = sx & 1;
91 
92         for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
93         {
94           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest,
95               (*SourceLine_4BPP & altnotmask[f1]) >> (4 * (1 - f1)));
96           *DestLine++ = xColor & 0xff;
97           *(PWORD)DestLine = (WORD)(xColor >> 8);
98           DestLine += 2;
99           if(f1 == 1) { SourceLine_4BPP++; f1 = 0; } else { f1 = 1; }
100           sx++;
101         }
102 
103         SourceBits_4BPP += BltInfo->SourceSurface->lDelta;
104         DestBits += BltInfo->DestSurface->lDelta;
105       }
106       break;
107 
108     case BMF_8BPP:
109       SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + BltInfo->SourcePoint.x;
110       DestLine = DestBits;
111 
112       for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
113       {
114         SourceBits = SourceLine;
115         DestBits = DestLine;
116 
117         for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
118         {
119           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceBits);
120           *DestBits = xColor & 0xff;
121           *(PWORD)(DestBits + 1) = (WORD)(xColor >> 8);
122           SourceBits += 1;
123           DestBits += 3;
124         }
125 
126         SourceLine += BltInfo->SourceSurface->lDelta;
127         DestLine += BltInfo->DestSurface->lDelta;
128       }
129       break;
130 
131     case BMF_16BPP:
132       SourceBits_16BPP = (PWORD)((PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 2 * BltInfo->SourcePoint.x);
133 
134       for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
135       {
136         SourceLine_16BPP = SourceBits_16BPP;
137         DestLine = DestBits;
138 
139         for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
140         {
141           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *SourceLine_16BPP);
142           *DestLine++ = xColor & 0xff;
143           *(PWORD)DestLine = (WORD)(xColor >> 8);
144           DestLine += 2;
145           SourceLine_16BPP++;
146         }
147 
148         SourceBits_16BPP = (PWORD)((PBYTE)SourceBits_16BPP + BltInfo->SourceSurface->lDelta);
149         DestBits += BltInfo->DestSurface->lDelta;
150       }
151       break;
152 
153     case BMF_24BPP:
154       if (NULL == BltInfo->XlateSourceToDest || 0 != (BltInfo->XlateSourceToDest->flXlate & XO_TRIVIAL))
155       {
156         if (BltInfo->DestRect.top < BltInfo->SourcePoint.y)
157         {
158           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
159           for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
160           {
161             RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
162             SourceBits += BltInfo->SourceSurface->lDelta;
163             DestBits += BltInfo->DestSurface->lDelta;
164           }
165         }
166         else
167         {
168           SourceBits = (PBYTE)BltInfo->SourceSurface->pvScan0 + ((BltInfo->SourcePoint.y + BltInfo->DestRect.bottom - BltInfo->DestRect.top - 1) * BltInfo->SourceSurface->lDelta) + 3 * BltInfo->SourcePoint.x;
169           DestBits = (PBYTE)BltInfo->DestSurface->pvScan0 + ((BltInfo->DestRect.bottom - 1) * BltInfo->DestSurface->lDelta) + 3 * BltInfo->DestRect.left;
170           for (j = BltInfo->DestRect.bottom - 1; BltInfo->DestRect.top <= j; j--)
171           {
172             RtlMoveMemory(DestBits, SourceBits, 3 * (BltInfo->DestRect.right - BltInfo->DestRect.left));
173             SourceBits -= BltInfo->SourceSurface->lDelta;
174             DestBits -= BltInfo->DestSurface->lDelta;
175           }
176         }
177       }
178       else
179       {
180         sx = BltInfo->SourcePoint.x;
181         sy = BltInfo->SourcePoint.y;
182 
183         for (j=BltInfo->DestRect.top; j<BltInfo->DestRect.bottom; j++)
184         {
185           sx = BltInfo->SourcePoint.x;
186           for (i=BltInfo->DestRect.left; i<BltInfo->DestRect.right; i++)
187           {
188             DWORD pixel = DIB_24BPP_GetPixel(BltInfo->SourceSurface, sx, sy);
189             DIB_24BPP_PutPixel(BltInfo->DestSurface, i, j, XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, pixel));
190             sx++;
191           }
192           sy++;
193         }
194       }
195       break;
196 
197     case BMF_32BPP:
198       SourceLine = (PBYTE)BltInfo->SourceSurface->pvScan0 + (BltInfo->SourcePoint.y * BltInfo->SourceSurface->lDelta) + 4 * BltInfo->SourcePoint.x;
199       DestLine = DestBits;
200 
201       for (j = BltInfo->DestRect.top; j < BltInfo->DestRect.bottom; j++)
202       {
203         SourceBits = SourceLine;
204         DestBits = DestLine;
205 
206         for (i = BltInfo->DestRect.left; i < BltInfo->DestRect.right; i++)
207         {
208           xColor = XLATEOBJ_iXlate(BltInfo->XlateSourceToDest, *((PDWORD) SourceBits));
209           *DestBits = xColor & 0xff;
210           *(PWORD)(DestBits + 1) = (WORD)(xColor >> 8);
211           SourceBits += 4;
212           DestBits += 3;
213         }
214 
215         SourceLine += BltInfo->SourceSurface->lDelta;
216         DestLine += BltInfo->DestSurface->lDelta;
217       }
218       break;
219 
220     default:
221       DbgPrint("DIB_24BPP_Bitblt: Unhandled Source BPP: %u\n", BitsPerFormat(BltInfo->SourceSurface->iBitmapFormat));
222       return FALSE;
223   }
224 
225   return TRUE;
226 }
227 
228 BOOLEAN
229 DIB_24BPP_BitBlt(PBLTINFO BltInfo)
230 {
231    LONG DestX, DestY;
232    LONG SourceX, SourceY;
233    LONG PatternY = 0;
234    ULONG Dest, Source = 0, Pattern = 0;
235    BOOL UsesSource;
236    BOOL UsesPattern;
237    PBYTE DestBits;
238 
239    UsesSource = ROP4_USES_SOURCE(BltInfo->Rop4);
240    UsesPattern = ROP4_USES_PATTERN(BltInfo->Rop4);
241 
242    SourceY = BltInfo->SourcePoint.y;
243    DestBits = (PBYTE)(
244       (PBYTE)BltInfo->DestSurface->pvScan0 +
245       (BltInfo->DestRect.left << 1) + BltInfo->DestRect.left +
246       BltInfo->DestRect.top * BltInfo->DestSurface->lDelta);
247 
248    if (UsesPattern)
249    {
250       if (BltInfo->PatternSurface)
251       {
252          PatternY = (BltInfo->DestRect.top - BltInfo->BrushOrigin.y) %
253                     BltInfo->PatternSurface->sizlBitmap.cy;
254       }
255       else
256       {
257          if (BltInfo->Brush)
258             Pattern = BltInfo->Brush->iSolidColor;
259       }
260    }
261 
262    for (DestY = BltInfo->DestRect.top; DestY < BltInfo->DestRect.bottom; DestY++)
263    {
264       SourceX = BltInfo->SourcePoint.x;
265 
266       for (DestX = BltInfo->DestRect.left; DestX < BltInfo->DestRect.right; DestX++, DestBits += 3, SourceX++)
267       {
268          Dest = *((PUSHORT)DestBits) + (*(DestBits + 2) << 16);
269 
270          if (UsesSource)
271          {
272             Source = DIB_GetSource(BltInfo->SourceSurface, SourceX, SourceY, BltInfo->XlateSourceToDest);
273          }
274 
275          if (BltInfo->PatternSurface)
276          {
277             Pattern = DIB_GetSourceIndex(BltInfo->PatternSurface, (DestX - BltInfo->BrushOrigin.x) % BltInfo->PatternSurface->sizlBitmap.cx, PatternY);
278          }
279 
280          Dest = DIB_DoRop(BltInfo->Rop4, Dest, Source, Pattern) & 0xFFFFFF;
281          *(PUSHORT)(DestBits) = Dest & 0xFFFF;
282          *(DestBits + 2) = (BYTE)(Dest >> 16);
283       }
284 
285       SourceY++;
286       if (BltInfo->PatternSurface)
287       {
288          PatternY++;
289          PatternY %= BltInfo->PatternSurface->sizlBitmap.cy;
290       }
291       DestBits -= (BltInfo->DestRect.right - BltInfo->DestRect.left) * 3;
292       DestBits += BltInfo->DestSurface->lDelta;
293    }
294 
295    return TRUE;
296 }
297 
298 /* BitBlt Optimize */
299 BOOLEAN
300 DIB_24BPP_ColorFill(SURFOBJ* DestSurface, RECTL* DestRect, ULONG color)
301 {
302   LONG DestY;
303 
304 #if defined(_M_IX86) && !defined(_MSC_VER)
305   PBYTE xaddr = (PBYTE)DestSurface->pvScan0 + DestRect->top * DestSurface->lDelta + (DestRect->left << 1) + DestRect->left;
306   PBYTE addr;
307   ULONG Count;
308   ULONG xCount=DestRect->right - DestRect->left;
309 
310   for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
311   {
312     Count = xCount;
313     addr = xaddr;
314     xaddr = (PBYTE)((ULONG_PTR)addr + DestSurface->lDelta);
315 
316     if (Count < 8)
317     {
318       /* For small fills, don't bother doing anything fancy */
319       while (Count--)
320         {
321           *(PUSHORT)(addr) = color;
322           addr += 2;
323           *(addr) = color >> 16;
324           addr += 1;
325         }
326     }
327     else
328     {
329       /* Align to 4-byte address */
330       while (0 != ((ULONG_PTR) addr & 0x3))
331       {
332         *(PUSHORT)(addr) = color;
333         addr += 2;
334         *(addr) = color >> 16;
335         addr += 1;
336         Count--;
337       }
338       /* If the color we need to fill with is 0ABC, then the final mem pattern
339        * (note little-endianness) would be:
340        *
341        * |C.B.A|C.B.A|C.B.A|C.B.A|   <- pixel borders
342        * |C.B.A.C|B.A.C.B|A.C.B.A|   <- ULONG borders
343        *
344        * So, taking endianness into account again, we need to fill with these
345        * ULONGs: CABC BCAB ABCA */
346 
347       /* This is about 30% faster than the generic C code below */
348       __asm__ __volatile__ (
349         "movl %1, %%ecx\n\t"
350         "andl $0xffffff, %%ecx\n\t"     /* 0ABC */
351         "movl %%ecx, %%ebx\n\t"         /* Construct BCAB in ebx */
352         "shrl $8, %%ebx\n\t"
353         "movl %%ecx, %%eax\n\t"
354         "shll $16, %%eax\n\t"
355         "orl  %%eax, %%ebx\n\t"
356         "movl %%ecx, %%edx\n\t"         /* Construct ABCA in edx */
357         "shll $8, %%edx\n\t"
358         "movl %%ecx, %%eax\n\t"
359         "shrl $16, %%eax\n\t"
360         "orl  %%eax, %%edx\n\t"
361         "movl %%ecx, %%eax\n\t"         /* Construct CABC in eax */
362         "shll $24, %%eax\n\t"
363         "orl  %%ecx, %%eax\n\t"
364         "movl %2, %%ecx\n\t"            /* Load count */
365         "shr  $2, %%ecx\n\t"
366         "movl %3, %%edi\n"              /* Load dest */
367         "1:\n\t"
368         "movl %%eax, (%%edi)\n\t"       /* Store 4 pixels, 12 bytes */
369         "movl %%ebx, 4(%%edi)\n\t"
370         "movl %%edx, 8(%%edi)\n\t"
371         "addl $12, %%edi\n\t"
372         "dec  %%ecx\n\t"
373         "jnz  1b\n\t"
374         "movl %%edi, %0"
375         : "=m"(addr)
376         : "m"(color), "m"(Count), "m"(addr)
377         : "%eax", "%ebx", "%ecx", "%edx", "%edi");
378       Count = Count & 0x03;
379       while (0 != Count--)
380       {
381         *(PUSHORT)(addr) = color;
382         addr += 2;
383         *(addr) = color >> 16;
384         addr += 1;
385       }
386     }
387   }
388 #else
389 
390   for (DestY = DestRect->top; DestY< DestRect->bottom; DestY++)
391   {
392     DIB_24BPP_HLine(DestSurface, DestRect->left, DestRect->right, DestY, color);
393   }
394 #endif
395   return TRUE;
396 }
397 
398 BOOLEAN
399 DIB_24BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
400                          RECTL*  DestRect,  RECTL *SourceRect,
401                          XLATEOBJ *ColorTranslation, ULONG iTransColor)
402 {
403   LONG X, Y, SourceX, SourceY = 0, wd;
404   ULONG Source = 0, Dest;
405   BYTE *DestBits;
406 
407   LONG DstHeight;
408   LONG DstWidth;
409   LONG SrcHeight;
410   LONG SrcWidth;
411 
412   DstHeight = DestRect->bottom - DestRect->top;
413   DstWidth = DestRect->right - DestRect->left;
414   SrcHeight = SourceRect->bottom - SourceRect->top;
415   SrcWidth = SourceRect->right - SourceRect->left;
416 
417   DestBits = (BYTE*)((PBYTE)DestSurf->pvScan0 +
418                       (DestRect->left * 3) +
419                       DestRect->top * DestSurf->lDelta);
420   wd = DestSurf->lDelta - ((DestRect->right - DestRect->left) * 3);
421 
422   for(Y = DestRect->top; Y < DestRect->bottom; Y++)
423   {
424     SourceY = SourceRect->top+(Y - DestRect->top) * SrcHeight / DstHeight;
425     for(X = DestRect->left; X < DestRect->right; X++, DestBits += 3)
426     {
427       SourceX = SourceRect->left+(X - DestRect->left) * SrcWidth / DstWidth;
428       if (SourceX >= 0 && SourceY >= 0 &&
429           SourceSurf->sizlBitmap.cx > SourceX && SourceSurf->sizlBitmap.cy > SourceY)
430       {
431         Source = DIB_GetSourceIndex(SourceSurf, SourceX, SourceY);
432         if(Source != iTransColor)
433         {
434           Dest = XLATEOBJ_iXlate(ColorTranslation, Source) & 0xFFFFFF;
435            *(PUSHORT)(DestBits) = Dest & 0xFFFF;
436            *(DestBits + 2) = (BYTE)(Dest >> 16);
437         }
438       }
439     }
440 
441     DestBits = (BYTE*)((ULONG_PTR)DestBits + wd);
442   }
443 
444   return TRUE;
445 }
446 
447 typedef union {
448    ULONG ul;
449    struct {
450       UCHAR red;
451       UCHAR green;
452       UCHAR blue;
453       UCHAR alpha;
454    } col;
455 } NICEPIXEL32;
456 
457 static __inline UCHAR
458 Clamp8(ULONG val)
459 {
460    return (val > 255) ? 255 : (UCHAR)val;
461 }
462 
463 BOOLEAN
464 DIB_24BPP_AlphaBlend(SURFOBJ* Dest, SURFOBJ* Source, RECTL* DestRect,
465                      RECTL* SourceRect, CLIPOBJ* ClipRegion,
466                      XLATEOBJ* ColorTranslation, BLENDOBJ* BlendObj)
467 {
468    INT Rows, Cols, SrcX, SrcY;
469    register PUCHAR Dst;
470    BLENDFUNCTION BlendFunc;
471    register NICEPIXEL32 DstPixel, SrcPixel;
472    UCHAR Alpha;
473    //UCHAR SrcBpp;
474 
475    DPRINT("DIB_24BPP_AlphaBlend: srcRect: (%d,%d)-(%d,%d), dstRect: (%d,%d)-(%d,%d)\n",
476           SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
477           DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
478 
479    BlendFunc = BlendObj->BlendFunction;
480    if (BlendFunc.BlendOp != AC_SRC_OVER)
481    {
482       DPRINT1("BlendOp != AC_SRC_OVER\n");
483       return FALSE;
484    }
485    if (BlendFunc.BlendFlags != 0)
486    {
487       DPRINT1("BlendFlags != 0\n");
488       return FALSE;
489    }
490    if ((BlendFunc.AlphaFormat & ~AC_SRC_ALPHA) != 0)
491    {
492       DPRINT1("Unsupported AlphaFormat (0x%x)\n", BlendFunc.AlphaFormat);
493       return FALSE;
494    }
495    if ((BlendFunc.AlphaFormat & AC_SRC_ALPHA) != 0 &&
496        BitsPerFormat(Source->iBitmapFormat) != 32)
497    {
498       DPRINT1("Source bitmap must be 32bpp when AC_SRC_ALPHA is set\n");
499       return FALSE;
500    }
501 
502    Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + (DestRect->top * Dest->lDelta) +
503                              (DestRect->left * 3));
504    //SrcBpp = BitsPerFormat(Source->iBitmapFormat);
505 
506    Rows = 0;
507    SrcY = SourceRect->top;
508    while (++Rows <= DestRect->bottom - DestRect->top)
509   {
510     Cols = 0;
511     SrcX = SourceRect->left;
512     while (++Cols <= DestRect->right - DestRect->left)
513     {
514       SrcPixel.ul = DIB_GetSource(Source, SrcX, SrcY, ColorTranslation);
515       SrcPixel.col.red = (SrcPixel.col.red * BlendFunc.SourceConstantAlpha) / 255;
516       SrcPixel.col.green = (SrcPixel.col.green * BlendFunc.SourceConstantAlpha) / 255;
517       SrcPixel.col.blue = (SrcPixel.col.blue * BlendFunc.SourceConstantAlpha) / 255;
518       if (!(BlendFunc.AlphaFormat & AC_SRC_ALPHA))
519       {
520           Alpha = BlendFunc.SourceConstantAlpha ;
521       }
522       else
523       {
524         Alpha = (SrcPixel.col.alpha * BlendFunc.SourceConstantAlpha) / 255;
525       }
526 
527       DstPixel.col.red = Clamp8((*Dst * (255 - Alpha)) / 255 + SrcPixel.col.red) ;
528       DstPixel.col.green = Clamp8((*(Dst+1) * (255 - Alpha) / 255 + SrcPixel.col.green)) ;
529       DstPixel.col.blue = Clamp8((*(Dst+2) * (255 - Alpha)) / 255 + SrcPixel.col.blue) ;
530       *Dst++ = DstPixel.col.red;
531       *Dst++ = DstPixel.col.green;
532       *Dst++ = DstPixel.col.blue;
533       SrcX = SourceRect->left + (Cols*(SourceRect->right - SourceRect->left))/(DestRect->right - DestRect->left);
534     }
535     Dst = (PUCHAR)((ULONG_PTR)Dest->pvScan0 + ((DestRect->top + Rows) * Dest->lDelta) +
536                 (DestRect->left*3));
537     SrcY = SourceRect->top + (Rows*(SourceRect->bottom - SourceRect->top))/(DestRect->bottom - DestRect->top);
538   }
539 
540    return TRUE;
541 }
542 
543 /* EOF */
544