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 * $FreeBSD$ 29 */ 30 31 #include <sys/types.h> 32 #include <signal.h> 33 #include <sys/fbio.h> 34 #include "vgl.h" 35 36 #define min(x, y) (((x) < (y)) ? (x) : (y)) 37 38 static byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; 39 static int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101, 40 0x00010000, 0x00010001, 0x00010100, 0x00010101, 41 0x01000000, 0x01000001, 0x01000100, 0x01000101, 42 0x01010000, 0x01010001, 0x01010100, 0x01010101}; 43 44 static void 45 WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line) 46 { 47 int i, pos, last, planepos, start_offset, end_offset, offset; 48 int len; 49 unsigned int word = 0; 50 byte *address; 51 byte *VGLPlane[4]; 52 53 switch (dst->Type) { 54 case VIDBUF4: 55 case VIDBUF4S: 56 start_offset = (x & 0x07); 57 end_offset = (x + width) & 0x07; 58 i = (width + start_offset) / 8; 59 if (end_offset) 60 i++; 61 VGLPlane[0] = VGLBuf; 62 VGLPlane[1] = VGLPlane[0] + i; 63 VGLPlane[2] = VGLPlane[1] + i; 64 VGLPlane[3] = VGLPlane[2] + i; 65 pos = 0; 66 planepos = 0; 67 last = 8 - start_offset; 68 while (pos < width) { 69 word = 0; 70 while (pos < last && pos < width) 71 word = (word<<1) | color2bit[line[pos++]&0x0f]; 72 VGLPlane[0][planepos] = word; 73 VGLPlane[1][planepos] = word>>8; 74 VGLPlane[2][planepos] = word>>16; 75 VGLPlane[3][planepos] = word>>24; 76 planepos++; 77 last += 8; 78 } 79 planepos--; 80 if (end_offset) { 81 word <<= (8 - end_offset); 82 VGLPlane[0][planepos] = word; 83 VGLPlane[1][planepos] = word>>8; 84 VGLPlane[2][planepos] = word>>16; 85 VGLPlane[3][planepos] = word>>24; 86 } 87 if (start_offset || end_offset) 88 width+=8; 89 width /= 8; 90 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 91 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 92 for (i=0; i<4; i++) { 93 outb(0x3c4, 0x02); 94 outb(0x3c5, 0x01<<i); 95 outb(0x3ce, 0x04); 96 outb(0x3cf, i); 97 pos = VGLAdpInfo.va_line_width*y + x/8; 98 if (dst->Type == VIDBUF4) { 99 if (end_offset) 100 VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset]; 101 if (start_offset) 102 VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset]; 103 bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width); 104 } else { /* VIDBUF4S */ 105 if (end_offset) { 106 offset = VGLSetSegment(pos + planepos); 107 VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset]; 108 } 109 offset = VGLSetSegment(pos); 110 if (start_offset) 111 VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset]; 112 for (last = width; ; ) { 113 len = min(VGLAdpInfo.va_window_size - offset, last); 114 bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len); 115 pos += len; 116 last -= len; 117 if (last <= 0) 118 break; 119 offset = VGLSetSegment(pos); 120 } 121 } 122 } 123 break; 124 case VIDBUF8X: 125 address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4; 126 for (i=0; i<4; i++) { 127 outb(0x3c4, 0x02); 128 outb(0x3c5, 0x01 << ((x + i)%4)); 129 for (planepos=0, pos=i; pos<width; planepos++, pos+=4) 130 address[planepos] = line[pos]; 131 if ((x + i)%4 == 3) 132 ++address; 133 } 134 break; 135 case VIDBUF8S: 136 pos = dst->VXsize * y + x; 137 while (width > 0) { 138 offset = VGLSetSegment(pos); 139 i = min(VGLAdpInfo.va_window_size - offset, width); 140 bcopy(line, dst->Bitmap + offset, i); 141 line += i; 142 pos += i; 143 width -= i; 144 } 145 break; 146 case VIDBUF16S: 147 case VIDBUF24S: 148 case VIDBUF32S: 149 width = width * dst->PixelBytes; 150 pos = (dst->VXsize * y + x) * dst->PixelBytes; 151 while (width > 0) { 152 offset = VGLSetSegment(pos); 153 i = min(VGLAdpInfo.va_window_size - offset, width); 154 bcopy(line, dst->Bitmap + offset, i); 155 line += i; 156 pos += i; 157 width -= i; 158 } 159 break; 160 case VIDBUF8: 161 case MEMBUF: 162 address = dst->Bitmap + dst->VXsize * y + x; 163 bcopy(line, address, width); 164 break; 165 case VIDBUF16: 166 case VIDBUF24: 167 case VIDBUF32: 168 address = dst->Bitmap + (dst->VXsize * y + x) * dst->PixelBytes; 169 bcopy(line, address, width * dst->PixelBytes); 170 break; 171 default: 172 } 173 } 174 175 static void 176 ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line) 177 { 178 int i, bit, pos, count, planepos, start_offset, end_offset, offset; 179 int width2, len; 180 byte *address; 181 byte *VGLPlane[4]; 182 183 switch (src->Type) { 184 case VIDBUF4S: 185 start_offset = (x & 0x07); 186 end_offset = (x + width) & 0x07; 187 count = (width + start_offset) / 8; 188 if (end_offset) 189 count++; 190 VGLPlane[0] = VGLBuf; 191 VGLPlane[1] = VGLPlane[0] + count; 192 VGLPlane[2] = VGLPlane[1] + count; 193 VGLPlane[3] = VGLPlane[2] + count; 194 for (i=0; i<4; i++) { 195 outb(0x3ce, 0x04); 196 outb(0x3cf, i); 197 pos = VGLAdpInfo.va_line_width*y + x/8; 198 for (width2 = count; width2 > 0; ) { 199 offset = VGLSetSegment(pos); 200 len = min(VGLAdpInfo.va_window_size - offset, width2); 201 bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len); 202 pos += len; 203 width2 -= len; 204 } 205 } 206 goto read_planar; 207 case VIDBUF4: 208 address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8; 209 start_offset = (x & 0x07); 210 end_offset = (x + width) & 0x07; 211 count = (width + start_offset) / 8; 212 if (end_offset) 213 count++; 214 VGLPlane[0] = VGLBuf; 215 VGLPlane[1] = VGLPlane[0] + count; 216 VGLPlane[2] = VGLPlane[1] + count; 217 VGLPlane[3] = VGLPlane[2] + count; 218 for (i=0; i<4; i++) { 219 outb(0x3ce, 0x04); 220 outb(0x3cf, i); 221 bcopy(address, &VGLPlane[i][0], count); 222 } 223 read_planar: 224 pos = 0; 225 planepos = 0; 226 bit = 7 - start_offset; 227 while (pos < width) { 228 for (; bit >= 0 && pos < width; bit--, pos++) { 229 line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) | 230 ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) | 231 ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) | 232 ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3); 233 } 234 planepos++; 235 bit = 7; 236 } 237 break; 238 case VIDBUF8X: 239 address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4; 240 for (i=0; i<4; i++) { 241 outb(0x3ce, 0x04); 242 outb(0x3cf, (x + i)%4); 243 for (planepos=0, pos=i; pos<width; planepos++, pos+=4) 244 line[pos] = address[planepos]; 245 if ((x + i)%4 == 3) 246 ++address; 247 } 248 break; 249 case VIDBUF8S: 250 pos = src->VXsize * y + x; 251 while (width > 0) { 252 offset = VGLSetSegment(pos); 253 i = min(VGLAdpInfo.va_window_size - offset, width); 254 bcopy(src->Bitmap + offset, line, i); 255 line += i; 256 pos += i; 257 width -= i; 258 } 259 break; 260 case VIDBUF16S: 261 case VIDBUF24S: 262 case VIDBUF32S: 263 width = width * src->PixelBytes; 264 pos = (src->VXsize * y + x) * src->PixelBytes; 265 while (width > 0) { 266 offset = VGLSetSegment(pos); 267 i = min(VGLAdpInfo.va_window_size - offset, width); 268 bcopy(src->Bitmap + offset, line, i); 269 line += i; 270 pos += i; 271 width -= i; 272 } 273 break; 274 case VIDBUF8: 275 case MEMBUF: 276 address = src->Bitmap + src->VXsize * y + x; 277 bcopy(address, line, width); 278 break; 279 case VIDBUF16: 280 case VIDBUF24: 281 case VIDBUF32: 282 address = src->Bitmap + (src->VXsize * y + x) * src->PixelBytes; 283 bcopy(address, line, width * src->PixelBytes); 284 break; 285 default: 286 } 287 } 288 289 int 290 __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, 291 VGLBitmap *dst, int dstx, int dsty, int width, int hight) 292 { 293 int srcline, dstline; 294 295 if (srcx>src->VXsize || srcy>src->VYsize 296 || dstx>dst->VXsize || dsty>dst->VYsize) 297 return -1; 298 if (srcx < 0) { 299 width=width+srcx; dstx-=srcx; srcx=0; 300 } 301 if (srcy < 0) { 302 hight=hight+srcy; dsty-=srcy; srcy=0; 303 } 304 if (dstx < 0) { 305 width=width+dstx; srcx-=dstx; dstx=0; 306 } 307 if (dsty < 0) { 308 hight=hight+dsty; srcy-=dsty; dsty=0; 309 } 310 if (srcx+width > src->VXsize) 311 width=src->VXsize-srcx; 312 if (srcy+hight > src->VYsize) 313 hight=src->VYsize-srcy; 314 if (dstx+width > dst->VXsize) 315 width=dst->VXsize-dstx; 316 if (dsty+hight > dst->VYsize) 317 hight=dst->VYsize-dsty; 318 if (width < 0 || hight < 0) 319 return -1; 320 if (src->Type == MEMBUF) { 321 for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) { 322 WriteVerticalLine(dst, dstx, dstline, width, 323 (src->Bitmap+(srcline*src->VXsize)+srcx)); 324 } 325 } 326 else if (dst->Type == MEMBUF) { 327 for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) { 328 ReadVerticalLine(src, srcx, srcline, width, 329 (dst->Bitmap+(dstline*dst->VXsize)+dstx)); 330 } 331 } 332 else { 333 byte buffer[2048]; /* XXX */ 334 byte *p; 335 336 if (width > sizeof(buffer)) { 337 p = malloc(width); 338 if (p == NULL) 339 return 1; 340 } else { 341 p = buffer; 342 } 343 for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) { 344 ReadVerticalLine(src, srcx, srcline, width, p); 345 WriteVerticalLine(dst, dstx, dstline, width, p); 346 } 347 if (width > sizeof(buffer)) 348 free(p); 349 } 350 return 0; 351 } 352 353 int 354 VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, 355 VGLBitmap *dst, int dstx, int dsty, int width, int hight) 356 { 357 int error; 358 359 VGLMouseFreeze(dstx, dsty, width, hight, 0); 360 error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight); 361 VGLMouseUnFreeze(); 362 return error; 363 } 364 365 VGLBitmap 366 *VGLBitmapCreate(int type, int xsize, int ysize, byte *bits) 367 { 368 VGLBitmap *object; 369 370 if (type != MEMBUF) 371 return NULL; 372 if (xsize < 0 || ysize < 0) 373 return NULL; 374 object = (VGLBitmap *)malloc(sizeof(*object)); 375 if (object == NULL) 376 return NULL; 377 object->Type = type; 378 object->Xsize = xsize; 379 object->Ysize = ysize; 380 object->VXsize = xsize; 381 object->VYsize = ysize; 382 object->Xorigin = 0; 383 object->Yorigin = 0; 384 object->Bitmap = bits; 385 return object; 386 } 387 388 void 389 VGLBitmapDestroy(VGLBitmap *object) 390 { 391 if (object->Bitmap) 392 free(object->Bitmap); 393 free(object); 394 } 395 396 int 397 VGLBitmapAllocateBits(VGLBitmap *object) 398 { 399 object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize); 400 if (object->Bitmap == NULL) 401 return -1; 402 return 0; 403 } 404