bitmap.c revision 83551
128328Ssos/*-
228328Ssos * Copyright (c) 1991-1997 S�ren Schmidt
328328Ssos * All rights reserved.
428328Ssos *
528328Ssos * Redistribution and use in source and binary forms, with or without
628328Ssos * modification, are permitted provided that the following conditions
728328Ssos * are met:
828328Ssos * 1. Redistributions of source code must retain the above copyright
928328Ssos *    notice, this list of conditions and the following disclaimer,
1028328Ssos *    in this position and unchanged.
1128328Ssos * 2. Redistributions in binary form must reproduce the above copyright
1228328Ssos *    notice, this list of conditions and the following disclaimer in the
1328328Ssos *    documentation and/or other materials provided with the distribution.
1428328Ssos * 3. The name of the author may not be used to endorse or promote products
1528328Ssos *    derived from this software withough specific prior written permission.
1628328Ssos *
1728328Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1828328Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1928328Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2028328Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2128328Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2228328Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2328328Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2428328Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2528328Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2628328Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2728328Ssos */
2828328Ssos
2983551Sdillon#include <sys/cdefs.h>
3083551Sdillon__FBSDID("$FreeBSD: head/lib/libvgl/bitmap.c 83551 2001-09-16 21:35:07Z dillon $");
3183551Sdillon
3228328Ssos#include <sys/types.h>
3328328Ssos#include <signal.h>
3466834Sphk#include <sys/fbio.h>
3528328Ssos#include "vgl.h"
3628328Ssos
3753013Syokota#define min(x, y)	(((x) < (y)) ? (x) : (y))
3853013Syokota
3928328Ssosstatic byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
4028328Ssosstatic int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101,
4128328Ssos			    0x00010000, 0x00010001, 0x00010100, 0x00010101,
4228328Ssos			    0x01000000, 0x01000001, 0x01000100, 0x01000101,
4328328Ssos			    0x01010000, 0x01010001, 0x01010100, 0x01010101};
4428328Ssos
4528328Ssosstatic void
4628328SsosWriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line)
4728328Ssos{
4828328Ssos  int i, pos, last, planepos, start_offset, end_offset, offset;
4953013Syokota  int len;
5028328Ssos  unsigned int word = 0;
5128328Ssos  byte *address;
5253013Syokota  byte *VGLPlane[4];
5328328Ssos
5428328Ssos  switch (dst->Type) {
5528328Ssos  case VIDBUF4:
5653013Syokota  case VIDBUF4S:
5728328Ssos    start_offset = (x & 0x07);
5828328Ssos    end_offset = (x + width) & 0x07;
5953013Syokota    i = (width + start_offset) / 8;
6053013Syokota    if (end_offset)
6153013Syokota	i++;
6253013Syokota    VGLPlane[0] = VGLBuf;
6353013Syokota    VGLPlane[1] = VGLPlane[0] + i;
6453013Syokota    VGLPlane[2] = VGLPlane[1] + i;
6553013Syokota    VGLPlane[3] = VGLPlane[2] + i;
6628328Ssos    pos = 0;
6728328Ssos    planepos = 0;
6853013Syokota    last = 8 - start_offset;
6928328Ssos    while (pos < width) {
7028328Ssos      word = 0;
7128328Ssos      while (pos < last && pos < width)
7228328Ssos	word = (word<<1) | color2bit[line[pos++]&0x0f];
7328328Ssos      VGLPlane[0][planepos] = word;
7428328Ssos      VGLPlane[1][planepos] = word>>8;
7528328Ssos      VGLPlane[2][planepos] = word>>16;
7628328Ssos      VGLPlane[3][planepos] = word>>24;
7728328Ssos      planepos++;
7853013Syokota      last += 8;
7928328Ssos    }
8028328Ssos    planepos--;
8128328Ssos    if (end_offset) {
8228328Ssos      word <<= (8 - end_offset);
8328328Ssos      VGLPlane[0][planepos] = word;
8428328Ssos      VGLPlane[1][planepos] = word>>8;
8528328Ssos      VGLPlane[2][planepos] = word>>16;
8628328Ssos      VGLPlane[3][planepos] = word>>24;
8728328Ssos    }
8828328Ssos    if (start_offset || end_offset)
8928328Ssos      width+=8;
9053013Syokota    width /= 8;
9153013Syokota    outb(0x3ce, 0x01); outb(0x3cf, 0x00);		/* set/reset enable */
9253013Syokota    outb(0x3ce, 0x08); outb(0x3cf, 0xff);		/* bit mask */
9328328Ssos    for (i=0; i<4; i++) {
9428328Ssos      outb(0x3c4, 0x02);
9528328Ssos      outb(0x3c5, 0x01<<i);
9628328Ssos      outb(0x3ce, 0x04);
9728328Ssos      outb(0x3cf, i);
9853013Syokota      pos = VGLAdpInfo.va_line_width*y + x/8;
9953013Syokota      if (dst->Type == VIDBUF4) {
10053013Syokota	if (end_offset)
10153013Syokota	  VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset];
10253013Syokota	if (start_offset)
10353013Syokota	  VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset];
10453013Syokota	bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width);
10553013Syokota      } else {	/* VIDBUF4S */
10653013Syokota	if (end_offset) {
10753013Syokota	  offset = VGLSetSegment(pos + planepos);
10853013Syokota	  VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset];
10953013Syokota	}
11053013Syokota	offset = VGLSetSegment(pos);
11153013Syokota	if (start_offset)
11253013Syokota	  VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset];
11353013Syokota	for (last = width; ; ) {
11453013Syokota	  len = min(VGLAdpInfo.va_window_size - offset, last);
11553013Syokota	  bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len);
11653013Syokota	  pos += len;
11753013Syokota	  last -= len;
11853013Syokota	  if (last <= 0)
11953013Syokota	    break;
12053013Syokota	  offset = VGLSetSegment(pos);
12153013Syokota	}
12253013Syokota      }
12328328Ssos    }
12428328Ssos    break;
12528328Ssos  case VIDBUF8X:
12653013Syokota    address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
12728328Ssos    for (i=0; i<4; i++) {
12828328Ssos      outb(0x3c4, 0x02);
12950141Syokota      outb(0x3c5, 0x01 << ((x + i)%4));
13050141Syokota      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
13128328Ssos        address[planepos] = line[pos];
13250141Syokota      if ((x + i)%4 == 3)
13350141Syokota	++address;
13450141Syokota    }
13528328Ssos    break;
13653013Syokota  case VIDBUF8S:
13753013Syokota    pos = dst->VXsize * y + x;
13853013Syokota    while (width > 0) {
13953013Syokota      offset = VGLSetSegment(pos);
14053013Syokota      i = min(VGLAdpInfo.va_window_size - offset, width);
14153013Syokota      bcopy(line, dst->Bitmap + offset, i);
14253013Syokota      line += i;
14353013Syokota      pos += i;
14453013Syokota      width -= i;
14553013Syokota    }
14653013Syokota    break;
14770991Snsouch  case VIDBUF16S:
14870991Snsouch  case VIDBUF24S:
14970991Snsouch  case VIDBUF32S:
15070991Snsouch    width = width * dst->PixelBytes;
15170991Snsouch    pos = (dst->VXsize * y + x) * dst->PixelBytes;
15270991Snsouch    while (width > 0) {
15370991Snsouch      offset = VGLSetSegment(pos);
15470991Snsouch      i = min(VGLAdpInfo.va_window_size - offset, width);
15570991Snsouch      bcopy(line, dst->Bitmap + offset, i);
15670991Snsouch      line += i;
15770991Snsouch      pos += i;
15870991Snsouch      width -= i;
15970991Snsouch    }
16070991Snsouch    break;
16128328Ssos  case VIDBUF8:
16228328Ssos  case MEMBUF:
16353013Syokota    address = dst->Bitmap + dst->VXsize * y + x;
16428328Ssos    bcopy(line, address, width);
16528328Ssos    break;
16670991Snsouch  case VIDBUF16:
16770991Snsouch  case VIDBUF24:
16870991Snsouch  case VIDBUF32:
16970991Snsouch    address = dst->Bitmap + (dst->VXsize * y + x) * dst->PixelBytes;
17070991Snsouch    bcopy(line, address, width * dst->PixelBytes);
17170991Snsouch    break;
17228328Ssos  default:
17328328Ssos  }
17428328Ssos}
17528328Ssos
17628328Ssosstatic void
17728328SsosReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
17828328Ssos{
17928328Ssos  int i, bit, pos, count, planepos, start_offset, end_offset, offset;
18053013Syokota  int width2, len;
18128328Ssos  byte *address;
18253013Syokota  byte *VGLPlane[4];
18328328Ssos
18428328Ssos  switch (src->Type) {
18553013Syokota  case VIDBUF4S:
18653013Syokota    start_offset = (x & 0x07);
18753013Syokota    end_offset = (x + width) & 0x07;
18853013Syokota    count = (width + start_offset) / 8;
18953013Syokota    if (end_offset)
19053013Syokota      count++;
19153013Syokota    VGLPlane[0] = VGLBuf;
19253013Syokota    VGLPlane[1] = VGLPlane[0] + count;
19353013Syokota    VGLPlane[2] = VGLPlane[1] + count;
19453013Syokota    VGLPlane[3] = VGLPlane[2] + count;
19553013Syokota    for (i=0; i<4; i++) {
19653013Syokota      outb(0x3ce, 0x04);
19753013Syokota      outb(0x3cf, i);
19853013Syokota      pos = VGLAdpInfo.va_line_width*y + x/8;
19953013Syokota      for (width2 = count; width2 > 0; ) {
20053013Syokota	offset = VGLSetSegment(pos);
20153013Syokota	len = min(VGLAdpInfo.va_window_size - offset, width2);
20253013Syokota	bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
20353013Syokota	pos += len;
20453013Syokota	width2 -= len;
20553013Syokota      }
20653013Syokota    }
20753013Syokota    goto read_planar;
20828328Ssos  case VIDBUF4:
20953013Syokota    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
21028328Ssos    start_offset = (x & 0x07);
21128328Ssos    end_offset = (x + width) & 0x07;
21253013Syokota    count = (width + start_offset) / 8;
21328328Ssos    if (end_offset)
21453013Syokota      count++;
21553013Syokota    VGLPlane[0] = VGLBuf;
21653013Syokota    VGLPlane[1] = VGLPlane[0] + count;
21753013Syokota    VGLPlane[2] = VGLPlane[1] + count;
21853013Syokota    VGLPlane[3] = VGLPlane[2] + count;
21928328Ssos    for (i=0; i<4; i++) {
22028328Ssos      outb(0x3ce, 0x04);
22128328Ssos      outb(0x3cf, i);
22228328Ssos      bcopy(address, &VGLPlane[i][0], count);
22328328Ssos    }
22453013Syokotaread_planar:
22528328Ssos    pos = 0;
22628328Ssos    planepos = 0;
22753013Syokota    bit = 7 - start_offset;
22828328Ssos    while (pos < width) {
22953013Syokota      for (; bit >= 0 && pos < width; bit--, pos++) {
23028328Ssos        line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
23128328Ssos                    ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
23228328Ssos                    ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
23328328Ssos                    ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
23428328Ssos      }
23528328Ssos      planepos++;
23653013Syokota      bit = 7;
23728328Ssos    }
23828328Ssos    break;
23928328Ssos  case VIDBUF8X:
24053013Syokota    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
24128328Ssos    for (i=0; i<4; i++) {
24228328Ssos      outb(0x3ce, 0x04);
24350141Syokota      outb(0x3cf, (x + i)%4);
24450141Syokota      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
24528328Ssos        line[pos] = address[planepos];
24650141Syokota      if ((x + i)%4 == 3)
24750141Syokota	++address;
24850141Syokota    }
24928328Ssos    break;
25053013Syokota  case VIDBUF8S:
25153013Syokota    pos = src->VXsize * y + x;
25253013Syokota    while (width > 0) {
25353013Syokota      offset = VGLSetSegment(pos);
25453013Syokota      i = min(VGLAdpInfo.va_window_size - offset, width);
25553013Syokota      bcopy(src->Bitmap + offset, line, i);
25653013Syokota      line += i;
25753013Syokota      pos += i;
25853013Syokota      width -= i;
25953013Syokota    }
26053013Syokota    break;
26170991Snsouch  case VIDBUF16S:
26270991Snsouch  case VIDBUF24S:
26370991Snsouch  case VIDBUF32S:
26470991Snsouch    width = width * src->PixelBytes;
26570991Snsouch    pos = (src->VXsize * y + x) * src->PixelBytes;
26670991Snsouch    while (width > 0) {
26770991Snsouch      offset = VGLSetSegment(pos);
26870991Snsouch      i = min(VGLAdpInfo.va_window_size - offset, width);
26970991Snsouch      bcopy(src->Bitmap + offset, line, i);
27070991Snsouch      line += i;
27170991Snsouch      pos += i;
27270991Snsouch      width -= i;
27370991Snsouch    }
27470991Snsouch    break;
27528328Ssos  case VIDBUF8:
27628328Ssos  case MEMBUF:
27753013Syokota    address = src->Bitmap + src->VXsize * y + x;
27828328Ssos    bcopy(address, line, width);
27928328Ssos    break;
28070991Snsouch  case VIDBUF16:
28170991Snsouch  case VIDBUF24:
28270991Snsouch  case VIDBUF32:
28370991Snsouch    address = src->Bitmap + (src->VXsize * y + x) * src->PixelBytes;
28470991Snsouch    bcopy(address, line, width * src->PixelBytes);
28570991Snsouch    break;
28628328Ssos  default:
28728328Ssos  }
28828328Ssos}
28928328Ssos
29028328Ssosint
29128328Ssos__VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
29228328Ssos	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
29328328Ssos{
29428328Ssos  int srcline, dstline;
29528328Ssos
29653013Syokota  if (srcx>src->VXsize || srcy>src->VYsize
29753013Syokota	|| dstx>dst->VXsize || dsty>dst->VYsize)
29828328Ssos    return -1;
29928328Ssos  if (srcx < 0) {
30028328Ssos    width=width+srcx; dstx-=srcx; srcx=0;
30128328Ssos  }
30228328Ssos  if (srcy < 0) {
30328328Ssos    hight=hight+srcy; dsty-=srcy; srcy=0;
30428328Ssos  }
30528328Ssos  if (dstx < 0) {
30628328Ssos    width=width+dstx; srcx-=dstx; dstx=0;
30728328Ssos  }
30828328Ssos  if (dsty < 0) {
30928328Ssos    hight=hight+dsty; srcy-=dsty; dsty=0;
31028328Ssos  }
31153013Syokota  if (srcx+width > src->VXsize)
31253013Syokota     width=src->VXsize-srcx;
31353013Syokota  if (srcy+hight > src->VYsize)
31453013Syokota     hight=src->VYsize-srcy;
31553013Syokota  if (dstx+width > dst->VXsize)
31653013Syokota     width=dst->VXsize-dstx;
31753013Syokota  if (dsty+hight > dst->VYsize)
31853013Syokota     hight=dst->VYsize-dsty;
31928328Ssos  if (width < 0 || hight < 0)
32028328Ssos     return -1;
32128328Ssos  if (src->Type == MEMBUF) {
32228328Ssos    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
32328328Ssos      WriteVerticalLine(dst, dstx, dstline, width,
32453013Syokota	(src->Bitmap+(srcline*src->VXsize)+srcx));
32528328Ssos    }
32628328Ssos  }
32728328Ssos  else if (dst->Type == MEMBUF) {
32828328Ssos    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
32928328Ssos      ReadVerticalLine(src, srcx, srcline, width,
33053013Syokota	 (dst->Bitmap+(dstline*dst->VXsize)+dstx));
33128328Ssos    }
33228328Ssos  }
33328328Ssos  else {
33453013Syokota    byte buffer[2048];	/* XXX */
33553013Syokota    byte *p;
33653013Syokota
33753013Syokota    if (width > sizeof(buffer)) {
33853013Syokota      p = malloc(width);
33953013Syokota      if (p == NULL)
34053013Syokota	return 1;
34153013Syokota    } else {
34253013Syokota      p = buffer;
34353013Syokota    }
34428328Ssos    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
34553013Syokota      ReadVerticalLine(src, srcx, srcline, width, p);
34653013Syokota      WriteVerticalLine(dst, dstx, dstline, width, p);
34728328Ssos    }
34853013Syokota    if (width > sizeof(buffer))
34953013Syokota      free(p);
35028328Ssos  }
35128328Ssos  return 0;
35228328Ssos}
35328328Ssos
35428328Ssosint
35528328SsosVGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
35628328Ssos	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
35728328Ssos{
35828328Ssos  int error;
35928328Ssos
36028328Ssos  VGLMouseFreeze(dstx, dsty, width, hight, 0);
36128328Ssos  error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
36228328Ssos  VGLMouseUnFreeze();
36328328Ssos  return error;
36428328Ssos}
36528328Ssos
36653013SyokotaVGLBitmap
36753013Syokota*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
36853013Syokota{
36953013Syokota  VGLBitmap *object;
37053013Syokota
37153013Syokota  if (type != MEMBUF)
37253013Syokota    return NULL;
37353013Syokota  if (xsize < 0 || ysize < 0)
37453013Syokota    return NULL;
37553013Syokota  object = (VGLBitmap *)malloc(sizeof(*object));
37653013Syokota  if (object == NULL)
37753013Syokota    return NULL;
37853013Syokota  object->Type = type;
37953013Syokota  object->Xsize = xsize;
38053013Syokota  object->Ysize = ysize;
38153013Syokota  object->VXsize = xsize;
38253013Syokota  object->VYsize = ysize;
38353013Syokota  object->Xorigin = 0;
38453013Syokota  object->Yorigin = 0;
38553013Syokota  object->Bitmap = bits;
38653013Syokota  return object;
38753013Syokota}
38853013Syokota
38953013Syokotavoid
39053013SyokotaVGLBitmapDestroy(VGLBitmap *object)
39153013Syokota{
39253013Syokota  if (object->Bitmap)
39353013Syokota    free(object->Bitmap);
39453013Syokota  free(object);
39553013Syokota}
39653013Syokota
39753013Syokotaint
39853013SyokotaVGLBitmapAllocateBits(VGLBitmap *object)
39953013Syokota{
40053013Syokota  object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
40153013Syokota  if (object->Bitmap == NULL)
40253013Syokota    return -1;
40353013Syokota  return 0;
40453013Syokota}
405