3efed459d5824b5bff71b5ef9781a121b90aa894
[reactos.git] / reactos / drivers / base / bootvid / i386 / vga.c
1 #include "precomp.h"
2
3 /* GLOBALS *******************************************************************/
4
5 static ULONG ScrollRegion[4] =
6 {
7 0,
8 0,
9 640 - 1,
10 480 - 1
11 };
12 static 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 static 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 static 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_PTR VgaRegisterBase = 0;
67 ULONG_PTR VgaBase = 0;
68 ULONG curr_x = 0;
69 ULONG curr_y = 0;
70 static ULONG VidTextColor = 0xF;
71 static BOOLEAN CarriageReturn = FALSE;
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 static VOID
82 NTAPI
83 ReadWriteMode(IN 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 FORCEINLINE
98 VOID
99 SetPixel(IN ULONG Left,
100 IN ULONG Top,
101 IN UCHAR Color)
102 {
103 PUCHAR PixelPosition;
104
105 /* Calculate the pixel position. */
106 PixelPosition = (PUCHAR)(VgaBase + (Left >> 3) + (Top * 80));
107
108 /* Select the bitmask register and write the mask */
109 __outpw(0x3CE, (PixelMask[Left & 7] << 8) | 8);
110
111 /* Read the current pixel value and add our color */
112 WRITE_REGISTER_UCHAR(PixelPosition,
113 READ_REGISTER_UCHAR(PixelPosition) & Color);
114 }
115
116 #define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \
117 do { \
118 /* Select the bitmask register and write the mask */ \
119 __outpw(0x3CE, ((_PixelMask) << 8) | 8); \
120 /* Set the new color */ \
121 WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \
122 } while (0);
123
124 #ifdef CHAR_GEN_UPSIDE_DOWN
125 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
126 # define FONT_PTR_DELTA (-1)
127 #else
128 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT];
129 # define FONT_PTR_DELTA (1)
130 #endif
131
132 static VOID
133 NTAPI
134 DisplayCharacter(IN CHAR Character,
135 IN ULONG Left,
136 IN ULONG Top,
137 IN ULONG TextColor,
138 IN 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 static VOID
234 NTAPI
235 DisplayStringXY(IN PUCHAR String,
236 IN ULONG Left,
237 IN ULONG Top,
238 IN ULONG TextColor,
239 IN 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 static 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 static 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 static 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] = {0x000000,
304 0x000020,
305 0x002000,
306 0x002020,
307 0x200000,
308 0x200020,
309 0x202000,
310 0x202020,
311 0x303030,
312 0x00003F,
313 0x003F00,
314 0x003F3F,
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 static VOID
326 NTAPI
327 VgaScroll(IN 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 static 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 loop every pixel */
397 Count = TopDelta * 80;
398
399 #if defined(_M_IX86) || defined(_M_AMD64)
400 __movsb(Position1, Position2, Count);
401 #else
402 while (Count--)
403 {
404 /* Write the data back on the other position */
405 WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2));
406
407 /* Increase both positions */
408 Position1++;
409 Position2++;
410 }
411 #endif
412 }
413
414 static VOID
415 NTAPI
416 BitBlt(IN ULONG Left,
417 IN ULONG Top,
418 IN ULONG Width,
419 IN ULONG Height,
420 IN PUCHAR Buffer,
421 IN ULONG BitsPerPixel,
422 IN ULONG Delta)
423 {
424 ULONG sx, dx, dy;
425 UCHAR color;
426 ULONG offset = 0;
427 const ULONG Bottom = Top + Height;
428 const ULONG Right = Left + Width;
429
430 /* Check if the buffer isn't 4bpp */
431 if (BitsPerPixel != 4)
432 {
433 /* FIXME: TODO */
434 DbgPrint("Unhandled BitBlt\n"
435 "%lux%lu @ (%lu|%lu)\n"
436 "Bits Per Pixel %lu\n"
437 "Buffer: %p. Delta: %lu\n",
438 Width,
439 Height,
440 Left,
441 Top,
442 BitsPerPixel,
443 Buffer,
444 Delta);
445 return;
446 }
447
448 /* Switch to mode 10 */
449 ReadWriteMode(10);
450
451 /* Clear the 4 planes (we're already in unchained mode here) */
452 __outpw(0x3C4, 0xF02);
453
454 /* Select the color don't care register */
455 __outpw(0x3CE, 7);
456
457 /* 4bpp blitting */
458 dy = Top;
459 do
460 {
461 sx = 0;
462 do
463 {
464 /* Extract color */
465 color = Buffer[offset + sx];
466
467 /* Calc destination x */
468 dx = Left + (sx << 1);
469
470 /* Set two pixels */
471 SetPixel(dx, dy, color >> 4);
472 SetPixel(dx + 1, dy, color & 0x0F);
473
474 sx++;
475 } while (dx < Right);
476 offset += Delta;
477 dy++;
478 } while (dy < Bottom);
479 }
480
481 static VOID
482 NTAPI
483 RleBitBlt(IN ULONG Left,
484 IN ULONG Top,
485 IN ULONG Width,
486 IN ULONG Height,
487 IN PUCHAR Buffer)
488 {
489 ULONG YDelta;
490 ULONG x;
491 ULONG RleValue, NewRleValue;
492 ULONG Color, Color2;
493 ULONG i, j;
494 ULONG Code;
495
496 /* Switch to mode 10 */
497 ReadWriteMode(10);
498
499 /* Clear the 4 planes (we're already in unchained mode here) */
500 __outpw(0x3C4, 0xF02);
501
502 /* Select the color don't care register */
503 __outpw(0x3CE, 7);
504
505 /* Set Y height and current X value and start loop */
506 YDelta = Top + Height - 1;
507 x = Left;
508 for (;;)
509 {
510 /* Get the current value and advance in the buffer */
511 RleValue = *Buffer;
512 Buffer++;
513 if (RleValue)
514 {
515 /* Check if we've gone past the edge */
516 if ((x + RleValue) > (Width + Left))
517 {
518 /* Fixeup the pixel value */
519 RleValue = Left - x + Width;
520 }
521
522 /* Get the new value */
523 NewRleValue = *Buffer;
524
525 /* Get the two colors */
526 Color = NewRleValue >> 4;
527 Color2 = NewRleValue & 0xF;
528
529 /* Increase buffer positition */
530 Buffer++;
531
532 /* Check if we need to do a fill */
533 if (Color == Color2)
534 {
535 /* Do a fill and continue the loop */
536 RleValue += x;
537 VidSolidColorFill(x, YDelta, RleValue - 1, YDelta, (UCHAR)Color);
538 x = RleValue;
539 continue;
540 }
541
542 /* Check if the pixel value is 1 or below */
543 if (RleValue > 1)
544 {
545 /* Set loop variables */
546 i = (RleValue - 2) / 2 + 1;
547 do
548 {
549 /* Set the pixels */
550 SetPixel(x, YDelta, (UCHAR)Color);
551 x++;
552 SetPixel(x, YDelta, (UCHAR)Color2);
553 x++;
554
555 /* Decrease pixel value */
556 RleValue -= 2;
557 } while (--i);
558 }
559
560 /* Check if there is any value at all */
561 if (RleValue)
562 {
563 /* Set the pixel and increase posititon */
564 SetPixel(x, YDelta, (UCHAR)Color);
565 x++;
566 }
567
568 /* Start over */
569 continue;
570 }
571
572 /* Get the current pixel value */
573 RleValue = *Buffer;
574 Code = RleValue;
575 switch (Code)
576 {
577 /* Case 0 */
578 case 0:
579 {
580 /* Set new x value, decrease distance and restart */
581 x = Left;
582 YDelta--;
583 Buffer++;
584 continue;
585 }
586
587 /* Case 1 */
588 case 1:
589 {
590 /* Done */
591 return;
592 }
593
594 /* Case 2 */
595 case 2:
596 {
597 /* Set new x value, decrease distance and restart */
598 Buffer++;
599 x += *Buffer;
600 Buffer++;
601 YDelta -= *Buffer;
602 Buffer++;
603 continue;
604 }
605
606 /* Other values */
607 default:
608 {
609 Buffer++;
610 break;
611 }
612 }
613
614 /* Check if we've gone past the edge */
615 if ((x + RleValue) > (Width + Left))
616 {
617 /* Set fixed up loop count */
618 i = RleValue - Left - Width + x;
619
620 /* Fixup pixel value */
621 RleValue -= i;
622 }
623 else
624 {
625 /* Clear loop count */
626 i = 0;
627 }
628
629 /* Check the value now */
630 if (RleValue > 1)
631 {
632 /* Set loop variables */
633 j = (RleValue - 2) / 2 + 1;
634 do
635 {
636 /* Get the new value */
637 NewRleValue = *Buffer;
638
639 /* Get the two colors */
640 Color = NewRleValue >> 4;
641 Color2 = NewRleValue & 0xF;
642
643 /* Increase buffer position */
644 Buffer++;
645
646 /* Set the pixels */
647 SetPixel(x, YDelta, (UCHAR)Color);
648 x++;
649 SetPixel(x, YDelta, (UCHAR)Color2);
650 x++;
651
652 /* Decrease pixel value */
653 RleValue -= 2;
654 } while (--j);
655 }
656
657 /* Check if there is any value at all */
658 if (RleValue)
659 {
660 /* Set the pixel and increase position */
661 Color = *Buffer >> 4;
662 Buffer++;
663 SetPixel(x, YDelta, (UCHAR)Color);
664 x++;
665 i--;
666 }
667
668 /* Check loop count now */
669 if ((LONG)i > 0)
670 {
671 /* Decrease it */
672 i--;
673
674 /* Set new position */
675 Buffer = Buffer + (i / 2) + 1;
676 }
677
678 /* Check if we need to increase the buffer */
679 if ((ULONG_PTR)Buffer & 1) Buffer++;
680 }
681 }
682
683 /* PUBLIC FUNCTIONS **********************************************************/
684
685 /*
686 * @implemented
687 */
688 ULONG
689 NTAPI
690 VidSetTextColor(IN ULONG Color)
691 {
692 ULONG OldColor;
693
694 /* Save the old color and set the new one */
695 OldColor = VidTextColor;
696 VidTextColor = Color;
697 return OldColor;
698 }
699
700 /*
701 * @implemented
702 */
703 VOID
704 NTAPI
705 VidDisplayStringXY(IN PUCHAR String,
706 IN ULONG Left,
707 IN ULONG Top,
708 IN BOOLEAN Transparent)
709 {
710 ULONG BackColor;
711
712 /*
713 * If the caller wanted transparent, then send the special value (16),
714 * else use our default and call the helper routine.
715 */
716 BackColor = Transparent ? 16 : 14;
717 DisplayStringXY(String, Left, Top, 12, BackColor);
718 }
719
720 /*
721 * @implemented
722 */
723 VOID
724 NTAPI
725 VidSetScrollRegion(IN ULONG Left,
726 IN ULONG Top,
727 IN ULONG Right,
728 IN ULONG Bottom)
729 {
730 /* Assert alignment */
731 ASSERT((Left & 0x7) == 0);
732 ASSERT((Right & 0x7) == 7);
733
734 /* Set Scroll Region */
735 ScrollRegion[0] = Left;
736 ScrollRegion[1] = Top;
737 ScrollRegion[2] = Right;
738 ScrollRegion[3] = Bottom;
739
740 /* Set current X and Y */
741 curr_x = Left;
742 curr_y = Top;
743 }
744
745 /*
746 * @implemented
747 */
748 VOID
749 NTAPI
750 VidCleanUp(VOID)
751 {
752 /* Select bit mask register */
753 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
754
755 /* Clear it */
756 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 255);
757 }
758
759 /*
760 * @implemented
761 */
762 VOID
763 NTAPI
764 VidBufferToScreenBlt(IN PUCHAR Buffer,
765 IN ULONG Left,
766 IN ULONG Top,
767 IN ULONG Width,
768 IN ULONG Height,
769 IN ULONG Delta)
770 {
771 /* Make sure we have a width and height */
772 if (!Width || !Height) return;
773
774 /* Call the helper function */
775 BitBlt(Left, Top, Width, Height, Buffer, 4, Delta);
776 }
777
778 /*
779 * @implemented
780 */
781 VOID
782 NTAPI
783 VidDisplayString(IN PUCHAR String)
784 {
785 ULONG TopDelta = BOOTCHAR_HEIGHT + 1;
786
787 /* Start looping the string */
788 while (*String)
789 {
790 /* Treat new-line separately */
791 if (*String == '\n')
792 {
793 /* Modify Y position */
794 curr_y += TopDelta;
795 if (curr_y + TopDelta >= ScrollRegion[3])
796 {
797 /* Scroll the view */
798 VgaScroll(TopDelta);
799 curr_y -= TopDelta;
800 }
801 else
802 {
803 /* Preserve row */
804 PreserveRow(curr_y, TopDelta, FALSE);
805 }
806
807 /* Update current X */
808 curr_x = ScrollRegion[0];
809
810 /* Do not clear line if "\r\n" is given */
811 CarriageReturn = FALSE;
812 }
813 else if (*String == '\r')
814 {
815 /* Update current X */
816 curr_x = ScrollRegion[0];
817
818 /* Check if we're being followed by a new line */
819 CarriageReturn = TRUE;
820 }
821 else
822 {
823 /* check if we had a '\r' last time */
824 if (CarriageReturn)
825 {
826 /* We did, clear the current row */
827 PreserveRow(curr_y, TopDelta, TRUE);
828 CarriageReturn = FALSE;
829 }
830
831 /* Display this character */
832 DisplayCharacter(*String, curr_x, curr_y, VidTextColor, 16);
833 curr_x += 8;
834
835 /* Check if we should scroll */
836 if (curr_x + 8 > ScrollRegion[2])
837 {
838 /* Update Y position and check if we should scroll it */
839 curr_y += TopDelta;
840 if (curr_y + TopDelta > ScrollRegion[3])
841 {
842 /* Do the scroll */
843 VgaScroll(TopDelta);
844 curr_y -= TopDelta;
845 }
846 else
847 {
848 /* Preserve the current row */
849 PreserveRow(curr_y, TopDelta, FALSE);
850 }
851
852 /* Update X */
853 curr_x = ScrollRegion[0];
854 }
855 }
856
857 /* Get the next character */
858 String++;
859 }
860 }
861
862 /*
863 * @implemented
864 */
865 VOID
866 NTAPI
867 VidBitBlt(IN PUCHAR Buffer,
868 IN ULONG Left,
869 IN ULONG Top)
870 {
871 PBITMAPINFOHEADER BitmapInfoHeader;
872 LONG Delta;
873 PUCHAR BitmapOffset;
874
875 /* Get the Bitmap Header */
876 BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer;
877
878 /* Initialize the palette */
879 InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize),
880 (BitmapInfoHeader->biClrUsed) ?
881 BitmapInfoHeader->biClrUsed : 16);
882
883 /* Make sure we can support this bitmap */
884 ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4);
885
886 /*
887 * Calculate the delta and align it on 32-bytes, then calculate
888 * the actual start of the bitmap data.
889 */
890 Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31;
891 Delta >>= 3;
892 Delta &= ~3;
893 BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + 16 * sizeof(ULONG);
894
895 /* Check the compression of the bitmap */
896 if (BitmapInfoHeader->biCompression == BI_RLE4)
897 {
898 /* Make sure we have a width and a height */
899 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
900 {
901 /* We can use RLE Bit Blt */
902 RleBitBlt(Left,
903 Top,
904 BitmapInfoHeader->biWidth,
905 BitmapInfoHeader->biHeight,
906 BitmapOffset);
907 }
908 }
909 else
910 {
911 /* Check if the height is negative */
912 if (BitmapInfoHeader->biHeight < 0)
913 {
914 /* Make it positive in the header */
915 BitmapInfoHeader->biHeight *= -1;
916 }
917 else
918 {
919 /* Update buffer offset */
920 BitmapOffset += ((BitmapInfoHeader->biHeight - 1) * Delta);
921 Delta *= -1;
922 }
923
924 /* Make sure we have a width and a height */
925 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
926 {
927 /* Do the BitBlt */
928 BitBlt(Left,
929 Top,
930 BitmapInfoHeader->biWidth,
931 BitmapInfoHeader->biHeight,
932 BitmapOffset,
933 BitmapInfoHeader->biBitCount,
934 Delta);
935 }
936 }
937 }
938
939 /*
940 * @implemented
941 */
942 VOID
943 NTAPI
944 VidScreenToBufferBlt(IN PUCHAR Buffer,
945 IN ULONG Left,
946 IN ULONG Top,
947 IN ULONG Width,
948 IN ULONG Height,
949 IN ULONG Delta)
950 {
951 ULONG Plane;
952 ULONG XDistance;
953 ULONG LeftDelta, RightDelta;
954 ULONG PixelOffset;
955 PUCHAR PixelPosition;
956 PUCHAR k, i;
957 PULONG m;
958 UCHAR Value, Value2;
959 UCHAR a;
960 ULONG b;
961 ULONG x, y;
962
963 /* Calculate total distance to copy on X */
964 XDistance = Left + Width - 1;
965
966 /* Start at plane 0 */
967 Plane = 0;
968
969 /* Calculate the 8-byte left and right deltas */
970 LeftDelta = Left & 7;
971 RightDelta = 8 - LeftDelta;
972
973 /* Clear the destination buffer */
974 RtlZeroMemory(Buffer, Delta * Height);
975
976 /* Calculate the pixel offset and convert the X distance into byte form */
977 PixelOffset = Top * 80 + (Left >> 3);
978 XDistance >>= 3;
979
980 /* Loop the 4 planes */
981 do
982 {
983 /* Set the current pixel position and reset buffer loop variable */
984 PixelPosition = (PUCHAR)(VgaBase + PixelOffset);
985 i = Buffer;
986
987 /* Set Mode 0 */
988 ReadWriteMode(0);
989
990 /* Set the current plane */
991 __outpw(0x3CE, (Plane << 8) | 4);
992
993 /* Make sure we have a height */
994 if (Height > 0)
995 {
996 /* Start the outer Y loop */
997 y = Height;
998 do
999 {
1000 /* Read the current value */
1001 m = (PULONG)i;
1002 Value = READ_REGISTER_UCHAR(PixelPosition);
1003
1004 /* Set Pixel Position loop variable */
1005 k = PixelPosition + 1;
1006
1007 /* Check if we're still within bounds */
1008 if (Left <= XDistance)
1009 {
1010 /* Start X Inner loop */
1011 x = (XDistance - Left) + 1;
1012 do
1013 {
1014 /* Read the current value */
1015 Value2 = READ_REGISTER_UCHAR(k);
1016
1017 /* Increase pixel position */
1018 k++;
1019
1020 /* Do the blt */
1021 a = Value2 >> (UCHAR)RightDelta;
1022 a |= Value << (UCHAR)LeftDelta;
1023 b = lookup[a & 0xF];
1024 a >>= 4;
1025 b <<= 16;
1026 b |= lookup[a];
1027
1028 /* Save new value to buffer */
1029 *m |= (b << Plane);
1030
1031 /* Move to next destination location */
1032 m++;
1033
1034 /* Write new value */
1035 Value = Value2;
1036 } while (--x);
1037 }
1038
1039 /* Update pixel position */
1040 PixelPosition += 80;
1041 i += Delta;
1042 } while (--y);
1043 }
1044 } while (++Plane < 4);
1045 }
1046
1047 /*
1048 * @implemented
1049 */
1050 VOID
1051 NTAPI
1052 VidSolidColorFill(IN ULONG Left,
1053 IN ULONG Top,
1054 IN ULONG Right,
1055 IN ULONG Bottom,
1056 IN UCHAR Color)
1057 {
1058 ULONG rMask, lMask;
1059 ULONG LeftOffset, RightOffset, Distance;
1060 PUCHAR Offset;
1061 ULONG i, j;
1062
1063 /* Get the left and right masks, shifts, and delta */
1064 LeftOffset = Left >> 3;
1065 lMask = (lMaskTable[Left & 0x7] << 8) | 8;
1066 RightOffset = Right >> 3;
1067 rMask = (rMaskTable[Right & 0x7] << 8) | 8;
1068 Distance = RightOffset - LeftOffset;
1069
1070 /* If there is no distance, then combine the right and left masks */
1071 if (!Distance) lMask &= rMask;
1072
1073 /* Switch to mode 10 */
1074 ReadWriteMode(10);
1075
1076 /* Clear the 4 planes (we're already in unchained mode here) */
1077 __outpw(0x3C4, 0xF02);
1078
1079 /* Select the color don't care register */
1080 __outpw(0x3CE, 7);
1081
1082 /* Calculate pixel position for the read */
1083 Offset = (PUCHAR)(VgaBase + (Top * 80) + LeftOffset);
1084
1085 /* Select the bitmask register and write the mask */
1086 __outpw(0x3CE, (USHORT)lMask);
1087
1088 /* Check if the top coord is below the bottom one */
1089 if (Top <= Bottom)
1090 {
1091 /* Start looping each line */
1092 i = (Bottom - Top) + 1;
1093 do
1094 {
1095 /* Read the previous value and add our color */
1096 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color);
1097
1098 /* Move to the next line */
1099 Offset += 80;
1100 } while (--i);
1101 }
1102
1103 /* Check if we have a delta */
1104 if (Distance)
1105 {
1106 /* Calculate new pixel position */
1107 Offset = (PUCHAR)(VgaBase + (Top * 80) + RightOffset);
1108 Distance--;
1109
1110 /* Select the bitmask register and write the mask */
1111 __outpw(0x3CE, (USHORT)rMask);
1112
1113 /* Check if the top coord is below the bottom one */
1114 if (Top <= Bottom)
1115 {
1116 /* Start looping each line */
1117 i = (Bottom - Top) + 1;
1118 do
1119 {
1120 /* Read the previous value and add our color */
1121 WRITE_REGISTER_UCHAR(Offset,
1122 READ_REGISTER_UCHAR(Offset) & Color);
1123
1124 /* Move to the next line */
1125 Offset += 80;
1126 } while (--i);
1127 }
1128
1129 /* Check if we still have a delta */
1130 if (Distance)
1131 {
1132 /* Calculate new pixel position */
1133 Offset = (PUCHAR)(VgaBase + (Top * 80) + LeftOffset + 1);
1134
1135 /* Set the bitmask to 0xFF for all 4 planes */
1136 __outpw(0x3CE, 0xFF08);
1137
1138 /* Check if the top coord is below the bottom one */
1139 if (Top <= Bottom)
1140 {
1141 /* Start looping each line */
1142 i = (Bottom - Top) + 1;
1143 do
1144 {
1145 /* Loop the shift delta */
1146 if (Distance > 0)
1147 {
1148 for (j = Distance; j; Offset++, j--)
1149 {
1150 /* Write the color */
1151 WRITE_REGISTER_UCHAR(Offset, Color);
1152 }
1153 }
1154
1155 /* Update position in memory */
1156 Offset += (80 - Distance);
1157 } while (--i);
1158 }
1159 }
1160 }
1161 }