Sync up to trunk head before merging.
[reactos.git] / drivers / base / bootvid / i386 / vga.c
1 #include "precomp.h"
2
3 /* GLOBALS *******************************************************************/
4
5 ULONG ScrollRegion[4] =
6 {
7 0,
8 0,
9 640 - 1,
10 480 - 1
11 };
12 UCHAR lMaskTable[8] =
13 {
14 (1 << 8) - (1 << 0),
15 (1 << 7) - (1 << 0),
16 (1 << 6) - (1 << 0),
17 (1 << 5) - (1 << 0),
18 (1 << 4) - (1 << 0),
19 (1 << 3) - (1 << 0),
20 (1 << 2) - (1 << 0),
21 (1 << 1) - (1 << 0)
22 };
23 UCHAR rMaskTable[8] =
24 {
25 (1 << 7),
26 (1 << 7)+ (1 << 6),
27 (1 << 7)+ (1 << 6) + (1 << 5),
28 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4),
29 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3),
30 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2),
31 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1),
32 (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1) +
33 (1 << 0),
34 };
35 UCHAR PixelMask[8] =
36 {
37 (1 << 7),
38 (1 << 6),
39 (1 << 5),
40 (1 << 4),
41 (1 << 3),
42 (1 << 2),
43 (1 << 1),
44 (1 << 0),
45 };
46 ULONG lookup[16] =
47 {
48 0x0000,
49 0x0100,
50 0x1000,
51 0x1100,
52 0x0001,
53 0x0101,
54 0x1001,
55 0x1101,
56 0x0010,
57 0x0110,
58 0x1010,
59 0x1110,
60 0x0011,
61 0x0111,
62 0x1011,
63 0x1111,
64 };
65
66 ULONG VidTextColor = 0xF;
67 ULONG curr_x = 0;
68 ULONG curr_y = 0;
69 BOOLEAN CarriageReturn = FALSE;
70 ULONG_PTR VgaRegisterBase = 0;
71 ULONG_PTR VgaBase = 0;
72
73 #define __outpb(Port, Value) \
74 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + Port, (UCHAR)Value)
75
76 #define __outpw(Port, Value) \
77 WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + Port), (USHORT)Value)
78
79 /* PRIVATE FUNCTIONS *********************************************************/
80
81 VOID
82 NTAPI
83 ReadWriteMode(UCHAR Mode)
84 {
85 UCHAR Value;
86
87 /* Switch to graphics mode register */
88 __outpb(0x3CE, 5);
89
90 /* Get the current register value, minus the current mode */
91 Value = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) & 0xF4;
92
93 /* Set the new mode */
94 __outpb(0x3CF, Mode | Value);
95 }
96
97
98 FORCEINLINE
99 VOID
100 SetPixel(IN ULONG Left,
101 IN ULONG Top,
102 IN UCHAR Color)
103 {
104 PUCHAR PixelPosition;
105
106 /* Calculate the pixel position. */
107 PixelPosition = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80);
108
109 /* Select the bitmask register and write the mask */
110 __outpw(0x3CE, (PixelMask[Left & 7] << 8) | 8);
111
112 /* Read the current pixel value and add our color */
113 WRITE_REGISTER_UCHAR(PixelPosition,
114 READ_REGISTER_UCHAR(PixelPosition) & Color);
115 }
116
117 #ifdef CHAR_GEN_UPSIDE_DOWN
118 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
119 # define FONT_PTR_DELTA (-1)
120 #else
121 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT];
122 # define FONT_PTR_DELTA (1)
123 #endif
124
125 #define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \
126 /* Select the bitmask register and write the mask */ \
127 __outpw(0x3CE, (_PixelMask << 8) | 8); \
128 \
129 /* Set the new color */ \
130 WRITE_REGISTER_UCHAR(_PixelPtr, (UCHAR)_TextColor);\
131
132 VOID
133 NTAPI
134 DisplayCharacter(CHAR Character,
135 ULONG Left,
136 ULONG Top,
137 ULONG TextColor,
138 ULONG BackColor)
139 {
140 PUCHAR FontChar, PixelPtr;
141 ULONG Height;
142 UCHAR Shift;
143
144 /* Switch to mode 10 */
145 ReadWriteMode(10);
146
147 /* Clear the 4 planes (we're already in unchained mode here) */
148 __outpw(0x3C4, 0xF02);
149
150 /* Select the color don't care register */
151 __outpw(0x3CE, 7);
152
153 /* Calculate shift */
154 Shift = Left & 7;
155
156 /* Get the font and pixel pointer */
157 FontChar = GetFontPtr(Character);
158 PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80);
159
160 /* Loop all pixel rows */
161 Height = BOOTCHAR_HEIGHT;
162 do
163 {
164 SET_PIXELS(PixelPtr, *FontChar >> Shift, TextColor);
165 PixelPtr += 80;
166 FontChar += FONT_PTR_DELTA;
167 } while (--Height);
168
169 /* Check if we need to update neighbor bytes */
170 if (Shift)
171 {
172 /* Calculate shift for 2nd byte */
173 Shift = 8 - Shift;
174
175 /* Get the font and pixel pointer (2nd byte) */
176 FontChar = GetFontPtr(Character);
177 PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80) + 1;
178
179 /* Loop all pixel rows */
180 Height = BOOTCHAR_HEIGHT;
181 do
182 {
183 SET_PIXELS(PixelPtr, *FontChar << Shift, TextColor);
184 PixelPtr += 80;
185 FontChar += FONT_PTR_DELTA;
186 } while (--Height);
187 }
188
189 /* Check if the background color is transparent */
190 if (BackColor >= 16)
191 {
192 /* We are done */
193 return;
194 }
195
196 /* Calculate shift */
197 Shift = Left & 7;
198
199 /* Get the font and pixel pointer */
200 FontChar = GetFontPtr(Character);
201 PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80);
202
203 /* Loop all pixel rows */
204 Height = BOOTCHAR_HEIGHT;
205 do
206 {
207 SET_PIXELS(PixelPtr, ~*FontChar >> Shift, BackColor);
208 PixelPtr += 80;
209 FontChar += FONT_PTR_DELTA;
210 } while (--Height);
211
212 /* Check if we need to update neighbor bytes */
213 if (Shift)
214 {
215 /* Calculate shift for 2nd byte */
216 Shift = 8 - Shift;
217
218 /* Get the font and pixel pointer (2nd byte) */
219 FontChar = GetFontPtr(Character);
220 PixelPtr = (PUCHAR)VgaBase + (Left >> 3) + (Top * 80) + 1;
221
222 /* Loop all pixel rows */
223 Height = BOOTCHAR_HEIGHT;
224 do
225 {
226 SET_PIXELS(PixelPtr, ~*FontChar << Shift, BackColor);
227 PixelPtr += 80;
228 FontChar += FONT_PTR_DELTA;
229 } while (--Height);
230 }
231 }
232
233 VOID
234 NTAPI
235 DisplayStringXY(PUCHAR String,
236 ULONG Left,
237 ULONG Top,
238 ULONG TextColor,
239 ULONG BackColor)
240 {
241 /* Loop every character */
242 while (*String)
243 {
244 /* Display a character */
245 DisplayCharacter(*String, Left, Top, TextColor, BackColor);
246
247 /* Move to next character and next position */
248 String++;
249 Left += 8;
250 }
251 }
252
253 VOID
254 NTAPI
255 SetPaletteEntryRGB(IN ULONG Id,
256 IN ULONG Rgb)
257 {
258 PCHAR Colors = (PCHAR)&Rgb;
259
260 /* Set the palette index */
261 __outpb(0x3C8, (UCHAR)Id);
262
263 /* Set RGB colors */
264 __outpb(0x3C9, Colors[2] >> 2);
265 __outpb(0x3C9, Colors[1] >> 2);
266 __outpb(0x3C9, Colors[0] >> 2);
267 }
268
269 VOID
270 NTAPI
271 InitPaletteWithTable(IN PULONG Table,
272 IN ULONG Count)
273 {
274 ULONG i;
275 PULONG Entry = Table;
276
277 /* Loop every entry */
278 for (i = 0; i < Count; i++, Entry++)
279 {
280 /* Set the entry */
281 SetPaletteEntryRGB(i, *Entry);
282 }
283 }
284
285 VOID
286 NTAPI
287 SetPaletteEntry(IN ULONG Id,
288 IN ULONG PaletteEntry)
289 {
290 /* Set the palette index */
291 __outpb(0x3C8, (UCHAR)Id);
292
293 /* Set RGB colors */
294 __outpb(0x3C9, PaletteEntry & 0xFF);
295 __outpb(0x3C9, (PaletteEntry >>= 8) & 0xFF);
296 __outpb(0x3C9, (PaletteEntry >> 8) & 0xFF);
297 }
298
299 VOID
300 NTAPI
301 InitializePalette(VOID)
302 {
303 ULONG PaletteEntry[16] = {0,
304 0x20,
305 0x2000,
306 0x2020,
307 0x200000,
308 0x200020,
309 0x202000,
310 0x202020,
311 0x303030,
312 0x3F,
313 0x3F00,
314 0x3F3F,
315 0x3F0000,
316 0x3F003F,
317 0x3F3F00,
318 0x3F3F3F};
319 ULONG i;
320
321 /* Loop all the entries and set their palettes */
322 for (i = 0; i < 16; i++) SetPaletteEntry(i, PaletteEntry[i]);
323 }
324
325 VOID
326 NTAPI
327 VgaScroll(ULONG Scroll)
328 {
329 ULONG Top, RowSize;
330 PUCHAR OldPosition, NewPosition;
331
332 /* Clear the 4 planes */
333 __outpw(0x3C4, 0xF02);
334
335 /* Set the bitmask to 0xFF for all 4 planes */
336 __outpw(0x3CE, 0xFF08);
337
338 /* Set Mode 1 */
339 ReadWriteMode(1);
340
341 RowSize = (ScrollRegion[2] - ScrollRegion[0] + 1) / 8;
342
343 /* Calculate the position in memory for the row */
344 OldPosition = (PUCHAR)VgaBase + (ScrollRegion[1] + Scroll) * 80 + ScrollRegion[0] / 8;
345 NewPosition = (PUCHAR)VgaBase + ScrollRegion[1] * 80 + ScrollRegion[0] / 8;
346
347 /* Start loop */
348 for(Top = ScrollRegion[1]; Top <= ScrollRegion[3]; ++Top)
349 {
350 #if defined(_M_IX86) || defined(_M_AMD64)
351 __movsb(NewPosition, OldPosition, RowSize);
352 #else
353 ULONG i;
354
355 /* Scroll the row */
356 for(i = 0; i < RowSize; ++i)
357 WRITE_REGISTER_UCHAR(NewPosition + i, READ_REGISTER_UCHAR(OldPosition + i));
358 #endif
359 OldPosition += 80;
360 NewPosition += 80;
361 }
362 }
363
364 VOID
365 NTAPI
366 PreserveRow(IN ULONG CurrentTop,
367 IN ULONG TopDelta,
368 IN BOOLEAN Direction)
369 {
370 PUCHAR Position1, Position2;
371 ULONG Count;
372
373 /* Clear the 4 planes */
374 __outpw(0x3C4, 0xF02);
375
376 /* Set the bitmask to 0xFF for all 4 planes */
377 __outpw(0x3CE, 0xFF08);
378
379 /* Set Mode 1 */
380 ReadWriteMode(1);
381
382 /* Check which way we're preserving */
383 if (Direction)
384 {
385 /* Calculate the position in memory for the row */
386 Position1 = (PUCHAR)VgaBase + CurrentTop * 80;
387 Position2 = (PUCHAR)VgaBase + 0x9600;
388 }
389 else
390 {
391 /* Calculate the position in memory for the row */
392 Position1 = (PUCHAR)VgaBase + 0x9600;
393 Position2 = (PUCHAR)VgaBase + CurrentTop * 80;
394 }
395
396 /* Set the count and make sure it's above 0 */
397 Count = TopDelta * 80;
398
399 #if defined(_M_IX86) || defined(_M_AMD64)
400 __movsb(Position1, Position2, Count);
401 #else
402 /* Loop every pixel */
403 while (Count--)
404 {
405 /* Write the data back on the other position */
406 WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2));
407
408 /* Increase both positions */
409 Position2++;
410 Position1++;
411 }
412 #endif
413 }
414
415 VOID
416 NTAPI
417 BitBlt(IN ULONG Left,
418 IN ULONG Top,
419 IN ULONG Width,
420 IN ULONG Height,
421 IN PUCHAR Buffer,
422 IN ULONG BitsPerPixel,
423 IN ULONG Delta)
424 {
425 ULONG sx, dx, dy;
426 UCHAR color;
427 ULONG offset = 0;
428 const ULONG Bottom = Top + Height;
429 const ULONG Right = Left + Width;
430
431 /* Check if the buffer isn't 4bpp */
432 if (BitsPerPixel != 4)
433 {
434 /* FIXME: TODO */
435 DbgPrint("Unhandled BitBlt\n"
436 "%lux%lu @ (%lu|%lu)\n"
437 "Bits Per Pixel %lu\n"
438 "Buffer: %p. Delta: %lu\n",
439 Width,
440 Height,
441 Left,
442 Top,
443 BitsPerPixel,
444 Buffer,
445 Delta);
446 return;
447 }
448
449 /* Switch to mode 10 */
450 ReadWriteMode(10);
451
452 /* Clear the 4 planes (we're already in unchained mode here) */
453 __outpw(0x3C4, 0xF02);
454
455 /* Select the color don't care register */
456 __outpw(0x3CE, 7);
457
458 /* 4bpp blitting */
459 dy = Top;
460 do
461 {
462 sx = 0;
463 do
464 {
465 /* Extract color */
466 color = Buffer[offset + sx];
467
468 /* Calc destination x */
469 dx = Left + (sx << 1);
470
471 /* Set two pixels */
472 SetPixel(dx, dy, color >> 4);
473 SetPixel(dx + 1, dy, color & 0x0F);
474
475 sx++;
476 } while (dx < Right);
477 offset += Delta;
478 dy++;
479 } while (dy < Bottom);
480 }
481
482 VOID
483 NTAPI
484 RleBitBlt(IN ULONG Left,
485 IN ULONG Top,
486 IN ULONG Width,
487 IN ULONG Height,
488 IN PUCHAR Buffer)
489 {
490 ULONG YDelta;
491 ULONG x;
492 ULONG RleValue, NewRleValue;
493 ULONG Color, Color2;
494 ULONG i, j;
495 ULONG Code;
496
497 /* Switch to mode 10 */
498 ReadWriteMode(10);
499
500 /* Clear the 4 planes (we're already in unchained mode here) */
501 __outpw(0x3C4, 0xF02);
502
503 /* Select the color don't care register */
504 __outpw(0x3CE, 7);
505
506 /* Set Y height and current X value and start loop */
507 YDelta = Top + Height - 1;
508 x = Left;
509 for (;;)
510 {
511 /* Get the current value and advance in the buffer */
512 RleValue = *Buffer;
513 Buffer++;
514 if (RleValue)
515 {
516 /* Check if we've gone past the edge */
517 if ((x + RleValue) > (Width + Left))
518 {
519 /* Fixeup the pixel value */
520 RleValue = Left - x + Width;
521 }
522
523 /* Get the new value */
524 NewRleValue = *Buffer;
525
526 /* Get the two colors */
527 Color = NewRleValue >> 4;
528 Color2 = NewRleValue & 0xF;
529
530 /* Increase buffer positition */
531 Buffer++;
532
533 /* Check if we need to do a fill */
534 if (Color == Color2)
535 {
536 /* Do a fill and continue the loop */
537 RleValue += x;
538 VidSolidColorFill(x, YDelta, RleValue - 1, YDelta, (UCHAR)Color);
539 x = RleValue;
540 continue;
541 }
542
543 /* Check if the pixel value is 1 or below */
544 if (RleValue > 1)
545 {
546 /* Set loop variables */
547 i = (RleValue - 2) / 2 + 1;
548 do
549 {
550 /* Set the pixels */
551 SetPixel(x, YDelta, (UCHAR)Color);
552 x++;
553 SetPixel(x, YDelta, (UCHAR)Color2);
554 x++;
555
556 /* Decrease pixel value */
557 RleValue -= 2;
558 } while (--i);
559 }
560
561 /* Check if there is any value at all */
562 if (RleValue)
563 {
564 /* Set the pixel and increase posititon */
565 SetPixel(x, YDelta, (UCHAR)Color);
566 x++;
567 }
568
569 /* Start over */
570 continue;
571 }
572
573 /* Get the current pixel value */
574 RleValue = *Buffer;
575 Code = RleValue;
576 switch (Code)
577 {
578 /* Case 0 */
579 case 0:
580
581 /* Set new x value, decrease distance and restart */
582 x = Left;
583 YDelta--;
584 Buffer++;
585 continue;
586
587 /* Case 1 */
588 case 1:
589
590 /* Done */
591 return;
592
593 /* Case 2 */
594 case 2:
595
596 /* Set new x value, decrease distance and restart */
597 Buffer++;
598 x += *Buffer;
599 Buffer++;
600 YDelta -= *Buffer;
601 Buffer++;
602 continue;
603
604 /* Other values */
605 default:
606
607 Buffer++;
608 break;
609 }
610
611 /* Check if we've gone past the edge */
612 if ((x + RleValue) > (Width + Left))
613 {
614 /* Set fixed up loop count */
615 i = RleValue - Left - Width + x;
616
617 /* Fixup pixel value */
618 RleValue -= i;
619 }
620 else
621 {
622 /* Clear loop count */
623 i = 0;
624 }
625
626 /* Check the value now */
627 if (RleValue > 1)
628 {
629 /* Set loop variables */
630 j = (RleValue - 2) / 2 + 1;
631 do
632 {
633 /* Get the new value */
634 NewRleValue = *Buffer;
635
636 /* Get the two colors */
637 Color = NewRleValue >> 4;
638 Color2 = NewRleValue & 0xF;
639
640 /* Increase buffer position */
641 Buffer++;
642
643 /* Set the pixels */
644 SetPixel(x, YDelta, (UCHAR)Color);
645 x++;
646 SetPixel(x, YDelta, (UCHAR)Color2);
647 x++;
648
649 /* Decrease pixel value */
650 RleValue -= 2;
651 } while (--j);
652 }
653
654 /* Check if there is any value at all */
655 if (RleValue)
656 {
657 /* Set the pixel and increase position */
658 Color = *Buffer >> 4;
659 Buffer++;
660 SetPixel(x, YDelta, (UCHAR)Color);
661 x++;
662 i--;
663 }
664
665 /* Check loop count now */
666 if ((LONG)i > 0)
667 {
668 /* Decrease it */
669 i--;
670
671 /* Set new position */
672 Buffer = Buffer + (i / 2) + 1;
673 }
674
675 /* Check if we need to increase the buffer */
676 if ((ULONG_PTR)Buffer & 1) Buffer++;
677 }
678 }
679
680 /* PUBLIC FUNCTIONS **********************************************************/
681
682 /*
683 * @implemented
684 */
685 ULONG
686 NTAPI
687 VidSetTextColor(ULONG Color)
688 {
689 ULONG OldColor;
690
691 /* Save the old color and set the new one */
692 OldColor = VidTextColor;
693 VidTextColor = Color;
694 return OldColor;
695 }
696
697 /*
698 * @implemented
699 */
700 VOID
701 NTAPI
702 VidDisplayStringXY(PUCHAR String,
703 ULONG Left,
704 ULONG Top,
705 BOOLEAN Transparent)
706 {
707 ULONG BackColor;
708
709 /* If the caller wanted transparent, then send the special value (16), else */
710 /* use our default and call the helper routine. */
711 BackColor = (Transparent) ? 16 : 14;
712 DisplayStringXY(String, Left, Top, 12, BackColor);
713 }
714
715 /*
716 * @implemented
717 */
718 VOID
719 NTAPI
720 VidSetScrollRegion(ULONG x1,
721 ULONG y1,
722 ULONG x2,
723 ULONG y2)
724 {
725 /* Assert alignment */
726 ASSERT((x1 & 0x7) == 0);
727 ASSERT((x2 & 0x7) == 7);
728
729 /* Set Scroll Region */
730 ScrollRegion[0] = x1;
731 ScrollRegion[1] = y1;
732 ScrollRegion[2] = x2;
733 ScrollRegion[3] = y2;
734
735 /* Set current X and Y */
736 curr_x = x1;
737 curr_y = y1;
738 }
739
740 /*
741 * @implemented
742 */
743 VOID
744 NTAPI
745 VidCleanUp(VOID)
746 {
747 /* Select bit mask register */
748 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
749
750 /* Clear it */
751 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 255);
752 }
753
754 /*
755 * @implemented
756 */
757 VOID
758 NTAPI
759 VidBufferToScreenBlt(IN PUCHAR Buffer,
760 IN ULONG Left,
761 IN ULONG Top,
762 IN ULONG Width,
763 IN ULONG Height,
764 IN ULONG Delta)
765 {
766 /* Make sure we have a width and height */
767 if (!(Width) || !(Height)) return;
768
769 /* Call the helper function */
770 BitBlt(Left, Top, Width, Height, Buffer, 4, Delta);
771 }
772
773 /*
774 * @implemented
775 */
776 VOID
777 NTAPI
778 VidDisplayString(PUCHAR String)
779 {
780 ULONG TopDelta = BOOTCHAR_HEIGHT + 1;
781
782 /* Start looping the string */
783 while (*String)
784 {
785 /* Treat new-line separately */
786 if (*String == '\n')
787 {
788 /* Modify Y position */
789 curr_y += TopDelta;
790 if (curr_y + TopDelta >= ScrollRegion[3])
791 {
792 /* Scroll the view */
793 VgaScroll(TopDelta);
794 curr_y -= TopDelta;
795 }
796 else
797 {
798 /* Preserve row */
799 PreserveRow(curr_y, TopDelta, FALSE);
800 }
801
802 /* Update current X */
803 curr_x = ScrollRegion[0];
804
805 /* Do not clear line if "\r\n" is given */
806 CarriageReturn = FALSE;
807 }
808 else if (*String == '\r')
809 {
810 /* Update current X */
811 curr_x = ScrollRegion[0];
812
813 /* Check if we're being followed by a new line */
814 CarriageReturn = TRUE;
815 }
816 else
817 {
818 /* check if we had a '\r' last time */
819 if (CarriageReturn)
820 {
821 /* We did, clear the current row */
822 PreserveRow(curr_y, TopDelta, TRUE);
823 CarriageReturn = FALSE;
824 }
825
826 /* Display this character */
827 DisplayCharacter(*String, curr_x, curr_y, VidTextColor, 16);
828 curr_x += 8;
829
830 /* Check if we should scroll */
831 if (curr_x + 8 > ScrollRegion[2])
832 {
833 /* Update Y position and check if we should scroll it */
834 curr_y += TopDelta;
835 if (curr_y + TopDelta > ScrollRegion[3])
836 {
837 /* Do the scroll */
838 VgaScroll(TopDelta);
839 curr_y -= TopDelta;
840 }
841 else
842 {
843 /* Preserve the current row */
844 PreserveRow(curr_y, TopDelta, FALSE);
845 }
846
847 /* Update X */
848 curr_x = ScrollRegion[0];
849 }
850 }
851
852 /* Get the next character */
853 String++;
854 }
855 }
856
857 /*
858 * @implemented
859 */
860 VOID
861 NTAPI
862 VidBitBlt(PUCHAR Buffer,
863 ULONG Left,
864 ULONG Top)
865 {
866 PBITMAPINFOHEADER BitmapInfoHeader;
867 LONG Delta;
868 PUCHAR BitmapOffset;
869
870 /* Get the Bitmap Header */
871 BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer;
872
873 /* Initialize the palette */
874 InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize),
875 (BitmapInfoHeader->biClrUsed) ?
876 BitmapInfoHeader->biClrUsed : 16);
877
878 /* Make sure we can support this bitmap */
879 ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4);
880
881 /* Calculate the delta and align it on 32-bytes, then calculate the actual */
882 /* start of the bitmap data. */
883 Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31;
884 Delta >>= 3;
885 Delta &= ~3;
886 BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + 16 * sizeof(ULONG);
887
888 /* Check the compression of the bitmap */
889 if (BitmapInfoHeader->biCompression == 2)
890 {
891 /* Make sure we have a width and a height */
892 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
893 {
894 /* We can use RLE Bit Blt */
895 RleBitBlt(Left,
896 Top,
897 BitmapInfoHeader->biWidth,
898 BitmapInfoHeader->biHeight,
899 BitmapOffset);
900 }
901 }
902 else
903 {
904 /* Check if the height is negative */
905 if (BitmapInfoHeader->biHeight < 0)
906 {
907 /* Make it positive in the header */
908 BitmapInfoHeader->biHeight *= -1;
909 }
910 else
911 {
912 /* Update buffer offset */
913 BitmapOffset += ((BitmapInfoHeader->biHeight -1) * Delta);
914 Delta *= -1;
915 }
916
917 /* Make sure we have a width and a height */
918 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
919 {
920 /* Do the BitBlt */
921 BitBlt(Left,
922 Top,
923 BitmapInfoHeader->biWidth,
924 BitmapInfoHeader->biHeight,
925 BitmapOffset,
926 BitmapInfoHeader->biBitCount,
927 Delta);
928 }
929 }
930 }
931
932 /*
933 * @implemented
934 */
935 VOID
936 NTAPI
937 VidScreenToBufferBlt(PUCHAR Buffer,
938 ULONG Left,
939 ULONG Top,
940 ULONG Width,
941 ULONG Height,
942 ULONG Delta)
943 {
944 ULONG Plane;
945 ULONG XDistance;
946 ULONG LeftDelta, RightDelta;
947 ULONG PixelOffset;
948 PUCHAR PixelPosition;
949 PUCHAR k, i;
950 PULONG m;
951 UCHAR Value, Value2;
952 UCHAR a;
953 ULONG b;
954 ULONG x, y;
955
956 /* Calculate total distance to copy on X */
957 XDistance = Left + Width - 1;
958
959 /* Start at plane 0 */
960 Plane = 0;
961
962 /* Calculate the 8-byte left and right deltas */
963 LeftDelta = Left & 7;
964 RightDelta = 8 - LeftDelta;
965
966 /* Clear the destination buffer */
967 RtlZeroMemory(Buffer, Delta * Height);
968
969 /* Calculate the pixel offset and convert the X distance into byte form */
970 PixelOffset = Top * 80 + (Left >> 3);
971 XDistance >>= 3;
972
973 /* Loop the 4 planes */
974 do
975 {
976 /* Set the current pixel position and reset buffer loop variable */
977 PixelPosition = (PUCHAR)VgaBase + PixelOffset;
978 i = Buffer;
979
980 /* Set Mode 0 */
981 ReadWriteMode(0);
982
983 /* Set the current plane */
984 __outpw(0x3CE, (Plane << 8) | 4);
985
986 /* Make sure we have a height */
987 if (Height > 0)
988 {
989 /* Start the outer Y loop */
990 y = Height;
991 do
992 {
993 /* Read the current value */
994 m = (PULONG)i;
995 Value = READ_REGISTER_UCHAR(PixelPosition);
996
997 /* Set Pixel Position loop variable */
998 k = PixelPosition + 1;
999
1000 /* Check if we're still within bounds */
1001 if (Left <= XDistance)
1002 {
1003 /* Start X Inner loop */
1004 x = (XDistance - Left) + 1;
1005 do
1006 {
1007 /* Read the current value */
1008 Value2 = READ_REGISTER_UCHAR(k);
1009
1010 /* Increase pixel position */
1011 k++;
1012
1013 /* Do the blt */
1014 a = Value2 >> (UCHAR)RightDelta;
1015 a |= Value << (UCHAR)LeftDelta;
1016 b = lookup[a & 0xF];
1017 a >>= 4;
1018 b <<= 16;
1019 b |= lookup[a];
1020
1021 /* Save new value to buffer */
1022 *m |= (b << Plane);
1023
1024 /* Move to next destination location */
1025 m++;
1026
1027 /* Write new value */
1028 Value = Value2;
1029 } while (--x);
1030 }
1031
1032 /* Update pixel position */
1033 PixelPosition += 80;
1034 i += Delta;
1035 } while (--y);
1036 }
1037 } while (++Plane < 4);
1038 }
1039
1040 /*
1041 * @implemented
1042 */
1043 VOID
1044 NTAPI
1045 VidSolidColorFill(IN ULONG Left,
1046 IN ULONG Top,
1047 IN ULONG Right,
1048 IN ULONG Bottom,
1049 IN UCHAR Color)
1050 {
1051 ULONG rMask, lMask;
1052 ULONG LeftOffset, RightOffset, Distance;
1053 PUCHAR Offset;
1054 ULONG i, j;
1055
1056 /* Get the left and right masks, shifts, and delta */
1057 LeftOffset = Left >> 3;
1058 lMask = (lMaskTable[Left & 0x7] << 8) | 8;
1059 RightOffset = Right >> 3;
1060 rMask = (rMaskTable[Right & 0x7] << 8) | 8;
1061 Distance = RightOffset - LeftOffset;
1062
1063 /* If there is no distance, then combine the right and left masks */
1064 if (!Distance) lMask &= rMask;
1065
1066 /* Switch to mode 10 */
1067 ReadWriteMode(10);
1068
1069 /* Clear the 4 planes (we're already in unchained mode here) */
1070 __outpw(0x3C4, 0xF02);
1071
1072 /* Select the color don't care register */
1073 __outpw(0x3CE, 7);
1074
1075 /* Calculate pixel position for the read */
1076 Offset = VgaBase + (Top * 80) + (PUCHAR)(ULONG_PTR)LeftOffset;
1077
1078 /* Select the bitmask register and write the mask */
1079 __outpw(0x3CE, (USHORT)lMask);
1080
1081 /* Check if the top coord is below the bottom one */
1082 if (Top <= Bottom)
1083 {
1084 /* Start looping each line */
1085 i = (Bottom - Top) + 1;
1086 do
1087 {
1088 /* Read the previous value and add our color */
1089 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color);
1090
1091 /* Move to the next line */
1092 Offset += 80;
1093 } while (--i);
1094 }
1095
1096 /* Check if we have a delta */
1097 if (Distance)
1098 {
1099 /* Calculate new pixel position */
1100 Offset = VgaBase + (Top * 80) + (PUCHAR)(ULONG_PTR)RightOffset;
1101 Distance--;
1102
1103 /* Select the bitmask register and write the mask */
1104 __outpw(0x3CE, (USHORT)rMask);
1105
1106 /* Check if the top coord is below the bottom one */
1107 if (Top <= Bottom)
1108 {
1109 /* Start looping each line */
1110 i = (Bottom - Top) + 1;
1111 do
1112 {
1113 /* Read the previous value and add our color */
1114 WRITE_REGISTER_UCHAR(Offset,
1115 READ_REGISTER_UCHAR(Offset) & Color);
1116
1117 /* Move to the next line */
1118 Offset += 80;
1119 } while (--i);
1120 }
1121
1122 /* Check if we still have a delta */
1123 if (Distance)
1124 {
1125 /* Calculate new pixel position */
1126 Offset = VgaBase + (Top * 80) + (PUCHAR)(ULONG_PTR)(LeftOffset + 1);
1127
1128 /* Set the bitmask to 0xFF for all 4 planes */
1129 __outpw(0x3CE, 0xFF08);
1130
1131 /* Check if the top coord is below the bottom one */
1132 if (Top <= Bottom)
1133 {
1134 /* Start looping each line */
1135 i = (Bottom - Top) + 1;
1136 do
1137 {
1138 /* Loop the shift delta */
1139 if (Distance > 0)
1140 {
1141 for (j = Distance; j; Offset++, j--)
1142 {
1143 /* Write the color */
1144 WRITE_REGISTER_UCHAR(Offset, Color);
1145 }
1146 }
1147
1148 /* Update position in memory */
1149 Offset += (80 - Distance);
1150 } while (--i);
1151 }
1152 }
1153 }
1154 }