sync with trunk r46493
[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 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 LeftAnd, LeftShifted, LeftPlusOne, LeftPos;
406 ULONG lMask, rMask;
407 UCHAR NotlMask;
408 ULONG Distance;
409 ULONG DistanceMinusLeftBpp;
410 ULONG SomeYesNoFlag, SomeYesNoFlag2;
411 PUCHAR PixelPosition, m;
412 PUCHAR i, k;
413 ULONG j;
414 ULONG x;
415 ULONG Plane;
416 UCHAR LeftArray[84];
417 PUCHAR CurrentLeft;
418 PUCHAR l;
419 ULONG LoopCount;
420 UCHAR pMask, PlaneShift;
421 BOOLEAN Odd;
422 UCHAR Value;
423
424 /* Check if the buffer isn't 4bpp */
425 if (BitsPerPixel != 4)
426 {
427 /* FIXME: TODO */
428 DbgPrint("Unhandled BitBlt\n"
429 "%lxx%lx @ (%lx,%lx)\n"
430 "Bits Per Pixel %lx\n"
431 "Buffer: %p. Delta: %lx\n",
432 Width,
433 Height,
434 Left,
435 Top,
436 BitsPerPixel,
437 Buffer,
438 Delta);
439 return;
440 }
441
442 /* Get the masks and other values */
443 LeftAnd = Left & 0x7;
444 lMask = lMaskTable[LeftAnd];
445 Distance = Width + Left;
446 rMask = rMaskTable[(Distance - 1) & 0x7];
447 Left >>= 3;
448
449 /* Set some values */
450 SomeYesNoFlag = FALSE;
451 SomeYesNoFlag2 = FALSE;
452 Distance = (Distance - 1) >> 3;
453 DistanceMinusLeftBpp = Distance - Left;
454
455 /* Check if the distance is equal to the left position and add the masks */
456 if (Left == Distance) lMask += rMask;
457
458 /* Check if there's no distance offset */
459 if (DistanceMinusLeftBpp)
460 {
461 /* Set the first flag on */
462 SomeYesNoFlag = TRUE;
463
464 /* Decrease offset and check if we still have one */
465 if (--DistanceMinusLeftBpp)
466 {
467 /* Still have a distance offset */
468 SomeYesNoFlag2 = TRUE;
469 }
470 }
471
472 /* Calculate initial pixel position */
473 PixelPosition = (PUCHAR)VgaBase + (Top * 80) + Left;
474
475 /* Set loop buffer variable */
476 i = Buffer;
477
478 /* Switch to mode 0 */
479 ReadWriteMode(0);
480
481 /* Leave now if the height is 0 */
482 if (Height <= 0) return;
483
484 /* Set more weird values */
485 CurrentLeft = &LeftArray[Left];
486 NotlMask = ~(UCHAR)lMask;
487 LeftPlusOne = Left + 1;
488 LeftShifted = (lMask << 8) | 8;
489 j = Height;
490
491 /* Start the height loop */
492 do
493 {
494 /* Start the plane loop */
495 Plane = 0;
496 do
497 {
498 /* Clear the current value */
499 *CurrentLeft = 0;
500 LoopCount = 0;
501
502 /* Set the buffer loop variable for this loop */
503 k = i;
504
505 /* Calculate plane shift and pixel mask */
506 PlaneShift = 1 << Plane;
507 pMask = PixelMask[LeftAnd];
508
509 /* Check if we have a width */
510 if (Width > 0)
511 {
512 /* Loop it */
513 l = CurrentLeft;
514 x = Width;
515 do
516 {
517 /* Check if we're odd and increase the loop count */
518 Odd = LoopCount & 1 ? TRUE : FALSE;
519 LoopCount++;
520 if (Odd)
521 {
522 /* Check for the plane shift */
523 if (*k & PlaneShift)
524 {
525 /* Write the pixel mask */
526 *l |= pMask;
527 }
528
529 /* Increase buffer position */
530 k++;
531 }
532 else
533 {
534 /* Check for plane shift */
535 if ((*k >> 4) & PlaneShift)
536 {
537 /* Write the pixel mask */
538 *l |= pMask;
539 }
540 }
541
542 /* Shift the pixel mask */
543 pMask >>= 1;
544 if (!pMask)
545 {
546 /* Move to the next current left position and clear it */
547 l++;
548 *l = 0;
549
550 /* Set the pixel mask to 0x80 */
551 pMask = 0x80;
552 }
553 } while (--x);
554 }
555
556 /* Set the plane value */
557 __outpw(0x3C4, (1 << (Plane + 8) | 2));
558
559 /* Select the bitmask register and write the mask */
560 __outpw(0x3CE, (USHORT)LeftShifted);
561
562 /* Read the current Pixel value */
563 Value = READ_REGISTER_UCHAR(PixelPosition);
564
565 /* Add our mask */
566 Value = (Value & NotlMask) | *CurrentLeft;
567
568 /* Set current left for the loop, and write new pixel value */
569 LeftPos = LeftPlusOne;
570 WRITE_REGISTER_UCHAR(PixelPosition, Value);
571
572 /* Set loop pixel position and check if we should loop */
573 m = PixelPosition + 1;
574 if (SomeYesNoFlag2)
575 {
576 /* Set the bitmask to 0xFF for all 4 planes */
577 __outpw(0x3CE, 0xFF08);
578
579 /* Check if we have any distance left */
580 if (DistanceMinusLeftBpp > 0)
581 {
582 /* Start looping it */
583 x = DistanceMinusLeftBpp;
584 do
585 {
586 /* Write the value */
587 WRITE_REGISTER_UCHAR(m, LeftArray[LeftPos]);
588
589 /* Go to the next position */
590 m++;
591 LeftPos++;
592 } while (--x);
593 }
594 }
595
596 /* Check if the first flag is on */
597 if (SomeYesNoFlag)
598 {
599 /* Set the mask value */
600 __outpw(0x3CE, (rMask << 8) | 8);
601
602 /* Read the current Pixel value */
603 Value = READ_REGISTER_UCHAR(m);
604
605 /* Add our mask */
606 Value = (Value & ~(UCHAR)rMask) | LeftArray[LeftPos];
607
608 /* Set current left for the loop, and write new pixel value */
609 WRITE_REGISTER_UCHAR(m, Value);
610 }
611 } while (++Plane < 4);
612
613 /* Update pixel position, buffer and height */
614 PixelPosition += 80;
615 i += Delta;
616 } while (--j);
617 }
618
619 VOID
620 NTAPI
621 RleBitBlt(IN ULONG Left,
622 IN ULONG Top,
623 IN ULONG Width,
624 IN ULONG Height,
625 IN PUCHAR Buffer)
626 {
627 ULONG YDelta;
628 ULONG x;
629 ULONG RleValue, NewRleValue;
630 ULONG Color, Color2;
631 ULONG i, j;
632 ULONG Code;
633
634 /* Set Y height and current X value and start loop */
635 YDelta = Top + Height - 1;
636 x = Left;
637 for (;;)
638 {
639 /* Get the current value and advance in the buffer */
640 RleValue = *Buffer;
641 Buffer++;
642 if (RleValue)
643 {
644 /* Check if we've gone past the edge */
645 if ((x + RleValue) > (Width + Left))
646 {
647 /* Fixeup the pixel value */
648 RleValue = Left - x + Width;
649 }
650
651 /* Get the new value */
652 NewRleValue = *Buffer;
653
654 /* Get the two colors */
655 Color = NewRleValue >> 4;
656 Color2 = NewRleValue & 0xF;
657
658 /* Increase buffer positition */
659 Buffer++;
660
661 /* Check if we need to do a fill */
662 if (Color == Color2)
663 {
664 /* Do a fill and continue the loop */
665 RleValue += x;
666 VidSolidColorFill(x, YDelta, RleValue - 1, YDelta, (UCHAR)Color);
667 x = RleValue;
668 continue;
669 }
670
671 /* Check if the pixel value is 1 or below */
672 if (RleValue > 1)
673 {
674 /* Set loop variables */
675 i = (RleValue - 2) / 2 + 1;
676 do
677 {
678 /* Set the pixels */
679 SetPixel(x, YDelta, (UCHAR)Color);
680 x++;
681 SetPixel(x, YDelta, (UCHAR)Color2);
682 x++;
683
684 /* Decrease pixel value */
685 RleValue -= 2;
686 } while (--i);
687 }
688
689 /* Check if there is any value at all */
690 if (RleValue)
691 {
692 /* Set the pixel and increase posititon */
693 SetPixel(x, YDelta, (UCHAR)Color);
694 x++;
695 }
696
697 /* Start over */
698 continue;
699 }
700
701 /* Get the current pixel value */
702 RleValue = *Buffer;
703 Code = RleValue;
704 switch (Code)
705 {
706 /* Case 0 */
707 case 0:
708
709 /* Set new x value, decrease distance and restart */
710 x = Left;
711 YDelta--;
712 Buffer++;
713 continue;
714
715 /* Case 1 */
716 case 1:
717
718 /* Done */
719 return;
720
721 /* Case 2 */
722 case 2:
723
724 /* Set new x value, decrease distance and restart */
725 Buffer++;
726 x += *Buffer;
727 Buffer++;
728 YDelta -= *Buffer;
729 Buffer++;
730 continue;
731
732 /* Other values */
733 default:
734
735 Buffer++;
736 break;
737 }
738
739 /* Check if we've gone past the edge */
740 if ((x + RleValue) > (Width + Left))
741 {
742 /* Set fixed up loop count */
743 i = RleValue - Left - Width + x;
744
745 /* Fixup pixel value */
746 RleValue -= i;
747 }
748 else
749 {
750 /* Clear loop count */
751 i = 0;
752 }
753
754 /* Check the value now */
755 if (RleValue > 1)
756 {
757 /* Set loop variables */
758 j = (RleValue - 2) / 2 + 1;
759 do
760 {
761 /* Get the new value */
762 NewRleValue = *Buffer;
763
764 /* Get the two colors */
765 Color = NewRleValue >> 4;
766 Color2 = NewRleValue & 0xF;
767
768 /* Increase buffer position */
769 Buffer++;
770
771 /* Set the pixels */
772 SetPixel(x, YDelta, (UCHAR)Color);
773 x++;
774 SetPixel(x, YDelta, (UCHAR)Color2);
775 x++;
776
777 /* Decrease pixel value */
778 RleValue -= 2;
779 } while (--j);
780 }
781
782 /* Check if there is any value at all */
783 if (RleValue)
784 {
785 /* Set the pixel and increase position */
786 Color = *Buffer >> 4;
787 Buffer++;
788 SetPixel(x, YDelta, (UCHAR)Color);
789 x++;
790 i--;
791 }
792
793 /* Check loop count now */
794 if ((LONG)i > 0)
795 {
796 /* Decrease it */
797 i--;
798
799 /* Set new position */
800 Buffer = Buffer + (i / 2) + 1;
801 }
802
803 /* Check if we need to increase the buffer */
804 if ((ULONG_PTR)Buffer & 1) Buffer++;
805 }
806 }
807
808 /* PUBLIC FUNCTIONS **********************************************************/
809
810 /*
811 * @implemented
812 */
813 ULONG
814 NTAPI
815 VidSetTextColor(ULONG Color)
816 {
817 ULONG OldColor;
818
819 /* Save the old color and set the new one */
820 OldColor = TextColor;
821 TextColor = Color;
822 return OldColor;
823 }
824
825 /*
826 * @implemented
827 */
828 VOID
829 NTAPI
830 VidDisplayStringXY(PUCHAR String,
831 ULONG Left,
832 ULONG Top,
833 BOOLEAN Transparent)
834 {
835 ULONG BackColor;
836
837 /* If the caller wanted transparent, then send the special value (16), else */
838 /* use our default and call the helper routine. */
839 BackColor = (Transparent) ? 16 : 14;
840 DisplayStringXY(String, Left, Top, 12, BackColor);
841 }
842
843 /*
844 * @implemented
845 */
846 VOID
847 NTAPI
848 VidSetScrollRegion(ULONG x1,
849 ULONG y1,
850 ULONG x2,
851 ULONG y2)
852 {
853 /* Assert alignment */
854 ASSERT((x1 & 0x7) == 0);
855 ASSERT((x2 & 0x7) == 7);
856
857 /* Set Scroll Region */
858 ScrollRegion[0] = x1;
859 ScrollRegion[1] = y1;
860 ScrollRegion[2] = x2;
861 ScrollRegion[3] = y2;
862
863 /* Set current X and Y */
864 curr_x = x1;
865 curr_y = y1;
866 }
867
868 /*
869 * @implemented
870 */
871 VOID
872 NTAPI
873 VidCleanUp(VOID)
874 {
875 /* Select bit mask register */
876 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
877
878 /* Clear it */
879 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 255);
880 }
881
882 /*
883 * @implemented
884 */
885 VOID
886 NTAPI
887 VidBufferToScreenBlt(IN PUCHAR Buffer,
888 IN ULONG Left,
889 IN ULONG Top,
890 IN ULONG Width,
891 IN ULONG Height,
892 IN ULONG Delta)
893 {
894 /* Make sure we have a width and height */
895 if (!(Width) || !(Height)) return;
896
897 /* Call the helper function */
898 BitBlt(Left, Top, Width, Height, Buffer, 4, Delta);
899 }
900
901 /*
902 * @implemented
903 */
904 VOID
905 NTAPI
906 VidDisplayString(PUCHAR String)
907 {
908 ULONG TopDelta = 14;
909
910 /* Start looping the string */
911 while (*String)
912 {
913 /* Treat new-line separately */
914 if (*String == '\n')
915 {
916 /* Modify Y position */
917 curr_y += TopDelta;
918 if (curr_y >= ScrollRegion[3])
919 {
920 /* Scroll the view */
921 VgaScroll(TopDelta);
922 curr_y -= TopDelta;
923
924 /* Preserve row */
925 PreserveRow(curr_y, TopDelta, TRUE);
926 }
927
928 /* Update current X */
929 curr_x = ScrollRegion[0];
930
931 /* Preseve the current row */
932 PreserveRow(curr_y, TopDelta, FALSE);
933 }
934 else if (*String == '\r')
935 {
936 /* Update current X */
937 curr_x = ScrollRegion[0];
938
939 /* Check if we're being followed by a new line */
940 if (String[1] != '\n') NextLine = TRUE;
941 }
942 else
943 {
944 /* Check if we had a \n\r last time */
945 if (NextLine)
946 {
947 /* We did, preserve the current row */
948 PreserveRow(curr_y, TopDelta, TRUE);
949 NextLine = FALSE;
950 }
951
952 /* Display this character */
953 DisplayCharacter(*String, curr_x, curr_y, TextColor, 16);
954 curr_x += 8;
955
956 /* Check if we should scroll */
957 if (curr_x > ScrollRegion[2])
958 {
959 /* Update Y position and check if we should scroll it */
960 curr_y += TopDelta;
961 if (curr_y > ScrollRegion[3])
962 {
963 /* Do the scroll */
964 VgaScroll(TopDelta);
965 curr_y -= TopDelta;
966
967 /* Save the row */
968 PreserveRow(curr_y, TopDelta, TRUE);
969 }
970
971 /* Update X */
972 curr_x = ScrollRegion[0];
973 }
974 }
975
976 /* Get the next character */
977 String++;
978 }
979 }
980
981 /*
982 * @implemented
983 */
984 VOID
985 NTAPI
986 VidBitBlt(PUCHAR Buffer,
987 ULONG Left,
988 ULONG Top)
989 {
990 PBITMAPINFOHEADER BitmapInfoHeader;
991 LONG Delta;
992 PUCHAR BitmapOffset;
993
994 /* Get the Bitmap Header */
995 BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer;
996
997 /* Initialize the palette */
998 InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize),
999 (BitmapInfoHeader->biClrUsed) ?
1000 BitmapInfoHeader->biClrUsed : 16);
1001
1002 /* Make sure we can support this bitmap */
1003 ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4);
1004
1005 /* Calculate the delta and align it on 32-bytes, then calculate the actual */
1006 /* start of the bitmap data. */
1007 Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31;
1008 Delta >>= 3;
1009 Delta &= ~3;
1010 BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + 16 * sizeof(ULONG);
1011
1012 /* Check the compression of the bitmap */
1013 if (BitmapInfoHeader->biCompression == 2)
1014 {
1015 /* Make sure we have a width and a height */
1016 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
1017 {
1018 /* We can use RLE Bit Blt */
1019 RleBitBlt(Left,
1020 Top,
1021 BitmapInfoHeader->biWidth,
1022 BitmapInfoHeader->biHeight,
1023 BitmapOffset);
1024 }
1025 }
1026 else
1027 {
1028 /* Check if the height is negative */
1029 if (BitmapInfoHeader->biHeight < 0)
1030 {
1031 /* Make it positive in the header */
1032 BitmapInfoHeader->biHeight *= -1;
1033 }
1034 else
1035 {
1036 /* Update buffer offset */
1037 BitmapOffset += ((BitmapInfoHeader->biHeight -1) * Delta);
1038 Delta *= -1;
1039 }
1040
1041 /* Make sure we have a width and a height */
1042 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
1043 {
1044 /* Do the BitBlt */
1045 BitBlt(Left,
1046 Top,
1047 BitmapInfoHeader->biWidth,
1048 BitmapInfoHeader->biHeight,
1049 BitmapOffset,
1050 BitmapInfoHeader->biBitCount,
1051 Delta);
1052 }
1053 }
1054 }
1055
1056 /*
1057 * @implemented
1058 */
1059 VOID
1060 NTAPI
1061 VidScreenToBufferBlt(PUCHAR Buffer,
1062 ULONG Left,
1063 ULONG Top,
1064 ULONG Width,
1065 ULONG Height,
1066 ULONG Delta)
1067 {
1068 ULONG Plane;
1069 ULONG XDistance;
1070 ULONG LeftDelta, RightDelta;
1071 ULONG PixelOffset;
1072 PUCHAR PixelPosition;
1073 PUCHAR k, i;
1074 PULONG m;
1075 UCHAR Value, Value2;
1076 UCHAR a;
1077 ULONG b;
1078 ULONG x, y;
1079
1080 /* Calculate total distance to copy on X */
1081 XDistance = Left + Width - 1;
1082
1083 /* Start at plane 0 */
1084 Plane = 0;
1085
1086 /* Calculate the 8-byte left and right deltas */
1087 LeftDelta = Left & 7;
1088 RightDelta = 8 - LeftDelta;
1089
1090 /* Clear the destination buffer */
1091 RtlZeroMemory(Buffer, Delta * Height);
1092
1093 /* Calculate the pixel offset and convert the X distance into byte form */
1094 PixelOffset = Top * 80 + (Left >> 3);
1095 XDistance >>= 3;
1096
1097 /* Loop the 4 planes */
1098 do
1099 {
1100 /* Set the current pixel position and reset buffer loop variable */
1101 PixelPosition = (PUCHAR)VgaBase + PixelOffset;
1102 i = Buffer;
1103
1104 /* Set Mode 0 */
1105 ReadWriteMode(0);
1106
1107 /* Set the current plane */
1108 __outpw(0x3CE, (Plane << 8) | 4);
1109
1110 /* Make sure we have a height */
1111 if (Height > 0)
1112 {
1113 /* Start the outer Y loop */
1114 y = Height;
1115 do
1116 {
1117 /* Read the current value */
1118 m = (PULONG)i;
1119 Value = READ_REGISTER_UCHAR(PixelPosition);
1120
1121 /* Set Pixel Position loop variable */
1122 k = PixelPosition + 1;
1123
1124 /* Check if we're still within bounds */
1125 if (Left <= XDistance)
1126 {
1127 /* Start X Inner loop */
1128 x = (XDistance - Left) + 1;
1129 do
1130 {
1131 /* Read the current value */
1132 Value2 = READ_REGISTER_UCHAR(k);
1133
1134 /* Increase pixel position */
1135 k++;
1136
1137 /* Do the blt */
1138 a = Value2 >> (UCHAR)RightDelta;
1139 a |= Value << (UCHAR)LeftDelta;
1140 b = lookup[a & 0xF];
1141 a >>= 4;
1142 b <<= 16;
1143 b |= lookup[a];
1144
1145 /* Save new value to buffer */
1146 *m |= (b << Plane);
1147
1148 /* Move to next destination location */
1149 m++;
1150
1151 /* Write new value */
1152 Value = Value2;
1153 } while (--x);
1154 }
1155
1156 /* Update pixel position */
1157 PixelPosition += 80;
1158 i += Delta;
1159 } while (--y);
1160 }
1161 } while (++Plane < 4);
1162 }
1163
1164 /*
1165 * @implemented
1166 */
1167 VOID
1168 NTAPI
1169 VidSolidColorFill(IN ULONG Left,
1170 IN ULONG Top,
1171 IN ULONG Right,
1172 IN ULONG Bottom,
1173 IN UCHAR Color)
1174 {
1175 ULONG rMask, lMask;
1176 ULONG LeftOffset, RightOffset, Distance;
1177 PUCHAR Offset;
1178 ULONG i, j;
1179
1180 /* Get the left and right masks, shifts, and delta */
1181 LeftOffset = Left >> 3;
1182 lMask = (lMaskTable[Left & 0x7] << 8) | 8;
1183 RightOffset = Right >> 3;
1184 rMask = (rMaskTable[Right & 0x7] << 8) | 8;
1185 Distance = RightOffset - LeftOffset;
1186
1187 /* If there is no distance, then combine the right and left masks */
1188 if (!Distance) lMask &= rMask;
1189
1190 /* Switch to mode 10 */
1191 ReadWriteMode(10);
1192
1193 /* Clear the 4 planes (we're already in unchained mode here) */
1194 __outpw(0x3C4, 0xF02);
1195
1196 /* Select the color don't care register */
1197 __outpw(0x3CE, 7);
1198
1199 /* Calculate pixel position for the read */
1200 Offset = VgaBase + (Top * 80) + (PUCHAR)(ULONG_PTR)LeftOffset;
1201
1202 /* Select the bitmask register and write the mask */
1203 __outpw(0x3CE, (USHORT)lMask);
1204
1205 /* Check if the top coord is below the bottom one */
1206 if (Top <= Bottom)
1207 {
1208 /* Start looping each line */
1209 i = (Bottom - Top) + 1;
1210 do
1211 {
1212 /* Read the previous value and add our color */
1213 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color);
1214
1215 /* Move to the next line */
1216 Offset += 80;
1217 } while (--i);
1218 }
1219
1220 /* Check if we have a delta */
1221 if (Distance)
1222 {
1223 /* Calculate new pixel position */
1224 Offset = VgaBase + (Top * 80) + (PUCHAR)(ULONG_PTR)RightOffset;
1225 Distance--;
1226
1227 /* Select the bitmask register and write the mask */
1228 __outpw(0x3CE, (USHORT)rMask);
1229
1230 /* Check if the top coord is below the bottom one */
1231 if (Top <= Bottom)
1232 {
1233 /* Start looping each line */
1234 i = (Bottom - Top) + 1;
1235 do
1236 {
1237 /* Read the previous value and add our color */
1238 WRITE_REGISTER_UCHAR(Offset,
1239 READ_REGISTER_UCHAR(Offset) & Color);
1240
1241 /* Move to the next line */
1242 Offset += 80;
1243 } while (--i);
1244 }
1245
1246 /* Check if we still have a delta */
1247 if (Distance)
1248 {
1249 /* Calculate new pixel position */
1250 Offset = VgaBase + (Top * 80) + (PUCHAR)(ULONG_PTR)(LeftOffset + 1);
1251
1252 /* Set the bitmask to 0xFF for all 4 planes */
1253 __outpw(0x3CE, 0xFF08);
1254
1255 /* Check if the top coord is below the bottom one */
1256 if (Top <= Bottom)
1257 {
1258 /* Start looping each line */
1259 i = (Bottom - Top) + 1;
1260 do
1261 {
1262 /* Loop the shift delta */
1263 if (Distance > 0)
1264 {
1265 for (j = Distance; j; Offset++, j--)
1266 {
1267 /* Write the color */
1268 WRITE_REGISTER_UCHAR(Offset, Color);
1269 }
1270 }
1271
1272 /* Update position in memory */
1273 Offset += (80 - Distance);
1274 } while (--i);
1275 }
1276 }
1277 }
1278 }
1279