1 #include "precomp.h" 2 3 /* GLOBALS ********************************************************************/ 4 5 UCHAR VidpTextColor = 0x0F; 6 7 ULONG VidpCurrentX = 0; 8 ULONG VidpCurrentY = 0; 9 10 ULONG VidpScrollRegion[4] = 11 { 12 0, 13 0, 14 SCREEN_WIDTH - 1, 15 SCREEN_HEIGHT - 1 16 }; 17 18 /* PRIVATE FUNCTIONS **********************************************************/ 19 20 static VOID 21 NTAPI 22 BitBlt( 23 _In_ ULONG Left, 24 _In_ ULONG Top, 25 _In_ ULONG Width, 26 _In_ ULONG Height, 27 _In_ PUCHAR Buffer, 28 _In_ ULONG BitsPerPixel, 29 _In_ ULONG Delta) 30 { 31 ULONG sx, dx, dy; 32 UCHAR color; 33 ULONG offset = 0; 34 const ULONG Bottom = Top + Height; 35 const ULONG Right = Left + Width; 36 37 /* Check if the buffer isn't 4bpp */ 38 if (BitsPerPixel != 4) 39 { 40 /* FIXME: TODO */ 41 DbgPrint("Unhandled BitBlt\n" 42 "%lux%lu @ (%lu|%lu)\n" 43 "Bits Per Pixel %lu\n" 44 "Buffer: %p. Delta: %lu\n", 45 Width, 46 Height, 47 Left, 48 Top, 49 BitsPerPixel, 50 Buffer, 51 Delta); 52 return; 53 } 54 55 PrepareForSetPixel(); 56 57 /* 4bpp blitting */ 58 for (dy = Top; dy < Bottom; ++dy) 59 { 60 sx = 0; 61 do 62 { 63 /* Extract color */ 64 color = Buffer[offset + sx]; 65 66 /* Calc destination x */ 67 dx = Left + (sx << 1); 68 69 /* Set two pixels */ 70 SetPixel(dx, dy, color >> 4); 71 SetPixel(dx + 1, dy, color & 0x0F); 72 73 sx++; 74 } while (dx < Right); 75 offset += Delta; 76 } 77 } 78 79 static VOID 80 NTAPI 81 RleBitBlt( 82 _In_ ULONG Left, 83 _In_ ULONG Top, 84 _In_ ULONG Width, 85 _In_ ULONG Height, 86 _In_ PUCHAR Buffer) 87 { 88 ULONG YDelta; 89 ULONG x; 90 ULONG RleValue, NewRleValue; 91 ULONG Color, Color2; 92 ULONG i, j; 93 ULONG Code; 94 95 PrepareForSetPixel(); 96 97 /* Set Y height and current X value and start loop */ 98 YDelta = Top + Height - 1; 99 x = Left; 100 for (;;) 101 { 102 /* Get the current value and advance in the buffer */ 103 RleValue = *Buffer; 104 Buffer++; 105 if (RleValue) 106 { 107 /* Check if we've gone past the edge */ 108 if ((x + RleValue) > (Width + Left)) 109 { 110 /* Fixup the pixel value */ 111 RleValue = Left - x + Width; 112 } 113 114 /* Get the new value */ 115 NewRleValue = *Buffer; 116 117 /* Get the two colors */ 118 Color = NewRleValue >> 4; 119 Color2 = NewRleValue & 0xF; 120 121 /* Increase buffer position */ 122 Buffer++; 123 124 /* Check if we need to do a fill */ 125 if (Color == Color2) 126 { 127 /* Do a fill and continue the loop */ 128 RleValue += x; 129 VidSolidColorFill(x, YDelta, RleValue - 1, YDelta, (UCHAR)Color); 130 x = RleValue; 131 continue; 132 } 133 134 /* Check if the pixel value is 1 or below */ 135 if (RleValue > 1) 136 { 137 /* Set loop variables */ 138 for (i = (RleValue - 2) / 2 + 1; i > 0; --i) 139 { 140 /* Set the pixels */ 141 SetPixel(x, YDelta, (UCHAR)Color); 142 x++; 143 SetPixel(x, YDelta, (UCHAR)Color2); 144 x++; 145 146 /* Decrease pixel value */ 147 RleValue -= 2; 148 } 149 } 150 151 /* Check if there is any value at all */ 152 if (RleValue) 153 { 154 /* Set the pixel and increase position */ 155 SetPixel(x, YDelta, (UCHAR)Color); 156 x++; 157 } 158 159 /* Start over */ 160 continue; 161 } 162 163 /* Get the current pixel value */ 164 RleValue = *Buffer; 165 Code = RleValue; 166 switch (Code) 167 { 168 /* Case 0 */ 169 case 0: 170 { 171 /* Set new x value, decrease distance and restart */ 172 x = Left; 173 YDelta--; 174 Buffer++; 175 continue; 176 } 177 178 /* Case 1 */ 179 case 1: 180 { 181 /* Done */ 182 return; 183 } 184 185 /* Case 2 */ 186 case 2: 187 { 188 /* Set new x value, decrease distance and restart */ 189 Buffer++; 190 x += *Buffer; 191 Buffer++; 192 YDelta -= *Buffer; 193 Buffer++; 194 continue; 195 } 196 197 /* Other values */ 198 default: 199 { 200 Buffer++; 201 break; 202 } 203 } 204 205 /* Check if we've gone past the edge */ 206 if ((x + RleValue) > (Width + Left)) 207 { 208 /* Set fixed up loop count */ 209 i = RleValue - Left - Width + x; 210 211 /* Fixup pixel value */ 212 RleValue -= i; 213 } 214 else 215 { 216 /* Clear loop count */ 217 i = 0; 218 } 219 220 /* Check the value now */ 221 if (RleValue > 1) 222 { 223 /* Set loop variables */ 224 for (j = (RleValue - 2) / 2 + 1; j > 0; --j) 225 { 226 /* Get the new value */ 227 NewRleValue = *Buffer; 228 229 /* Get the two colors */ 230 Color = NewRleValue >> 4; 231 Color2 = NewRleValue & 0xF; 232 233 /* Increase buffer position */ 234 Buffer++; 235 236 /* Set the pixels */ 237 SetPixel(x, YDelta, (UCHAR)Color); 238 x++; 239 SetPixel(x, YDelta, (UCHAR)Color2); 240 x++; 241 242 /* Decrease pixel value */ 243 RleValue -= 2; 244 } 245 } 246 247 /* Check if there is any value at all */ 248 if (RleValue) 249 { 250 /* Set the pixel and increase position */ 251 Color = *Buffer >> 4; 252 Buffer++; 253 SetPixel(x, YDelta, (UCHAR)Color); 254 x++; 255 i--; 256 } 257 258 /* Check loop count now */ 259 if ((LONG)i > 0) 260 { 261 /* Decrease it */ 262 i--; 263 264 /* Set new position */ 265 Buffer = Buffer + (i / 2) + 1; 266 } 267 268 /* Check if we need to increase the buffer */ 269 if ((ULONG_PTR)Buffer & 1) Buffer++; 270 } 271 } 272 273 /* PUBLIC FUNCTIONS ***********************************************************/ 274 275 VOID 276 NTAPI 277 VidDisplayStringXY( 278 _In_ PUCHAR String, 279 _In_ ULONG Left, 280 _In_ ULONG Top, 281 _In_ BOOLEAN Transparent) 282 { 283 ULONG BackColor; 284 285 /* 286 * If the caller wanted transparent, then send the special value (16), 287 * else use our default and call the helper routine. 288 */ 289 BackColor = Transparent ? 16 : 14; 290 291 /* Loop every character and adjust the position */ 292 for (; *String; ++String, Left += 8) 293 { 294 /* Display a character */ 295 DisplayCharacter(*String, Left, Top, 12, BackColor); 296 } 297 } 298 299 VOID 300 NTAPI 301 VidSetScrollRegion( 302 _In_ ULONG Left, 303 _In_ ULONG Top, 304 _In_ ULONG Right, 305 _In_ ULONG Bottom) 306 { 307 /* Assert alignment */ 308 ASSERT((Left & 0x7) == 0); 309 ASSERT((Right & 0x7) == 7); 310 311 /* Set Scroll Region */ 312 VidpScrollRegion[0] = Left; 313 VidpScrollRegion[1] = Top; 314 VidpScrollRegion[2] = Right; 315 VidpScrollRegion[3] = Bottom; 316 317 /* Set current X and Y */ 318 VidpCurrentX = Left; 319 VidpCurrentY = Top; 320 } 321 322 VOID 323 NTAPI 324 VidBufferToScreenBlt( 325 _In_ PUCHAR Buffer, 326 _In_ ULONG Left, 327 _In_ ULONG Top, 328 _In_ ULONG Width, 329 _In_ ULONG Height, 330 _In_ ULONG Delta) 331 { 332 /* Make sure we have a width and height */ 333 if (!Width || !Height) 334 return; 335 336 /* Call the helper function */ 337 BitBlt(Left, Top, Width, Height, Buffer, 4, Delta); 338 } 339 340 VOID 341 NTAPI 342 VidBitBlt( 343 _In_ PUCHAR Buffer, 344 _In_ ULONG Left, 345 _In_ ULONG Top) 346 { 347 PBITMAPINFOHEADER BitmapInfoHeader; 348 LONG Delta; 349 PUCHAR BitmapOffset; 350 351 /* Get the Bitmap Header */ 352 BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer; 353 354 /* Initialize the palette */ 355 InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize), 356 (BitmapInfoHeader->biClrUsed) ? 357 BitmapInfoHeader->biClrUsed : 16); 358 359 /* Make sure we can support this bitmap */ 360 ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4); 361 362 /* 363 * Calculate the delta and align it on 32-bytes, then calculate 364 * the actual start of the bitmap data. 365 */ 366 Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31; 367 Delta >>= 3; 368 Delta &= ~3; 369 BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + 16 * sizeof(ULONG); 370 371 /* Check the compression of the bitmap */ 372 if (BitmapInfoHeader->biCompression == BI_RLE4) 373 { 374 /* Make sure we have a width and a height */ 375 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight)) 376 { 377 /* We can use RLE Bit Blt */ 378 RleBitBlt(Left, 379 Top, 380 BitmapInfoHeader->biWidth, 381 BitmapInfoHeader->biHeight, 382 BitmapOffset); 383 } 384 } 385 else 386 { 387 /* Check if the height is negative */ 388 if (BitmapInfoHeader->biHeight < 0) 389 { 390 /* Make it positive in the header */ 391 BitmapInfoHeader->biHeight *= -1; 392 } 393 else 394 { 395 /* Update buffer offset */ 396 BitmapOffset += ((BitmapInfoHeader->biHeight - 1) * Delta); 397 Delta *= -1; 398 } 399 400 /* Make sure we have a width and a height */ 401 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight)) 402 { 403 /* Do the BitBlt */ 404 BitBlt(Left, 405 Top, 406 BitmapInfoHeader->biWidth, 407 BitmapInfoHeader->biHeight, 408 BitmapOffset, 409 BitmapInfoHeader->biBitCount, 410 Delta); 411 } 412 } 413 } 414