bitmap.c revision 53013
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1991-1997 S�ren Schmidt
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer,
101590Srgrimes *    in this position and unchanged.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes * 3. The name of the author may not be used to endorse or promote products
151590Srgrimes *    derived from this software withough specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
181590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
201590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
211590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
221590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
261590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271590Srgrimes *
281590Srgrimes * $FreeBSD: head/lib/libvgl/bitmap.c 53013 1999-11-08 11:37:46Z yokota $
291590Srgrimes */
301590Srgrimes
311590Srgrimes#include <sys/types.h>
321590Srgrimes#include <signal.h>
331590Srgrimes#include <machine/console.h>
341590Srgrimes#include "vgl.h"
3528693Scharnier
361590Srgrimes#define min(x, y)	(((x) < (y)) ? (x) : (y))
371590Srgrimes
38123441Sbdestatic byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
391590Srgrimesstatic int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101,
40123441Sbde			    0x00010000, 0x00010001, 0x00010100, 0x00010101,
411590Srgrimes			    0x01000000, 0x01000001, 0x01000100, 0x01000101,
42123441Sbde			    0x01010000, 0x01010001, 0x01010100, 0x01010101};
43123441Sbde
4428693Scharnierstatic void
451590SrgrimesWriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line)
46123441Sbde{
47123441Sbde  int i, pos, last, planepos, start_offset, end_offset, offset;
48123441Sbde  int len;
491590Srgrimes  unsigned int word = 0;
501590Srgrimes  byte *address;
511590Srgrimes  byte *VGLPlane[4];
5212811Sbde
531590Srgrimes  switch (dst->Type) {
541590Srgrimes  case VIDBUF4:
551590Srgrimes  case VIDBUF4S:
561590Srgrimes    start_offset = (x & 0x07);
571590Srgrimes    end_offset = (x + width) & 0x07;
58111008Sphk    i = (width + start_offset) / 8;
591590Srgrimes    if (end_offset)
60208389Ssbruno	i++;
6112804Speter    VGLPlane[0] = VGLBuf;
62198620Sjhb    VGLPlane[1] = VGLPlane[0] + i;
6312811Sbde    VGLPlane[2] = VGLPlane[1] + i;
6412811Sbde    VGLPlane[3] = VGLPlane[2] + i;
6512811Sbde    pos = 0;
6628693Scharnier    planepos = 0;
6787690Smarkm    last = 8 - start_offset;
6828693Scharnier    while (pos < width) {
6928693Scharnier      word = 0;
7028693Scharnier      while (pos < last && pos < width)
7128693Scharnier	word = (word<<1) | color2bit[line[pos++]&0x0f];
72148413Srwatson      VGLPlane[0][planepos] = word;
731590Srgrimes      VGLPlane[1][planepos] = word>>8;
7428693Scharnier      VGLPlane[2][planepos] = word>>16;
751590Srgrimes      VGLPlane[3][planepos] = word>>24;
761590Srgrimes      planepos++;
771590Srgrimes      last += 8;
7830180Sdima    }
7928693Scharnier    planepos--;
8028693Scharnier    if (end_offset) {
81174573Speter      word <<= (8 - end_offset);
821590Srgrimes      VGLPlane[0][planepos] = word;
8387690Smarkm      VGLPlane[1][planepos] = word>>8;
8487690Smarkm      VGLPlane[2][planepos] = word>>16;
8587690Smarkm      VGLPlane[3][planepos] = word>>24;
86181881Sjhb    }
871590Srgrimes    if (start_offset || end_offset)
88181881Sjhb      width+=8;
891590Srgrimes    width /= 8;
90181881Sjhb    outb(0x3ce, 0x01); outb(0x3cf, 0x00);		/* set/reset enable */
911590Srgrimes    outb(0x3ce, 0x08); outb(0x3cf, 0xff);		/* bit mask */
92181881Sjhb    for (i=0; i<4; i++) {
931590Srgrimes      outb(0x3c4, 0x02);
94181881Sjhb      outb(0x3c5, 0x01<<i);
951590Srgrimes      outb(0x3ce, 0x04);
96181881Sjhb      outb(0x3cf, i);
971590Srgrimes      pos = VGLAdpInfo.va_line_width*y + x/8;
98181881Sjhb      if (dst->Type == VIDBUF4) {
991590Srgrimes	if (end_offset)
100181881Sjhb	  VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset];
1011590Srgrimes	if (start_offset)
102181881Sjhb	  VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset];
1031590Srgrimes	bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width);
104181881Sjhb      } else {	/* VIDBUF4S */
105131300Sgreen	if (end_offset) {
106181881Sjhb	  offset = VGLSetSegment(pos + planepos);
107131300Sgreen	  VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset];
10830180Sdima	}
109131300Sgreen	offset = VGLSetSegment(pos);
1101590Srgrimes	if (start_offset)
111131300Sgreen	  VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset];
1121590Srgrimes	for (last = width; ; ) {
113131300Sgreen	  len = min(VGLAdpInfo.va_window_size - offset, last);
1141590Srgrimes	  bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len);
115131300Sgreen	  pos += len;
1161590Srgrimes	  last -= len;
117131300Sgreen	  if (last <= 0)
11892653Sjeff	    break;
119181881Sjhb	  offset = VGLSetSegment(pos);
1201590Srgrimes	}
1211590Srgrimes      }
1221590Srgrimes    }
1231590Srgrimes    break;
124123250Sdes  case VIDBUF8X:
125123250Sdes    address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
126123250Sdes    for (i=0; i<4; i++) {
127123250Sdes      outb(0x3c4, 0x02);
128123250Sdes      outb(0x3c5, 0x01 << ((x + i)%4));
129123250Sdes      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
130123250Sdes        address[planepos] = line[pos];
131123250Sdes      if ((x + i)%4 == 3)
132123250Sdes	++address;
133123250Sdes    }
134123250Sdes    break;
1351590Srgrimes  case VIDBUF8S:
136123250Sdes    pos = dst->VXsize * y + x;
1371590Srgrimes    while (width > 0) {
138184645Skeramida      offset = VGLSetSegment(pos);
139184645Skeramida      i = min(VGLAdpInfo.va_window_size - offset, width);
140184645Skeramida      bcopy(line, dst->Bitmap + offset, i);
141184645Skeramida      line += i;
142123250Sdes      pos += i;
143123250Sdes      width -= i;
144174573Speter    }
145174573Speter    break;
1461590Srgrimes  case VIDBUF8:
147123250Sdes  case MEMBUF:
1481590Srgrimes    address = dst->Bitmap + dst->VXsize * y + x;
1491590Srgrimes    bcopy(line, address, width);
1501590Srgrimes    break;
1511590Srgrimes
1521590Srgrimes  default:
1531590Srgrimes  }
1541590Srgrimes}
15543962Sdillon
1561590Srgrimesstatic void
15792922SimpReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
158174573Speter{
15992922Simp  int i, bit, pos, count, planepos, start_offset, end_offset, offset;
160122300Sjmg  int width2, len;
16192922Simp  byte *address;
16292922Simp  byte *VGLPlane[4];
163123407Sdes
164148790Srwatson  switch (src->Type) {
165148630Srwatson  case VIDBUF4S:
16692922Simp    start_offset = (x & 0x07);
167131300Sgreen    end_offset = (x + width) & 0x07;
168131300Sgreen    count = (width + start_offset) / 8;
16992922Simp    if (end_offset)
170184645Skeramida      count++;
171184645Skeramida    VGLPlane[0] = VGLBuf;
172174573Speter    VGLPlane[1] = VGLPlane[0] + count;
17392922Simp    VGLPlane[2] = VGLPlane[1] + count;
1741590Srgrimes    VGLPlane[3] = VGLPlane[2] + count;
17592922Simp    for (i=0; i<4; i++) {
17692922Simp      outb(0x3ce, 0x04);
17787690Smarkm      outb(0x3cf, i);
178123250Sdes      pos = VGLAdpInfo.va_line_width*y + x/8;
17987690Smarkm      for (width2 = count; width2 > 0; ) {
18028693Scharnier	offset = VGLSetSegment(pos);
181123250Sdes	len = min(VGLAdpInfo.va_window_size - offset, width2);
1821590Srgrimes	bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
18387690Smarkm	pos += len;
184123407Sdes	width2 -= len;
185208389Ssbruno      }
1861590Srgrimes    }
1871590Srgrimes    goto read_planar;
18878474Sschweikh  case VIDBUF4:
1891590Srgrimes    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
1901590Srgrimes    start_offset = (x & 0x07);
1911590Srgrimes    end_offset = (x + width) & 0x07;
19243822Sken    count = (width + start_offset) / 8;
193174573Speter    if (end_offset)
194174573Speter      count++;
1951590Srgrimes    VGLPlane[0] = VGLBuf;
196123250Sdes    VGLPlane[1] = VGLPlane[0] + count;
197123250Sdes    VGLPlane[2] = VGLPlane[1] + count;
198123250Sdes    VGLPlane[3] = VGLPlane[2] + count;
1991590Srgrimes    for (i=0; i<4; i++) {
2001590Srgrimes      outb(0x3ce, 0x04);
2011590Srgrimes      outb(0x3cf, i);
202174573Speter      bcopy(address, &VGLPlane[i][0], count);
203174573Speter    }
204174573Speterread_planar:
2051590Srgrimes    pos = 0;
206113460Stjr    planepos = 0;
2071590Srgrimes    bit = 7 - start_offset;
208174573Speter    while (pos < width) {
209174573Speter      for (; bit >= 0 && pos < width; bit--, pos++) {
210174573Speter        line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
211174573Speter                    ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
212174573Speter                    ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
213174573Speter                    ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
2141590Srgrimes      }
2151590Srgrimes      planepos++;
2161590Srgrimes      bit = 7;
2171590Srgrimes    }
2181590Srgrimes    break;
2191590Srgrimes  case VIDBUF8X:
2201590Srgrimes    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
2211590Srgrimes    for (i=0; i<4; i++) {
2221590Srgrimes      outb(0x3ce, 0x04);
2231590Srgrimes      outb(0x3cf, (x + i)%4);
2241590Srgrimes      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
2251590Srgrimes        line[pos] = address[planepos];
22639230Sgibbs      if ((x + i)%4 == 3)
22739372Sdillon	++address;
22839230Sgibbs    }
22939230Sgibbs    break;
23039230Sgibbs  case VIDBUF8S:
23139230Sgibbs    pos = src->VXsize * y + x;
23239230Sgibbs    while (width > 0) {
23339230Sgibbs      offset = VGLSetSegment(pos);
234112284Sphk      i = min(VGLAdpInfo.va_window_size - offset, width);
23539230Sgibbs      bcopy(src->Bitmap + offset, line, i);
23639230Sgibbs      line += i;
2371590Srgrimes      pos += i;
2381590Srgrimes      width -= i;
2391590Srgrimes    }
2401590Srgrimes    break;
24130180Sdima  case VIDBUF8:
2421590Srgrimes  case MEMBUF:
24330180Sdima    address = src->Bitmap + src->VXsize * y + x;
24430180Sdima    bcopy(address, line, width);
24530180Sdima    break;
2461590Srgrimes  default:
2471590Srgrimes  }
248208389Ssbruno}
249208389Ssbruno
250208389Ssbrunoint
2511590Srgrimes__VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
25244067Sbde	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
25344067Sbde{
25444067Sbde  int srcline, dstline;
2551590Srgrimes
2561590Srgrimes  if (srcx>src->VXsize || srcy>src->VYsize
2571590Srgrimes	|| dstx>dst->VXsize || dsty>dst->VYsize)
2581590Srgrimes    return -1;
2591590Srgrimes  if (srcx < 0) {
2601590Srgrimes    width=width+srcx; dstx-=srcx; srcx=0;
2611590Srgrimes  }
2621590Srgrimes  if (srcy < 0) {
2631590Srgrimes    hight=hight+srcy; dsty-=srcy; srcy=0;
2641590Srgrimes  }
2651590Srgrimes  if (dstx < 0) {
266123250Sdes    width=width+dstx; srcx-=dstx; dstx=0;
267123250Sdes  }
268123250Sdes  if (dsty < 0) {
269123250Sdes    hight=hight+dsty; srcy-=dsty; dsty=0;
270123250Sdes  }
2711590Srgrimes  if (srcx+width > src->VXsize)
272123250Sdes     width=src->VXsize-srcx;
2731590Srgrimes  if (srcy+hight > src->VYsize)
27428693Scharnier     hight=src->VYsize-srcy;
2751590Srgrimes  if (dstx+width > dst->VXsize)
276123250Sdes     width=dst->VXsize-dstx;
277123250Sdes  if (dsty+hight > dst->VYsize)
2781590Srgrimes     hight=dst->VYsize-dsty;
27981537Sken  if (width < 0 || hight < 0)
2801590Srgrimes     return -1;
2811590Srgrimes  if (src->Type == MEMBUF) {
2821590Srgrimes    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
28328693Scharnier      WriteVerticalLine(dst, dstx, dstline, width,
2841590Srgrimes	(src->Bitmap+(srcline*src->VXsize)+srcx));
2851590Srgrimes    }
286174573Speter  }
287174573Speter  else if (dst->Type == MEMBUF) {
2881590Srgrimes    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
2891590Srgrimes      ReadVerticalLine(src, srcx, srcline, width,
29043819Sken	 (dst->Bitmap+(dstline*dst->VXsize)+dstx));
29143819Sken    }
29243819Sken  }
29343819Sken  else {
29443819Sken    byte buffer[2048];	/* XXX */
295112284Sphk    byte *p;
29643819Sken
29743819Sken    if (width > sizeof(buffer)) {
29843819Sken      p = malloc(width);
2991590Srgrimes      if (p == NULL)
3001590Srgrimes	return 1;
3011590Srgrimes    } else {
3021590Srgrimes      p = buffer;
3031590Srgrimes    }
3041590Srgrimes    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
305208389Ssbruno      ReadVerticalLine(src, srcx, srcline, width, p);
306208389Ssbruno      WriteVerticalLine(dst, dstx, dstline, width, p);
3071590Srgrimes    }
3081590Srgrimes    if (width > sizeof(buffer))
3091590Srgrimes      free(p);
3101590Srgrimes  }
3111590Srgrimes  return 0;
3121590Srgrimes}
3131590Srgrimes
3141590Srgrimesint
3151590SrgrimesVGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
316208389Ssbruno	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
3171590Srgrimes{
3181590Srgrimes  int error;
3191590Srgrimes
3201590Srgrimes  VGLMouseFreeze(dstx, dsty, width, hight, 0);
321148790Srwatson  error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
32243962Sdillon  VGLMouseUnFreeze();
323148630Srwatson  return error;
3241590Srgrimes}
3251590Srgrimes
32630180SdimaVGLBitmap
3271590Srgrimes*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
3281590Srgrimes{
3291590Srgrimes  VGLBitmap *object;
3301590Srgrimes
3311590Srgrimes  if (type != MEMBUF)
3321590Srgrimes    return NULL;
3331590Srgrimes  if (xsize < 0 || ysize < 0)
3341590Srgrimes    return NULL;
3351590Srgrimes  object = (VGLBitmap *)malloc(sizeof(*object));
3361590Srgrimes  if (object == NULL)
337123250Sdes    return NULL;
338123250Sdes  object->Type = type;
339123250Sdes  object->Xsize = xsize;
3401590Srgrimes  object->Ysize = ysize;
341123250Sdes  object->VXsize = xsize;
342123250Sdes  object->VYsize = ysize;
343123250Sdes  object->Xorigin = 0;
344123250Sdes  object->Yorigin = 0;
345123250Sdes  object->Bitmap = bits;
346123250Sdes  return object;
347123250Sdes}
348123250Sdes
349123250Sdesvoid
350123250SdesVGLBitmapDestroy(VGLBitmap *object)
351123250Sdes{
352112284Sphk  if (object->Bitmap)
35339230Sgibbs    free(object->Bitmap);
3541590Srgrimes  free(object);
355188888Sdelphij}
356188888Sdelphij
35739230Sgibbsint
358112284SphkVGLBitmapAllocateBits(VGLBitmap *object)
35939230Sgibbs{
36039230Sgibbs  object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
36139230Sgibbs  if (object->Bitmap == NULL)
36239230Sgibbs    return -1;
36339230Sgibbs  return 0;
36439230Sgibbs}
36539230Sgibbs