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