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