1 /*- 2 * Copyright (c) 1991-1997 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <signal.h> 34 #include <sys/fbio.h> 35 #include "vgl.h" 36 37 #define min(x, y) (((x) < (y)) ? (x) : (y)) 38 39 static byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; 40 static int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101, 41 0x00010000, 0x00010001, 0x00010100, 0x00010101, 42 0x01000000, 0x01000001, 0x01000100, 0x01000101, 43 0x01010000, 0x01010001, 0x01010100, 0x01010101}; 44 45 static void 46 WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line) 47 { 48 int i, pos, last, planepos, start_offset, end_offset, offset; 49 int len; 50 unsigned int word = 0; 51 byte *address; 52 byte *VGLPlane[4]; 53 54 switch (dst->Type) { 55 case VIDBUF4: 56 case VIDBUF4S: 57 start_offset = (x & 0x07); 58 end_offset = (x + width) & 0x07; 59 i = (width + start_offset) / 8; 60 if (end_offset) 61 i++; 62 VGLPlane[0] = VGLBuf; 63 VGLPlane[1] = VGLPlane[0] + i; 64 VGLPlane[2] = VGLPlane[1] + i; 65 VGLPlane[3] = VGLPlane[2] + i; 66 pos = 0; 67 planepos = 0; 68 last = 8 - start_offset; 69 while (pos < width) { 70 word = 0; 71 while (pos < last && pos < width) 72 word = (word<<1) | color2bit[line[pos++]&0x0f]; 73 VGLPlane[0][planepos] = word; 74 VGLPlane[1][planepos] = word>>8; 75 VGLPlane[2][planepos] = word>>16; 76 VGLPlane[3][planepos] = word>>24; 77 planepos++; 78 last += 8; 79 } 80 planepos--; 81 if (end_offset) { 82 word <<= (8 - end_offset); 83 VGLPlane[0][planepos] = word; 84 VGLPlane[1][planepos] = word>>8; 85 VGLPlane[2][planepos] = word>>16; 86 VGLPlane[3][planepos] = word>>24; 87 } 88 if (start_offset || end_offset) 89 width+=8; 90 width /= 8; 91 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 92 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 93 for (i=0; i<4; i++) { 94 outb(0x3c4, 0x02); 95 outb(0x3c5, 0x01<<i); 96 outb(0x3ce, 0x04); 97 outb(0x3cf, i); 98 pos = VGLAdpInfo.va_line_width*y + x/8; 99 if (dst->Type == VIDBUF4) { 100 if (end_offset) 101 VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset]; 102 if (start_offset) 103 VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset]; 104 bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width); 105 } else { /* VIDBUF4S */ 106 if (end_offset) { 107 offset = VGLSetSegment(pos + planepos); 108 VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset]; 109 } 110 offset = VGLSetSegment(pos); 111 if (start_offset) 112 VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset]; 113 for (last = width; ; ) { 114 len = min(VGLAdpInfo.va_window_size - offset, last); 115 bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len); 116 pos += len; 117 last -= len; 118 if (last <= 0) 119 break; 120 offset = VGLSetSegment(pos); 121 } 122 } 123 } 124 break; 125 case VIDBUF8X: 126 address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4; 127 for (i=0; i<4; i++) { 128 outb(0x3c4, 0x02); 129 outb(0x3c5, 0x01 << ((x + i)%4)); 130 for (planepos=0, pos=i; pos<width; planepos++, pos+=4) 131 address[planepos] = line[pos]; 132 if ((x + i)%4 == 3) 133 ++address; 134 } 135 break; 136 case VIDBUF8S: 137 pos = dst->VXsize * y + x; 138 while (width > 0) { 139 offset = VGLSetSegment(pos); 140 i = min(VGLAdpInfo.va_window_size - offset, width); 141 bcopy(line, dst->Bitmap + offset, i); 142 line += i; 143 pos += i; 144 width -= i; 145 } 146 break; 147 case VIDBUF16S: 148 case VIDBUF24S: 149 case VIDBUF32S: 150 width = width * dst->PixelBytes; 151 pos = (dst->VXsize * y + x) * dst->PixelBytes; 152 while (width > 0) { 153 offset = VGLSetSegment(pos); 154 i = min(VGLAdpInfo.va_window_size - offset, width); 155 bcopy(line, dst->Bitmap + offset, i); 156 line += i; 157 pos += i; 158 width -= i; 159 } 160 break; 161 case VIDBUF8: 162 case MEMBUF: 163 address = dst->Bitmap + dst->VXsize * y + x; 164 bcopy(line, address, width); 165 break; 166 case VIDBUF16: 167 case VIDBUF24: 168 case VIDBUF32: 169 address = dst->Bitmap + (dst->VXsize * y + x) * dst->PixelBytes; 170 bcopy(line, address, width * dst->PixelBytes); 171 break; 172 default: 173 } 174 } 175 176 static void 177 ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line) 178 { 179 int i, bit, pos, count, planepos, start_offset, end_offset, offset; 180 int width2, len; 181 byte *address; 182 byte *VGLPlane[4]; 183 184 switch (src->Type) { 185 case VIDBUF4S: 186 start_offset = (x & 0x07); 187 end_offset = (x + width) & 0x07; 188 count = (width + start_offset) / 8; 189 if (end_offset) 190 count++; 191 VGLPlane[0] = VGLBuf; 192 VGLPlane[1] = VGLPlane[0] + count; 193 VGLPlane[2] = VGLPlane[1] + count; 194 VGLPlane[3] = VGLPlane[2] + count; 195 for (i=0; i<4; i++) { 196 outb(0x3ce, 0x04); 197 outb(0x3cf, i); 198 pos = VGLAdpInfo.va_line_width*y + x/8; 199 for (width2 = count; width2 > 0; ) { 200 offset = VGLSetSegment(pos); 201 len = min(VGLAdpInfo.va_window_size - offset, width2); 202 bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len); 203 pos += len; 204 width2 -= len; 205 } 206 } 207 goto read_planar; 208 case VIDBUF4: 209 address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8; 210 start_offset = (x & 0x07); 211 end_offset = (x + width) & 0x07; 212 count = (width + start_offset) / 8; 213 if (end_offset) 214 count++; 215 VGLPlane[0] = VGLBuf; 216 VGLPlane[1] = VGLPlane[0] + count; 217 VGLPlane[2] = VGLPlane[1] + count; 218 VGLPlane[3] = VGLPlane[2] + count; 219 for (i=0; i<4; i++) { 220 outb(0x3ce, 0x04); 221 outb(0x3cf, i); 222 bcopy(address, &VGLPlane[i][0], count); 223 } 224 read_planar: 225 pos = 0; 226 planepos = 0; 227 bit = 7 - start_offset; 228 while (pos < width) { 229 for (; bit >= 0 && pos < width; bit--, pos++) { 230 line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) | 231 ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) | 232 ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) | 233 ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3); 234 } 235 planepos++; 236 bit = 7; 237 } 238 break; 239 case VIDBUF8X: 240 address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4; 241 for (i=0; i<4; i++) { 242 outb(0x3ce, 0x04); 243 outb(0x3cf, (x + i)%4); 244 for (planepos=0, pos=i; pos<width; planepos++, pos+=4) 245 line[pos] = address[planepos]; 246 if ((x + i)%4 == 3) 247 ++address; 248 } 249 break; 250 case VIDBUF8S: 251 pos = src->VXsize * y + x; 252 while (width > 0) { 253 offset = VGLSetSegment(pos); 254 i = min(VGLAdpInfo.va_window_size - offset, width); 255 bcopy(src->Bitmap + offset, line, i); 256 line += i; 257 pos += i; 258 width -= i; 259 } 260 break; 261 case VIDBUF16S: 262 case VIDBUF24S: 263 case VIDBUF32S: 264 width = width * src->PixelBytes; 265 pos = (src->VXsize * y + x) * src->PixelBytes; 266 while (width > 0) { 267 offset = VGLSetSegment(pos); 268 i = min(VGLAdpInfo.va_window_size - offset, width); 269 bcopy(src->Bitmap + offset, line, i); 270 line += i; 271 pos += i; 272 width -= i; 273 } 274 break; 275 case VIDBUF8: 276 case MEMBUF: 277 address = src->Bitmap + src->VXsize * y + x; 278 bcopy(address, line, width); 279 break; 280 case VIDBUF16: 281 case VIDBUF24: 282 case VIDBUF32: 283 address = src->Bitmap + (src->VXsize * y + x) * src->PixelBytes; 284 bcopy(address, line, width * src->PixelBytes); 285 break; 286 default: 287 } 288 } 289 290 int 291 __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, 292 VGLBitmap *dst, int dstx, int dsty, int width, int hight) 293 { 294 int srcline, dstline; 295 296 if (srcx>src->VXsize || srcy>src->VYsize 297 || dstx>dst->VXsize || dsty>dst->VYsize) 298 return -1; 299 if (srcx < 0) { 300 width=width+srcx; dstx-=srcx; srcx=0; 301 } 302 if (srcy < 0) { 303 hight=hight+srcy; dsty-=srcy; srcy=0; 304 } 305 if (dstx < 0) { 306 width=width+dstx; srcx-=dstx; dstx=0; 307 } 308 if (dsty < 0) { 309 hight=hight+dsty; srcy-=dsty; dsty=0; 310 } 311 if (srcx+width > src->VXsize) 312 width=src->VXsize-srcx; 313 if (srcy+hight > src->VYsize) 314 hight=src->VYsize-srcy; 315 if (dstx+width > dst->VXsize) 316 width=dst->VXsize-dstx; 317 if (dsty+hight > dst->VYsize) 318 hight=dst->VYsize-dsty; 319 if (width < 0 || hight < 0) 320 return -1; 321 if (src->Type == MEMBUF) { 322 for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) { 323 WriteVerticalLine(dst, dstx, dstline, width, 324 (src->Bitmap+(srcline*src->VXsize)+srcx)); 325 } 326 } 327 else if (dst->Type == MEMBUF) { 328 for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) { 329 ReadVerticalLine(src, srcx, srcline, width, 330 (dst->Bitmap+(dstline*dst->VXsize)+dstx)); 331 } 332 } 333 else { 334 byte buffer[2048]; /* XXX */ 335 byte *p; 336 337 if (width > sizeof(buffer)) { 338 p = malloc(width); 339 if (p == NULL) 340 return 1; 341 } else { 342 p = buffer; 343 } 344 for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) { 345 ReadVerticalLine(src, srcx, srcline, width, p); 346 WriteVerticalLine(dst, dstx, dstline, width, p); 347 } 348 if (width > sizeof(buffer)) 349 free(p); 350 } 351 return 0; 352 } 353 354 int 355 VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, 356 VGLBitmap *dst, int dstx, int dsty, int width, int hight) 357 { 358 int error; 359 360 VGLMouseFreeze(dstx, dsty, width, hight, 0); 361 error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight); 362 VGLMouseUnFreeze(); 363 return error; 364 } 365 366 VGLBitmap 367 *VGLBitmapCreate(int type, int xsize, int ysize, byte *bits) 368 { 369 VGLBitmap *object; 370 371 if (type != MEMBUF) 372 return NULL; 373 if (xsize < 0 || ysize < 0) 374 return NULL; 375 object = (VGLBitmap *)malloc(sizeof(*object)); 376 if (object == NULL) 377 return NULL; 378 object->Type = type; 379 object->Xsize = xsize; 380 object->Ysize = ysize; 381 object->VXsize = xsize; 382 object->VYsize = ysize; 383 object->Xorigin = 0; 384 object->Yorigin = 0; 385 object->Bitmap = bits; 386 return object; 387 } 388 389 void 390 VGLBitmapDestroy(VGLBitmap *object) 391 { 392 if (object->Bitmap) 393 free(object->Bitmap); 394 free(object); 395 } 396 397 int 398 VGLBitmapAllocateBits(VGLBitmap *object) 399 { 400 object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize); 401 if (object->Bitmap == NULL) 402 return -1; 403 return 0; 404 } 405