1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991-1997 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <signal.h> 35 #include <sys/fbio.h> 36 #include <sys/endian.h> 37 #include "vgl.h" 38 39 static byte VGLSavePaletteRed[256]; 40 static byte VGLSavePaletteGreen[256]; 41 static byte VGLSavePaletteBlue[256]; 42 43 #define ABS(a) (((a)<0) ? -(a) : (a)) 44 #define SGN(a) (((a)<0) ? -1 : 1) 45 #define min(x, y) (((x) < (y)) ? (x) : (y)) 46 #define max(x, y) (((x) > (y)) ? (x) : (y)) 47 48 void 49 VGLSetXY(VGLBitmap *object, int x, int y, u_long color) 50 { 51 int offset; 52 53 VGLCheckSwitch(); 54 if (x>=0 && x<object->VXsize && y>=0 && y<object->VYsize) { 55 if (object->Type == MEMBUF || 56 !VGLMouseFreeze(x, y, 1, 1, 0x80000000 | color)) { 57 offset = (y * object->VXsize + x) * object->PixelBytes; 58 switch (object->Type) { 59 case VIDBUF8S: 60 case VIDBUF16S: 61 case VIDBUF24S: 62 case VIDBUF32S: 63 offset = VGLSetSegment(offset); 64 /* FALLTHROUGH */ 65 case MEMBUF: 66 case VIDBUF8: 67 case VIDBUF16: 68 case VIDBUF24: 69 case VIDBUF32: 70 color = htole32(color); 71 switch (object->PixelBytes) { 72 case 1: 73 memcpy(&object->Bitmap[offset], &color, 1); 74 break; 75 case 2: 76 memcpy(&object->Bitmap[offset], &color, 2); 77 break; 78 case 3: 79 memcpy(&object->Bitmap[offset], &color, 3); 80 break; 81 case 4: 82 memcpy(&object->Bitmap[offset], &color, 4); 83 break; 84 } 85 break; 86 case VIDBUF8X: 87 outb(0x3c4, 0x02); 88 outb(0x3c5, 0x01 << (x&0x3)); 89 object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)] = ((byte)color); 90 break; 91 case VIDBUF4S: 92 offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8); 93 goto set_planar; 94 case VIDBUF4: 95 offset = y*VGLAdpInfo.va_line_width + x/8; 96 set_planar: 97 outb(0x3c4, 0x02); outb(0x3c5, 0x0f); 98 outb(0x3ce, 0x00); outb(0x3cf, (byte)color & 0x0f); /* set/reset */ 99 outb(0x3ce, 0x01); outb(0x3cf, 0x0f); /* set/reset enable */ 100 outb(0x3ce, 0x08); outb(0x3cf, 0x80 >> (x%8)); /* bit mask */ 101 object->Bitmap[offset] |= (byte)color; 102 } 103 } 104 if (object->Type != MEMBUF) 105 VGLMouseUnFreeze(); 106 } 107 } 108 109 static u_long 110 __VGLGetXY(VGLBitmap *object, int x, int y) 111 { 112 int offset; 113 int i; 114 u_long color; 115 byte mask; 116 117 offset = (y * object->VXsize + x) * object->PixelBytes; 118 switch (object->Type) { 119 case VIDBUF8S: 120 case VIDBUF16S: 121 case VIDBUF24S: 122 case VIDBUF32S: 123 offset = VGLSetSegment(offset); 124 /* FALLTHROUGH */ 125 case MEMBUF: 126 case VIDBUF8: 127 case VIDBUF16: 128 case VIDBUF24: 129 case VIDBUF32: 130 switch (object->PixelBytes) { 131 case 1: 132 memcpy(&color, &object->Bitmap[offset], 1); 133 return le32toh(color) & 0xff; 134 case 2: 135 memcpy(&color, &object->Bitmap[offset], 2); 136 return le32toh(color) & 0xffff; 137 case 3: 138 memcpy(&color, &object->Bitmap[offset], 3); 139 return le32toh(color) & 0xffffff; 140 case 4: 141 memcpy(&color, &object->Bitmap[offset], 4); 142 return le32toh(color); 143 } 144 break; 145 case VIDBUF8X: 146 outb(0x3ce, 0x04); outb(0x3cf, x & 0x3); 147 return object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)]; 148 case VIDBUF4S: 149 offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8); 150 goto get_planar; 151 case VIDBUF4: 152 offset = y*VGLAdpInfo.va_line_width + x/8; 153 get_planar: 154 color = 0; 155 mask = 0x80 >> (x%8); 156 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 157 outb(0x3ce, 0x04); outb(0x3cf, i); 158 color |= (((volatile VGLBitmap *)object)->Bitmap[offset] & mask) ? 159 (1 << i) : 0; 160 } 161 return color; 162 } 163 return 0; /* XXX black? */ 164 } 165 166 u_long 167 VGLGetXY(VGLBitmap *object, int x, int y) 168 { 169 u_long color; 170 171 VGLCheckSwitch(); 172 if (x<0 || x>=object->VXsize || y<0 || y>=object->VYsize) 173 return 0; 174 if (object->Type != MEMBUF) { 175 color = VGLMouseFreeze(x, y, 1, 1, 0x40000000); 176 if (color & 0x40000000) { 177 VGLMouseUnFreeze(); 178 return color & 0xffffff; 179 } 180 } 181 color = __VGLGetXY(object, x, y); 182 if (object->Type != MEMBUF) 183 VGLMouseUnFreeze(); 184 return color; 185 } 186 187 /* 188 * Symmetric Double Step Line Algorithm by Brian Wyvill from 189 * "Graphics Gems", Academic Press, 1990. 190 */ 191 192 #define SL_SWAP(a,b) {a^=b; b^=a; a^=b;} 193 #define SL_ABSOLUTE(i,j,k) ( (i-j)*(k = ( (i-j)<0 ? -1 : 1))) 194 195 void 196 plot(VGLBitmap * object, int x, int y, int flag, u_long color) 197 { 198 /* non-zero flag indicates the pixels need swapping back. */ 199 if (flag) 200 VGLSetXY(object, y, x, color); 201 else 202 VGLSetXY(object, x, y, color); 203 } 204 205 206 void 207 VGLLine(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color) 208 { 209 int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left; 210 int sign_x, sign_y, step, reverse, i; 211 212 dx = SL_ABSOLUTE(x2, x1, sign_x); 213 dy = SL_ABSOLUTE(y2, y1, sign_y); 214 /* decide increment sign by the slope sign */ 215 if (sign_x == sign_y) 216 step = 1; 217 else 218 step = -1; 219 220 if (dy > dx) { /* chooses axis of greatest movement (make dx) */ 221 SL_SWAP(x1, y1); 222 SL_SWAP(x2, y2); 223 SL_SWAP(dx, dy); 224 reverse = 1; 225 } else 226 reverse = 0; 227 /* note error check for dx==0 should be included here */ 228 if (x1 > x2) { /* start from the smaller coordinate */ 229 x = x2; 230 y = y2; 231 /* x1 = x1; 232 y1 = y1; */ 233 } else { 234 x = x1; 235 y = y1; 236 x1 = x2; 237 y1 = y2; 238 } 239 240 241 /* Note dx=n implies 0 - n or (dx+1) pixels to be set */ 242 /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */ 243 /* In fact (dx-1)/4 as 2 pixels are already plotted */ 244 xend = (dx - 1) / 4; 245 pixels_left = (dx - 1) % 4; /* number of pixels left over at the 246 * end */ 247 plot(object, x, y, reverse, color); 248 if (pixels_left < 0) 249 return; /* plot only one pixel for zero length 250 * vectors */ 251 plot(object, x1, y1, reverse, color); /* plot first two points */ 252 incr2 = 4 * dy - 2 * dx; 253 if (incr2 < 0) { /* slope less than 1/2 */ 254 c = 2 * dy; 255 incr1 = 2 * c; 256 D = incr1 - dx; 257 258 for (i = 0; i < xend; i++) { /* plotting loop */ 259 ++x; 260 --x1; 261 if (D < 0) { 262 /* pattern 1 forwards */ 263 plot(object, x, y, reverse, color); 264 plot(object, ++x, y, reverse, color); 265 /* pattern 1 backwards */ 266 plot(object, x1, y1, reverse, color); 267 plot(object, --x1, y1, reverse, color); 268 D += incr1; 269 } else { 270 if (D < c) { 271 /* pattern 2 forwards */ 272 plot(object, x, y, reverse, color); 273 plot(object, ++x, y += step, reverse, 274 color); 275 /* pattern 2 backwards */ 276 plot(object, x1, y1, reverse, color); 277 plot(object, --x1, y1 -= step, reverse, 278 color); 279 } else { 280 /* pattern 3 forwards */ 281 plot(object, x, y += step, reverse, color); 282 plot(object, ++x, y, reverse, color); 283 /* pattern 3 backwards */ 284 plot(object, x1, y1 -= step, reverse, 285 color); 286 plot(object, --x1, y1, reverse, color); 287 } 288 D += incr2; 289 } 290 } /* end for */ 291 292 /* plot last pattern */ 293 if (pixels_left) { 294 if (D < 0) { 295 plot(object, ++x, y, reverse, color); /* pattern 1 */ 296 if (pixels_left > 1) 297 plot(object, ++x, y, reverse, color); 298 if (pixels_left > 2) 299 plot(object, --x1, y1, reverse, color); 300 } else { 301 if (D < c) { 302 plot(object, ++x, y, reverse, color); /* pattern 2 */ 303 if (pixels_left > 1) 304 plot(object, ++x, y += step, reverse, color); 305 if (pixels_left > 2) 306 plot(object, --x1, y1, reverse, color); 307 } else { 308 /* pattern 3 */ 309 plot(object, ++x, y += step, reverse, color); 310 if (pixels_left > 1) 311 plot(object, ++x, y, reverse, color); 312 if (pixels_left > 2) 313 plot(object, --x1, y1 -= step, reverse, color); 314 } 315 } 316 } /* end if pixels_left */ 317 } 318 /* end slope < 1/2 */ 319 else { /* slope greater than 1/2 */ 320 c = 2 * (dy - dx); 321 incr1 = 2 * c; 322 D = incr1 + dx; 323 for (i = 0; i < xend; i++) { 324 ++x; 325 --x1; 326 if (D > 0) { 327 /* pattern 4 forwards */ 328 plot(object, x, y += step, reverse, color); 329 plot(object, ++x, y += step, reverse, color); 330 /* pattern 4 backwards */ 331 plot(object, x1, y1 -= step, reverse, color); 332 plot(object, --x1, y1 -= step, reverse, color); 333 D += incr1; 334 } else { 335 if (D < c) { 336 /* pattern 2 forwards */ 337 plot(object, x, y, reverse, color); 338 plot(object, ++x, y += step, reverse, 339 color); 340 341 /* pattern 2 backwards */ 342 plot(object, x1, y1, reverse, color); 343 plot(object, --x1, y1 -= step, reverse, 344 color); 345 } else { 346 /* pattern 3 forwards */ 347 plot(object, x, y += step, reverse, color); 348 plot(object, ++x, y, reverse, color); 349 /* pattern 3 backwards */ 350 plot(object, x1, y1 -= step, reverse, color); 351 plot(object, --x1, y1, reverse, color); 352 } 353 D += incr2; 354 } 355 } /* end for */ 356 /* plot last pattern */ 357 if (pixels_left) { 358 if (D > 0) { 359 plot(object, ++x, y += step, reverse, color); /* pattern 4 */ 360 if (pixels_left > 1) 361 plot(object, ++x, y += step, reverse, 362 color); 363 if (pixels_left > 2) 364 plot(object, --x1, y1 -= step, reverse, 365 color); 366 } else { 367 if (D < c) { 368 plot(object, ++x, y, reverse, color); /* pattern 2 */ 369 if (pixels_left > 1) 370 plot(object, ++x, y += step, reverse, color); 371 if (pixels_left > 2) 372 plot(object, --x1, y1, reverse, color); 373 } else { 374 /* pattern 3 */ 375 plot(object, ++x, y += step, reverse, color); 376 if (pixels_left > 1) 377 plot(object, ++x, y, reverse, color); 378 if (pixels_left > 2) { 379 if (D > c) /* step 3 */ 380 plot(object, --x1, y1 -= step, reverse, color); 381 else /* step 2 */ 382 plot(object, --x1, y1, reverse, color); 383 } 384 } 385 } 386 } 387 } 388 } 389 390 void 391 VGLBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color) 392 { 393 VGLLine(object, x1, y1, x2, y1, color); 394 VGLLine(object, x2, y1, x2, y2, color); 395 VGLLine(object, x2, y2, x1, y2, color); 396 VGLLine(object, x1, y2, x1, y1, color); 397 } 398 399 void 400 VGLFilledBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color) 401 { 402 int y; 403 404 for (y=y1; y<=y2; y++) VGLLine(object, x1, y, x2, y, color); 405 } 406 407 static inline void 408 set4pixels(VGLBitmap *object, int x, int y, int xc, int yc, u_long color) 409 { 410 if (x!=0) { 411 VGLSetXY(object, xc+x, yc+y, color); 412 VGLSetXY(object, xc-x, yc+y, color); 413 if (y!=0) { 414 VGLSetXY(object, xc+x, yc-y, color); 415 VGLSetXY(object, xc-x, yc-y, color); 416 } 417 } 418 else { 419 VGLSetXY(object, xc, yc+y, color); 420 if (y!=0) 421 VGLSetXY(object, xc, yc-y, color); 422 } 423 } 424 425 void 426 VGLEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color) 427 { 428 int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b; 429 int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b; 430 431 while (dx<dy) { 432 set4pixels(object, x, y, xc, yc, color); 433 if (d>0) { 434 y--; dy-=asq2; d-=dy; 435 } 436 x++; dx+=bsq2; d+=bsq+dx; 437 } 438 d+=(3*(asq-bsq)/2-(dx+dy))/2; 439 while (y>=0) { 440 set4pixels(object, x, y, xc, yc, color); 441 if (d<0) { 442 x++; dx+=bsq2; d+=dx; 443 } 444 y--; dy-=asq2; d+=asq-dy; 445 } 446 } 447 448 static inline void 449 set2lines(VGLBitmap *object, int x, int y, int xc, int yc, u_long color) 450 { 451 if (x!=0) { 452 VGLLine(object, xc+x, yc+y, xc-x, yc+y, color); 453 if (y!=0) 454 VGLLine(object, xc+x, yc-y, xc-x, yc-y, color); 455 } 456 else { 457 VGLLine(object, xc, yc+y, xc, yc-y, color); 458 } 459 } 460 461 void 462 VGLFilledEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color) 463 { 464 int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b; 465 int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b; 466 467 while (dx<dy) { 468 set2lines(object, x, y, xc, yc, color); 469 if (d>0) { 470 y--; dy-=asq2; d-=dy; 471 } 472 x++; dx+=bsq2; d+=bsq+dx; 473 } 474 d+=(3*(asq-bsq)/2-(dx+dy))/2; 475 while (y>=0) { 476 set2lines(object, x, y, xc, yc, color); 477 if (d<0) { 478 x++; dx+=bsq2; d+=dx; 479 } 480 y--; dy-=asq2; d+=asq-dy; 481 } 482 } 483 484 void 485 VGLClear(VGLBitmap *object, u_long color) 486 { 487 VGLBitmap src; 488 int offset; 489 int len; 490 int i; 491 492 VGLCheckSwitch(); 493 if (object->Type != MEMBUF) 494 VGLMouseFreeze(0, 0, object->Xsize, object->Ysize, color); 495 switch (object->Type) { 496 case MEMBUF: 497 case VIDBUF8: 498 case VIDBUF8S: 499 case VIDBUF16: 500 case VIDBUF16S: 501 case VIDBUF24: 502 case VIDBUF24S: 503 case VIDBUF32: 504 case VIDBUF32S: 505 src.Type = MEMBUF; 506 src.Xsize = object->Xsize; 507 src.VXsize = object->VXsize; 508 src.Ysize = 1; 509 src.VYsize = 1; 510 src.Xorigin = 0; 511 src.Yorigin = 0; 512 src.Bitmap = alloca(object->VXsize * object->PixelBytes); 513 src.PixelBytes = object->PixelBytes; 514 color = htole32(color); 515 for (i = 0; i < object->VXsize; i++) 516 bcopy(&color, src.Bitmap + i * object->PixelBytes, object->PixelBytes); 517 for (i = 0; i < object->VYsize; i++) 518 __VGLBitmapCopy(&src, 0, 0, object, 0, i, object->VXsize, 1); 519 break; 520 521 case VIDBUF8X: 522 /* XXX works only for Xsize % 4 = 0 */ 523 outb(0x3c6, 0xff); 524 outb(0x3c4, 0x02); outb(0x3c5, 0x0f); 525 memset(object->Bitmap, (byte)color, VGLAdpInfo.va_line_width*object->VYsize); 526 break; 527 528 case VIDBUF4: 529 case VIDBUF4S: 530 /* XXX works only for Xsize % 8 = 0 */ 531 outb(0x3c4, 0x02); outb(0x3c5, 0x0f); 532 outb(0x3ce, 0x05); outb(0x3cf, 0x02); /* mode 2 */ 533 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 534 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 535 for (offset = 0; offset < VGLAdpInfo.va_line_width*object->VYsize; ) { 536 VGLSetSegment(offset); 537 len = min(object->VXsize*object->VYsize - offset, 538 VGLAdpInfo.va_window_size); 539 memset(object->Bitmap, (byte)color, len); 540 offset += len; 541 } 542 outb(0x3ce, 0x05); outb(0x3cf, 0x00); 543 break; 544 } 545 if (object->Type != MEMBUF) 546 VGLMouseUnFreeze(); 547 } 548 549 void 550 VGLRestorePalette() 551 { 552 int i; 553 554 outb(0x3C6, 0xFF); 555 inb(0x3DA); 556 outb(0x3C8, 0x00); 557 for (i=0; i<256; i++) { 558 outb(0x3C9, VGLSavePaletteRed[i]); 559 inb(0x84); 560 outb(0x3C9, VGLSavePaletteGreen[i]); 561 inb(0x84); 562 outb(0x3C9, VGLSavePaletteBlue[i]); 563 inb(0x84); 564 } 565 inb(0x3DA); 566 outb(0x3C0, 0x20); 567 } 568 569 void 570 VGLSavePalette() 571 { 572 int i; 573 574 outb(0x3C6, 0xFF); 575 inb(0x3DA); 576 outb(0x3C7, 0x00); 577 for (i=0; i<256; i++) { 578 VGLSavePaletteRed[i] = inb(0x3C9); 579 inb(0x84); 580 VGLSavePaletteGreen[i] = inb(0x3C9); 581 inb(0x84); 582 VGLSavePaletteBlue[i] = inb(0x3C9); 583 inb(0x84); 584 } 585 inb(0x3DA); 586 outb(0x3C0, 0x20); 587 } 588 589 void 590 VGLSetPalette(byte *red, byte *green, byte *blue) 591 { 592 int i; 593 594 for (i=0; i<256; i++) { 595 VGLSavePaletteRed[i] = red[i]; 596 VGLSavePaletteGreen[i] = green[i]; 597 VGLSavePaletteBlue[i] = blue[i]; 598 } 599 VGLCheckSwitch(); 600 outb(0x3C6, 0xFF); 601 inb(0x3DA); 602 outb(0x3C8, 0x00); 603 for (i=0; i<256; i++) { 604 outb(0x3C9, VGLSavePaletteRed[i]); 605 inb(0x84); 606 outb(0x3C9, VGLSavePaletteGreen[i]); 607 inb(0x84); 608 outb(0x3C9, VGLSavePaletteBlue[i]); 609 inb(0x84); 610 } 611 inb(0x3DA); 612 outb(0x3C0, 0x20); 613 } 614 615 void 616 VGLSetPaletteIndex(byte color, byte red, byte green, byte blue) 617 { 618 VGLSavePaletteRed[color] = red; 619 VGLSavePaletteGreen[color] = green; 620 VGLSavePaletteBlue[color] = blue; 621 VGLCheckSwitch(); 622 outb(0x3C6, 0xFF); 623 inb(0x3DA); 624 outb(0x3C8, color); 625 outb(0x3C9, red); outb(0x3C9, green); outb(0x3C9, blue); 626 inb(0x3DA); 627 outb(0x3C0, 0x20); 628 } 629 630 void 631 VGLSetBorder(byte color) 632 { 633 VGLCheckSwitch(); 634 inb(0x3DA); 635 outb(0x3C0,0x11); outb(0x3C0, color); 636 inb(0x3DA); 637 outb(0x3C0, 0x20); 638 } 639 640 void 641 VGLBlankDisplay(int blank) 642 { 643 byte val; 644 645 VGLCheckSwitch(); 646 outb(0x3C4, 0x01); val = inb(0x3C5); outb(0x3C4, 0x01); 647 outb(0x3C5, ((blank) ? (val |= 0x20) : (val &= 0xDF))); 648 } 649