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