128328Ssos/*-
2229784Suqs * 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
1597748Sschweikh *    derived from this software without 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$");
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:
17397629Swollman    ;
17428328Ssos  }
17528328Ssos}
17628328Ssos
17728328Ssosstatic void
17828328SsosReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
17928328Ssos{
18028328Ssos  int i, bit, pos, count, planepos, start_offset, end_offset, offset;
18153013Syokota  int width2, len;
18228328Ssos  byte *address;
18353013Syokota  byte *VGLPlane[4];
18428328Ssos
18528328Ssos  switch (src->Type) {
18653013Syokota  case VIDBUF4S:
18753013Syokota    start_offset = (x & 0x07);
18853013Syokota    end_offset = (x + width) & 0x07;
18953013Syokota    count = (width + start_offset) / 8;
19053013Syokota    if (end_offset)
19153013Syokota      count++;
19253013Syokota    VGLPlane[0] = VGLBuf;
19353013Syokota    VGLPlane[1] = VGLPlane[0] + count;
19453013Syokota    VGLPlane[2] = VGLPlane[1] + count;
19553013Syokota    VGLPlane[3] = VGLPlane[2] + count;
19653013Syokota    for (i=0; i<4; i++) {
19753013Syokota      outb(0x3ce, 0x04);
19853013Syokota      outb(0x3cf, i);
19953013Syokota      pos = VGLAdpInfo.va_line_width*y + x/8;
20053013Syokota      for (width2 = count; width2 > 0; ) {
20153013Syokota	offset = VGLSetSegment(pos);
20253013Syokota	len = min(VGLAdpInfo.va_window_size - offset, width2);
20353013Syokota	bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
20453013Syokota	pos += len;
20553013Syokota	width2 -= len;
20653013Syokota      }
20753013Syokota    }
20853013Syokota    goto read_planar;
20928328Ssos  case VIDBUF4:
21053013Syokota    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
21128328Ssos    start_offset = (x & 0x07);
21228328Ssos    end_offset = (x + width) & 0x07;
21353013Syokota    count = (width + start_offset) / 8;
21428328Ssos    if (end_offset)
21553013Syokota      count++;
21653013Syokota    VGLPlane[0] = VGLBuf;
21753013Syokota    VGLPlane[1] = VGLPlane[0] + count;
21853013Syokota    VGLPlane[2] = VGLPlane[1] + count;
21953013Syokota    VGLPlane[3] = VGLPlane[2] + count;
22028328Ssos    for (i=0; i<4; i++) {
22128328Ssos      outb(0x3ce, 0x04);
22228328Ssos      outb(0x3cf, i);
22328328Ssos      bcopy(address, &VGLPlane[i][0], count);
22428328Ssos    }
22553013Syokotaread_planar:
22628328Ssos    pos = 0;
22728328Ssos    planepos = 0;
22853013Syokota    bit = 7 - start_offset;
22928328Ssos    while (pos < width) {
23053013Syokota      for (; bit >= 0 && pos < width; bit--, pos++) {
23128328Ssos        line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
23228328Ssos                    ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
23328328Ssos                    ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
23428328Ssos                    ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
23528328Ssos      }
23628328Ssos      planepos++;
23753013Syokota      bit = 7;
23828328Ssos    }
23928328Ssos    break;
24028328Ssos  case VIDBUF8X:
24153013Syokota    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
24228328Ssos    for (i=0; i<4; i++) {
24328328Ssos      outb(0x3ce, 0x04);
24450141Syokota      outb(0x3cf, (x + i)%4);
24550141Syokota      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
24628328Ssos        line[pos] = address[planepos];
24750141Syokota      if ((x + i)%4 == 3)
24850141Syokota	++address;
24950141Syokota    }
25028328Ssos    break;
25153013Syokota  case VIDBUF8S:
25253013Syokota    pos = src->VXsize * y + x;
25353013Syokota    while (width > 0) {
25453013Syokota      offset = VGLSetSegment(pos);
25553013Syokota      i = min(VGLAdpInfo.va_window_size - offset, width);
25653013Syokota      bcopy(src->Bitmap + offset, line, i);
25753013Syokota      line += i;
25853013Syokota      pos += i;
25953013Syokota      width -= i;
26053013Syokota    }
26153013Syokota    break;
26270991Snsouch  case VIDBUF16S:
26370991Snsouch  case VIDBUF24S:
26470991Snsouch  case VIDBUF32S:
26570991Snsouch    width = width * src->PixelBytes;
26670991Snsouch    pos = (src->VXsize * y + x) * src->PixelBytes;
26770991Snsouch    while (width > 0) {
26870991Snsouch      offset = VGLSetSegment(pos);
26970991Snsouch      i = min(VGLAdpInfo.va_window_size - offset, width);
27070991Snsouch      bcopy(src->Bitmap + offset, line, i);
27170991Snsouch      line += i;
27270991Snsouch      pos += i;
27370991Snsouch      width -= i;
27470991Snsouch    }
27570991Snsouch    break;
27628328Ssos  case VIDBUF8:
27728328Ssos  case MEMBUF:
27853013Syokota    address = src->Bitmap + src->VXsize * y + x;
27928328Ssos    bcopy(address, line, width);
28028328Ssos    break;
28170991Snsouch  case VIDBUF16:
28270991Snsouch  case VIDBUF24:
28370991Snsouch  case VIDBUF32:
28470991Snsouch    address = src->Bitmap + (src->VXsize * y + x) * src->PixelBytes;
28570991Snsouch    bcopy(address, line, width * src->PixelBytes);
28670991Snsouch    break;
28728328Ssos  default:
28897629Swollman    ;
28928328Ssos  }
29028328Ssos}
29128328Ssos
29228328Ssosint
29328328Ssos__VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
29428328Ssos	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
29528328Ssos{
29628328Ssos  int srcline, dstline;
29728328Ssos
29853013Syokota  if (srcx>src->VXsize || srcy>src->VYsize
29953013Syokota	|| dstx>dst->VXsize || dsty>dst->VYsize)
30028328Ssos    return -1;
30128328Ssos  if (srcx < 0) {
30228328Ssos    width=width+srcx; dstx-=srcx; srcx=0;
30328328Ssos  }
30428328Ssos  if (srcy < 0) {
30528328Ssos    hight=hight+srcy; dsty-=srcy; srcy=0;
30628328Ssos  }
30728328Ssos  if (dstx < 0) {
30828328Ssos    width=width+dstx; srcx-=dstx; dstx=0;
30928328Ssos  }
31028328Ssos  if (dsty < 0) {
31128328Ssos    hight=hight+dsty; srcy-=dsty; dsty=0;
31228328Ssos  }
31353013Syokota  if (srcx+width > src->VXsize)
31453013Syokota     width=src->VXsize-srcx;
31553013Syokota  if (srcy+hight > src->VYsize)
31653013Syokota     hight=src->VYsize-srcy;
31753013Syokota  if (dstx+width > dst->VXsize)
31853013Syokota     width=dst->VXsize-dstx;
31953013Syokota  if (dsty+hight > dst->VYsize)
32053013Syokota     hight=dst->VYsize-dsty;
32128328Ssos  if (width < 0 || hight < 0)
32228328Ssos     return -1;
32328328Ssos  if (src->Type == MEMBUF) {
32428328Ssos    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
32528328Ssos      WriteVerticalLine(dst, dstx, dstline, width,
32653013Syokota	(src->Bitmap+(srcline*src->VXsize)+srcx));
32728328Ssos    }
32828328Ssos  }
32928328Ssos  else if (dst->Type == MEMBUF) {
33028328Ssos    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
33128328Ssos      ReadVerticalLine(src, srcx, srcline, width,
33253013Syokota	 (dst->Bitmap+(dstline*dst->VXsize)+dstx));
33328328Ssos    }
33428328Ssos  }
33528328Ssos  else {
33653013Syokota    byte buffer[2048];	/* XXX */
33753013Syokota    byte *p;
33853013Syokota
33953013Syokota    if (width > sizeof(buffer)) {
34053013Syokota      p = malloc(width);
34153013Syokota      if (p == NULL)
34253013Syokota	return 1;
34353013Syokota    } else {
34453013Syokota      p = buffer;
34553013Syokota    }
34628328Ssos    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
34753013Syokota      ReadVerticalLine(src, srcx, srcline, width, p);
34853013Syokota      WriteVerticalLine(dst, dstx, dstline, width, p);
34928328Ssos    }
35053013Syokota    if (width > sizeof(buffer))
35153013Syokota      free(p);
35228328Ssos  }
35328328Ssos  return 0;
35428328Ssos}
35528328Ssos
35628328Ssosint
35728328SsosVGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
35828328Ssos	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
35928328Ssos{
36028328Ssos  int error;
36128328Ssos
36228328Ssos  VGLMouseFreeze(dstx, dsty, width, hight, 0);
36328328Ssos  error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
36428328Ssos  VGLMouseUnFreeze();
36528328Ssos  return error;
36628328Ssos}
36728328Ssos
36853013SyokotaVGLBitmap
36953013Syokota*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
37053013Syokota{
37153013Syokota  VGLBitmap *object;
37253013Syokota
37353013Syokota  if (type != MEMBUF)
37453013Syokota    return NULL;
37553013Syokota  if (xsize < 0 || ysize < 0)
37653013Syokota    return NULL;
37753013Syokota  object = (VGLBitmap *)malloc(sizeof(*object));
37853013Syokota  if (object == NULL)
37953013Syokota    return NULL;
38053013Syokota  object->Type = type;
38153013Syokota  object->Xsize = xsize;
38253013Syokota  object->Ysize = ysize;
38353013Syokota  object->VXsize = xsize;
38453013Syokota  object->VYsize = ysize;
38553013Syokota  object->Xorigin = 0;
38653013Syokota  object->Yorigin = 0;
38753013Syokota  object->Bitmap = bits;
38853013Syokota  return object;
38953013Syokota}
39053013Syokota
39153013Syokotavoid
39253013SyokotaVGLBitmapDestroy(VGLBitmap *object)
39353013Syokota{
39453013Syokota  if (object->Bitmap)
39553013Syokota    free(object->Bitmap);
39653013Syokota  free(object);
39753013Syokota}
39853013Syokota
39953013Syokotaint
40053013SyokotaVGLBitmapAllocateBits(VGLBitmap *object)
40153013Syokota{
40253013Syokota  object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
40353013Syokota  if (object->Bitmap == NULL)
40453013Syokota    return -1;
40553013Syokota  return 0;
40653013Syokota}
407