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