update for HEAD-2003091401
[reactos.git] / drivers / dd / vga / display / objects / bitblt.c
1 #include <ntddk.h>
2 #define NDEBUG
3 #include <debug.h>
4 #include "../vgaddi.h"
5 #include "../vgavideo/vgavideo.h"
6 #include "brush.h"
7 #include "bitblt.h"
8
9 typedef BOOL (*PFN_VGABlt)(SURFOBJ*, SURFOBJ*, XLATEOBJ*, RECTL*, POINTL*);
10 typedef BOOL STDCALL (*PBLTRECTFUNC)(PSURFOBJ OutputObj,
11                                      PSURFOBJ InputObj,
12                                      PSURFOBJ Mask,
13                                      PXLATEOBJ ColorTranslation,
14                                      PRECTL OutputRect,
15                                      PPOINTL InputPoint,
16                                      PPOINTL MaskOrigin,
17                                      PBRUSHOBJ Brush,
18                                      PPOINTL BrushOrigin,
19                                      ROP4 Rop4);
20
21 static BOOL FASTCALL VGADDI_IntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
22 {
23   static const RECTL rclEmpty = { 0, 0, 0, 0 };
24
25   prcDst->left  = max(prcSrc1->left, prcSrc2->left);
26   prcDst->right = min(prcSrc1->right, prcSrc2->right);
27
28   if (prcDst->left < prcDst->right)
29   {
30     prcDst->top    = max(prcSrc1->top, prcSrc2->top);
31     prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
32
33     if (prcDst->top < prcDst->bottom) return(TRUE);
34   }
35
36   *prcDst = rclEmpty;
37
38   return(FALSE);
39 }
40
41 BOOL
42 DIBtoVGA(SURFOBJ *Dest, SURFOBJ *Source, XLATEOBJ *ColorTranslation,
43          RECTL *DestRect, POINTL *SourcePoint)
44 {
45   LONG dx, dy;
46
47   dx = DestRect->right  - DestRect->left;
48   dy = DestRect->bottom - DestRect->top;
49
50   if (NULL == ColorTranslation || 0 != (ColorTranslation->flXlate & XO_TRIVIAL))
51     {
52       DIB_BltToVGA(DestRect->left, DestRect->top, dx, dy,
53                    Source->pvScan0 + SourcePoint->y * Source->lDelta + (SourcePoint->x >> 1),
54                    Source->lDelta);
55     }
56   else
57     {
58       /* Perform color translation */
59       DIB_BltToVGAWithXlate(DestRect->left, DestRect->top, dx, dy,
60                             Source->pvScan0 + SourcePoint->y * Source->lDelta + (SourcePoint->x >> 1),
61                             Source->lDelta, ColorTranslation);
62     }
63 }
64
65 BOOL 
66 VGAtoDIB(SURFOBJ *Dest, SURFOBJ *Source, XLATEOBJ *ColorTranslation,
67          RECTL *DestRect, POINTL *SourcePoint)
68 {
69   LONG i, j, dx, dy, RGBulong;
70   BYTE  *GDIpos, *initial, idxColor;
71   
72   // Used by the temporary DFB
73   PDEVSURF      TargetSurf;
74   DEVSURF       DestDevSurf;
75   PSURFOBJ      TargetBitmapSurf;
76   HBITMAP       hTargetBitmap;
77   SIZEL         InterSize;
78   POINTL        ZeroPoint;
79
80   // FIXME: Optimize to retrieve entire bytes at a time (see /display/vgavideo/vgavideo.c:vgaGetByte)
81
82   GDIpos = Dest->pvBits /* + (DestRect->top * Dest->lDelta) + (DestRect->left >> 1) */ ;
83   dx = DestRect->right  - DestRect->left;
84   dy = DestRect->bottom - DestRect->top;
85
86   if(ColorTranslation == NULL)
87   {
88     // Prepare a Dest Dev Target and copy from the DFB to the DIB
89     DestDevSurf.NextScan = Dest->lDelta;
90     DestDevSurf.StartBmp = Dest->pvScan0;
91
92     DIB_BltFromVGA(SourcePoint->x, SourcePoint->y, dx, dy, Dest->pvBits, Dest->lDelta);
93
94   } else {
95     // Color translation
96     for(j=SourcePoint->y; j<SourcePoint->y+dy; j++)
97     {
98        initial = GDIpos;
99        for(i=SourcePoint->x; i<SourcePoint->x+dx; i++)
100        {
101          *GDIpos = XLATEOBJ_iXlate(ColorTranslation, vgaGetPixel(i, j));
102          GDIpos+=1;
103        }
104        GDIpos = initial + Dest->lDelta;
105     }
106   }
107 }
108
109 BOOL 
110 DFBtoVGA(SURFOBJ *Dest, SURFOBJ *Source, XLATEOBJ *ColorTranslation,
111          RECTL *DestRect, POINTL *SourcePoint)
112 {
113   // Do DFBs need color translation??
114 }
115
116 BOOL
117 VGAtoDFB(SURFOBJ *Dest, SURFOBJ *Source, XLATEOBJ *ColorTranslation,
118          RECTL *DestRect, POINTL *SourcePoint)
119 {
120   // Do DFBs need color translation??
121 }
122
123 BOOL
124 VGAtoVGA(SURFOBJ *Dest, SURFOBJ *Source, XLATEOBJ *ColorTranslation,
125          RECTL *DestRect, POINTL *SourcePoint)
126 {
127   LONG i, i2, j, dx, dy, alterx, altery;
128   //LARGE_INTEGER Start, End; // for performance measurement only
129   static char buf[640];
130
131   // Calculate deltas
132
133   dx = DestRect->right  - DestRect->left;
134   dy = DestRect->bottom - DestRect->top;
135
136   alterx = DestRect->left - SourcePoint->x;
137   altery = DestRect->top - SourcePoint->y;
138
139   //KeQueryTickCount ( &Start );
140
141   i = SourcePoint->x;
142   i2 = i + alterx;
143
144   if (SourcePoint->y >= DestRect->top)
145   {
146     for(j=SourcePoint->y; j<SourcePoint->y+dy; j++)
147       {
148         LONG j2 = j + altery;
149         vgaReadScan  ( i,  j,  dx, buf );
150         vgaWriteScan ( i2, j2, dx, buf );
151       }
152   }
153   else
154   {
155     for(j=(SourcePoint->y+dy-1); j>=SourcePoint->y; j--)
156       {
157         LONG j2 = j + altery;
158         vgaReadScan  ( i,  j,  dx, buf );
159         vgaWriteScan ( i2, j2, dx, buf );
160       }
161   }
162
163   //KeQueryTickCount ( &End );
164   //DbgPrint ( "VgaBitBlt timing: %lu\n", (ULONG)(End.QuadPart-Start.QuadPart) );
165
166   return TRUE;
167 }
168
169 BOOL STDCALL
170 VGADDI_BltBrush(PSURFOBJ Dest, PSURFOBJ Source, PSURFOBJ MaskSurf,
171                 PXLATEOBJ ColorTranslation, PRECT DestRect,
172                 PPOINTL SourcePoint, PPOINTL MaskPoint,
173                 PBRUSHOBJ Brush, PPOINTL BrushPoint, ROP4 Rop4)
174 {
175   UCHAR SolidColor = 0;
176   ULONG Left;
177   ULONG Right;
178   ULONG Length;
179   PUCHAR Video;
180   UCHAR Mask;
181   ULONG i, j;
182   ULONG RasterOp = VGA_NORMAL;
183
184   /* Punt brush blts to non-device surfaces. */
185   if (Dest->iType != STYPE_DEVICE)
186     {
187       return(FALSE);
188     }
189
190   /* Punt pattern fills. */
191   if ((Rop4 == PATCOPY || Rop4 == PATINVERT) && 
192       Brush->iSolidColor == 0xFFFFFFFF)
193     {
194       return(FALSE);
195     }
196
197   /* Get the brush colour. */
198   switch (Rop4)
199     {
200     case PATCOPY: SolidColor = Brush->iSolidColor; break;
201     case PATINVERT: SolidColor = Brush->iSolidColor; RasterOp = VGA_XOR; break;
202     case WHITENESS: SolidColor = 0xF; break;
203     case BLACKNESS: SolidColor = 0x0; break;
204     case DSTINVERT: SolidColor = 0xF; RasterOp = VGA_XOR; break;
205     }
206
207   /* Select write mode 3. */
208   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
209   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x03);
210
211   /* Setup set/reset register. */
212   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x00);
213   WRITE_PORT_UCHAR((PUCHAR)GRA_D, (UCHAR)SolidColor);
214
215   /* Enable writes to all pixels. */
216   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);
217   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
218
219   /* Set up data rotate. */
220   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
221   WRITE_PORT_UCHAR((PUCHAR)GRA_D, RasterOp);
222   
223   /* Fill any pixels on the left which don't fall into a full row of eight. */
224   if ((DestRect->left % 8) != 0)
225     {
226       /* Disable writes to pixels outside of the destination rectangle. */
227       Mask = (1 << (8 - (DestRect->left % 8))) - 1;
228       if ((DestRect->right - DestRect->left) < (8 - (DestRect->left % 8)))
229         {
230           Mask &= ~((1 << (8 - (DestRect->right % 8))) - 1);
231         }
232
233       /* Write the same color to each pixel. */
234       Video = (PUCHAR)vidmem + DestRect->top * 80 + (DestRect->left >> 3);
235       for (i = DestRect->top; i < DestRect->bottom; i++, Video+=80)
236         {
237           (VOID)READ_REGISTER_UCHAR(Video);
238           WRITE_REGISTER_UCHAR(Video, Mask);
239         }
240
241       /* Have we finished. */
242       if ((DestRect->right - DestRect->left) < (8 - (DestRect->left % 8)))
243         {
244           /* Restore write mode 2. */
245           WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
246           WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
247
248           /* Set up data rotate. */
249           WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
250           WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
251
252           return TRUE;
253         }
254     }    
255
256   /* Fill any whole rows of eight pixels. */
257   Left = (DestRect->left + 7) & ~0x7;
258   Length = (DestRect->right >> 3) - (Left >> 3);
259   for (i = DestRect->top; i < DestRect->bottom; i++)
260     {
261       Video = (PUCHAR)vidmem + i * 80 + (Left >> 3);
262       for (j = 0; j < Length; j++, Video++)
263         {
264           (VOID)READ_REGISTER_UCHAR(Video);
265           WRITE_REGISTER_UCHAR(Video, 0xFF);
266         }
267     }
268
269   /* Fill any pixels on the right which don't fall into a complete row. */
270   if ((DestRect->right % 8) != 0)
271     {
272       /* Disable writes to pixels outside the destination rectangle. */
273       Mask = ~((1 << (8 - (DestRect->right % 8))) - 1);
274
275       Video = (PUCHAR)vidmem + DestRect->top * 80 + (DestRect->right >> 3);
276       for (i = DestRect->top; i < DestRect->bottom; i++, Video+=80)
277         {
278           (VOID)READ_REGISTER_UCHAR(Video);
279           WRITE_REGISTER_UCHAR(Video, Mask);
280         }
281     }
282
283   /* Restore write mode 2. */
284   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
285   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
286
287   /* Set up data rotate. */
288   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
289   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
290
291   return TRUE;
292 }
293
294 BOOL STDCALL
295 VGADDI_BltSrc(PSURFOBJ Dest, PSURFOBJ Source, PSURFOBJ Mask,
296               PXLATEOBJ ColorTranslation, PRECTL DestRect, PPOINTL SourcePoint,
297               PPOINTL MaskOrigin, PBRUSHOBJ Brush, PPOINTL BrushOrigin, ROP4 Rop4)
298 {
299   RECT_ENUM RectEnum;
300   BOOL EnumMore;
301   PFN_VGABlt  BltOperation;
302   ULONG SourceType;
303
304   SourceType = Source->iType;
305
306   if (SourceType == STYPE_BITMAP && Dest->iType == STYPE_DEVICE)
307     {
308       BltOperation = DIBtoVGA;
309     }
310   else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_BITMAP)
311     {
312       BltOperation = VGAtoDIB;
313     }
314   else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_DEVICE)
315     {
316       BltOperation = VGAtoVGA;
317     } 
318   else if (SourceType == STYPE_DEVBITMAP && Dest->iType == STYPE_DEVICE)
319     {
320       BltOperation = DFBtoVGA;
321     } 
322   else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_DEVBITMAP)
323     {
324       BltOperation = VGAtoDFB;
325     } 
326   else
327     {
328       /* Punt blts not involving a device or a device-bitmap. */
329       return(FALSE);
330    }
331
332   BltOperation(Dest, Source, ColorTranslation, DestRect, SourcePoint);
333   return(TRUE);
334 }
335
336 BOOL STDCALL
337 VGADDI_BltMask(PSURFOBJ Dest, PSURFOBJ Source, PSURFOBJ Mask,
338                PXLATEOBJ ColorTranslation, PRECTL DestRect,
339                PPOINTL SourcePoint, PPOINTL MaskPoint, BRUSHOBJ* Brush,
340                PPOINTL BrushPoint, ROP4 Rop4)
341 {
342   LONG i, j, dx, dy, idxColor, RGBulong = 0, c8;
343   BYTE *initial, *tMask, *lMask;
344
345   dx = DestRect->right  - DestRect->left;
346   dy = DestRect->bottom - DestRect->top;
347
348   if (ColorTranslation == NULL)
349     {
350       if (Mask != NULL)
351         {
352           tMask = Mask->pvBits;
353           for (j=0; j<dy; j++)
354             {
355               lMask = tMask;
356               c8 = 0;
357               for (i=0; i<dx; i++)
358                 {
359                   if((*lMask & maskbit[c8]) != 0)
360                     {
361                       vgaPutPixel(DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
362                     }
363                   c8++;
364                   if(c8 == 8) { lMask++; c8=0; }
365                 }
366               tMask += Mask->lDelta;
367             }
368         }
369     }
370 }
371
372 BOOL STDCALL
373 DrvBitBlt(SURFOBJ *Dest,
374           SURFOBJ *Source,
375           SURFOBJ *Mask,
376           CLIPOBJ *Clip,
377           XLATEOBJ *ColorTranslation,
378           RECTL *DestRect,
379           POINTL *SourcePoint,
380           POINTL *MaskPoint,
381           BRUSHOBJ *Brush,
382           POINTL *BrushPoint,
383           ROP4 rop4)
384 {
385   PBLTRECTFUNC BltRectFunc;
386   RECTL CombinedRect;
387   BOOL Ret;
388   RECT_ENUM RectEnum;
389   BOOL EnumMore;
390   unsigned i;
391   POINTL Pt;
392   ULONG Direction;
393   
394   switch (rop4)
395     {
396     case BLACKNESS:
397     case PATCOPY:
398     case WHITENESS:
399     case PATINVERT:
400     case DSTINVERT:
401       BltRectFunc = VGADDI_BltBrush;
402       break;
403
404     case SRCCOPY:
405       if (BMF_4BPP == Source->iBitmapFormat && BMF_4BPP == Dest->iBitmapFormat)
406         {
407           BltRectFunc = VGADDI_BltSrc;
408         }
409       else
410         {
411           return FALSE;
412         }
413       break;
414
415     case 0xAACC:
416       BltRectFunc = VGADDI_BltMask;
417       break;
418
419     default:
420       return FALSE;
421     }
422
423   switch(NULL == Clip ? DC_TRIVIAL : Clip->iDComplexity)
424   {
425     case DC_TRIVIAL:
426       Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, DestRect,
427                            SourcePoint, MaskPoint, Brush, BrushPoint,
428                            rop4);
429       break;
430     case DC_RECT:
431       // Clip the blt to the clip rectangle
432       VGADDI_IntersectRect(&CombinedRect, DestRect, &(Clip->rclBounds));
433       Pt.x = SourcePoint->x + CombinedRect.left - DestRect->left;
434       Pt.y = SourcePoint->y + CombinedRect.top - DestRect->top;
435       Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, &CombinedRect,
436                            &Pt, MaskPoint, Brush, BrushPoint,
437                            rop4);
438       break;
439     case DC_COMPLEX:
440       Ret = TRUE;
441       if (Dest == Source)
442         {
443           if (DestRect->top <= SourcePoint->y)
444             {
445               Direction = DestRect->left < SourcePoint->x ? CD_RIGHTDOWN : CD_LEFTDOWN;
446             }
447           else
448             {
449               Direction = DestRect->left < SourcePoint->x ? CD_RIGHTUP : CD_LEFTUP;
450             }
451         }
452       else
453         {
454           Direction = CD_ANY;
455         }
456       CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, Direction, ENUM_RECT_LIMIT);
457       do
458         {
459           EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
460
461           for (i = 0; i < RectEnum.c; i++)
462             {
463               VGADDI_IntersectRect(&CombinedRect, DestRect, RectEnum.arcl + i);
464               Pt.x = SourcePoint->x + CombinedRect.left - DestRect->left;
465               Pt.y = SourcePoint->y + CombinedRect.top - DestRect->top;
466               Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, &CombinedRect,
467                                    &Pt, MaskPoint, Brush, BrushPoint, rop4) &&
468                     Ret;
469             }
470         }
471       while (EnumMore);
472       break;
473   }
474
475   return Ret;
476 }