14Srgrimes/*-
2122296Speter * Copyright (c) 1991-1997 S��ren Schmidt
34Srgrimes * All rights reserved.
44Srgrimes *
54Srgrimes * Redistribution and use in source and binary forms, with or without
64Srgrimes * modification, are permitted provided that the following conditions
74Srgrimes * are met:
84Srgrimes * 1. Redistributions of source code must retain the above copyright
94Srgrimes *    notice, this list of conditions and the following disclaimer,
104Srgrimes *    in this position and unchanged.
114Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
124Srgrimes *    notice, this list of conditions and the following disclaimer in the
134Srgrimes *    documentation and/or other materials provided with the distribution.
144Srgrimes * 3. The name of the author may not be used to endorse or promote products
154Srgrimes *    derived from this software without specific prior written permission.
164Srgrimes *
174Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
184Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
194Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
204Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
214Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
224Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
264Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274Srgrimes */
284Srgrimes
294Srgrimes#include <sys/cdefs.h>
30122940Speter__FBSDID("$FreeBSD: releng/10.3/lib/libvgl/bitmap.c 229784 2012-01-07 16:13:56Z uqs $");
314Srgrimes
324Srgrimes#include <sys/types.h>
33118031Sobrien#include <signal.h>
34118031Sobrien#include <sys/fbio.h>
35118031Sobrien#include "vgl.h"
36223668Sjonathan
37219134Srwatson#define min(x, y)	(((x) < (y)) ? (x) : (y))
382056Swollman
392056Swollmanstatic byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
40219134Srwatsonstatic int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101,
41217564Skib			    0x00010000, 0x00010001, 0x00010100, 0x00010101,
4276166Smarkm			    0x01000000, 0x01000001, 0x01000100, 0x01000101,
43190620Skib			    0x01010000, 0x01010001, 0x01010100, 0x01010101};
44190620Skib
45190620Skibstatic void
462056SwollmanWriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line)
4776166Smarkm{
48190620Skib  int i, pos, last, planepos, start_offset, end_offset, offset;
4912662Sdg  int len;
50147889Sdavidxu  unsigned int word = 0;
51147889Sdavidxu  byte *address;
52190620Skib  byte *VGLPlane[4];
53190620Skib
54190620Skib  switch (dst->Type) {
55190620Skib  case VIDBUF4:
56190620Skib  case VIDBUF4S:
57190620Skib    start_offset = (x & 0x07);
58190620Skib    end_offset = (x + width) & 0x07;
59190620Skib    i = (width + start_offset) / 8;
60190620Skib    if (end_offset)
61147889Sdavidxu	i++;
62147889Sdavidxu    VGLPlane[0] = VGLBuf;
63190620Skib    VGLPlane[1] = VGLPlane[0] + i;
64190620Skib    VGLPlane[2] = VGLPlane[1] + i;
65217564Skib    VGLPlane[3] = VGLPlane[2] + i;
66217564Skib    pos = 0;
67190620Skib    planepos = 0;
68217604Skib    last = 8 - start_offset;
69217604Skib    while (pos < width) {
70217564Skib      word = 0;
71190620Skib      while (pos < last && pos < width)
72217564Skib	word = (word<<1) | color2bit[line[pos++]&0x0f];
73217564Skib      VGLPlane[0][planepos] = word;
74217564Skib      VGLPlane[1][planepos] = word>>8;
75217564Skib      VGLPlane[2][planepos] = word>>16;
76217564Skib      VGLPlane[3][planepos] = word>>24;
77217564Skib      planepos++;
78217564Skib      last += 8;
79217564Skib    }
80217564Skib    planepos--;
81217564Skib    if (end_offset) {
82217564Skib      word <<= (8 - end_offset);
83217564Skib      VGLPlane[0][planepos] = word;
84190620Skib      VGLPlane[1][planepos] = word>>8;
85190620Skib      VGLPlane[2][planepos] = word>>16;
86190620Skib      VGLPlane[3][planepos] = word>>24;
87190620Skib    }
88190620Skib    if (start_offset || end_offset)
89190620Skib      width+=8;
90190620Skib    width /= 8;
9112220Sbde    outb(0x3ce, 0x01); outb(0x3cf, 0x00);		/* set/reset enable */
926874Sdg    outb(0x3ce, 0x08); outb(0x3cf, 0xff);		/* bit mask */
936874Sdg    for (i=0; i<4; i++) {
946874Sdg      outb(0x3c4, 0x02);
95132Sdg      outb(0x3c5, 0x01<<i);
9612220Sbde      outb(0x3ce, 0x04);
97132Sdg      outb(0x3cf, i);
986874Sdg      pos = VGLAdpInfo.va_line_width*y + x/8;
99190620Skib      if (dst->Type == VIDBUF4) {
100190620Skib	if (end_offset)
101190620Skib	  VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset];
102190620Skib	if (start_offset)
103190620Skib	  VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset];
104190620Skib	bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width);
105190620Skib      } else {	/* VIDBUF4S */
106190620Skib	if (end_offset) {
107190620Skib	  offset = VGLSetSegment(pos + planepos);
108190620Skib	  VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset];
109195104Srwatson	}
110190620Skib	offset = VGLSetSegment(pos);
111190620Skib	if (start_offset)
112190620Skib	  VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset];
113190620Skib	for (last = width; ; ) {
114190620Skib	  len = min(VGLAdpInfo.va_window_size - offset, last);
115190620Skib	  bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len);
116190620Skib	  pos += len;
117190620Skib	  last -= len;
118190620Skib	  if (last <= 0)
119190620Skib	    break;
120190620Skib	  offset = VGLSetSegment(pos);
121190620Skib	}
122190620Skib      }
123217543Sjhb    }
124217543Sjhb    break;
125216634Sjkim  case VIDBUF8X:
126190620Skib    address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
127217563Skib    for (i=0; i<4; i++) {
128217563Skib      outb(0x3c4, 0x02);
129190620Skib      outb(0x3c5, 0x01 << ((x + i)%4));
130190620Skib      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
131190620Skib        address[planepos] = line[pos];
132190620Skib      if ((x + i)%4 == 3)
133217563Skib	++address;
134190620Skib    }
135190620Skib    break;
136190620Skib  case VIDBUF8S:
137190620Skib    pos = dst->VXsize * y + x;
138190620Skib    while (width > 0) {
139190620Skib      offset = VGLSetSegment(pos);
140190620Skib      i = min(VGLAdpInfo.va_window_size - offset, width);
141190620Skib      bcopy(line, dst->Bitmap + offset, i);
142190620Skib      line += i;
143190620Skib      pos += i;
144190620Skib      width -= i;
145190620Skib    }
146190620Skib    break;
147190620Skib  case VIDBUF16S:
148190620Skib  case VIDBUF24S:
149216634Sjkim  case VIDBUF32S:
150190620Skib    width = width * dst->PixelBytes;
151190620Skib    pos = (dst->VXsize * y + x) * dst->PixelBytes;
152190620Skib    while (width > 0) {
153190620Skib      offset = VGLSetSegment(pos);
154190620Skib      i = min(VGLAdpInfo.va_window_size - offset, width);
155190620Skib      bcopy(line, dst->Bitmap + offset, i);
156190620Skib      line += i;
157190620Skib      pos += i;
158190620Skib      width -= i;
159190620Skib    }
160190620Skib    break;
161190620Skib  case VIDBUF8:
162190620Skib  case MEMBUF:
163190620Skib    address = dst->Bitmap + dst->VXsize * y + x;
164216634Sjkim    bcopy(line, address, width);
165190620Skib    break;
166190620Skib  case VIDBUF16:
167190620Skib  case VIDBUF24:
168190620Skib  case VIDBUF32:
169190620Skib    address = dst->Bitmap + (dst->VXsize * y + x) * dst->PixelBytes;
170190620Skib    bcopy(line, address, width * dst->PixelBytes);
171190620Skib    break;
172190620Skib  default:
17383366Sjulian    ;
17483366Sjulian  }
1756874Sdg}
1764Srgrimes
177114928Speterstatic void
178114928SpeterReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
179145077Speter{
180147889Sdavidxu  int i, bit, pos, count, planepos, start_offset, end_offset, offset;
181190620Skib  int width2, len;
182230426Skib  byte *address;
183230426Skib  byte *VGLPlane[4];
1844Srgrimes
185223668Sjonathan  switch (src->Type) {
186219134Srwatson  case VIDBUF4S:
187223692Sjonathan    start_offset = (x & 0x07);
188223692Sjonathan    end_offset = (x + width) & 0x07;
189223692Sjonathan    count = (width + start_offset) / 8;
190219134Srwatson    if (end_offset)
191219134Srwatson      count++;
192219134Srwatson    VGLPlane[0] = VGLBuf;
193223692Sjonathan    VGLPlane[1] = VGLPlane[0] + count;
194223692Sjonathan    VGLPlane[2] = VGLPlane[1] + count;
195223692Sjonathan    VGLPlane[3] = VGLPlane[2] + count;
196223692Sjonathan    for (i=0; i<4; i++) {
197223692Sjonathan      outb(0x3ce, 0x04);
198223692Sjonathan      outb(0x3cf, i);
199223692Sjonathan      pos = VGLAdpInfo.va_line_width*y + x/8;
200230426Skib      for (width2 = count; width2 > 0; ) {
201223692Sjonathan	offset = VGLSetSegment(pos);
202223692Sjonathan	len = min(VGLAdpInfo.va_window_size - offset, width2);
203223692Sjonathan	bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
204223692Sjonathan	pos += len;
205230426Skib	width2 -= len;
206223692Sjonathan      }
207219134Srwatson    }
208223692Sjonathan    goto read_planar;
209223692Sjonathan  case VIDBUF4:
210226498Sdes    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
211226498Sdes    start_offset = (x & 0x07);
212255677Spjd    end_offset = (x + width) & 0x07;
213226498Sdes    count = (width + start_offset) / 8;
214223692Sjonathan    if (end_offset)
215219134Srwatson      count++;
216219134Srwatson    VGLPlane[0] = VGLBuf;
217219134Srwatson    VGLPlane[1] = VGLPlane[0] + count;
218219134Srwatson    VGLPlane[2] = VGLPlane[1] + count;
219190620Skib    VGLPlane[3] = VGLPlane[2] + count;
220190620Skib    for (i=0; i<4; i++) {
221190620Skib      outb(0x3ce, 0x04);
222190620Skib      outb(0x3cf, i);
223190620Skib      bcopy(address, &VGLPlane[i][0], count);
224190620Skib    }
225195105Srwatsonread_planar:
226190620Skib    pos = 0;
227190620Skib    planepos = 0;
228190620Skib    bit = 7 - start_offset;
229190620Skib    while (pos < width) {
230190620Skib      for (; bit >= 0 && pos < width; bit--, pos++) {
231190620Skib        line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
232190620Skib                    ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
233230426Skib                    ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
234230426Skib                    ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
235230426Skib      }
236230426Skib      planepos++;
237230426Skib      bit = 7;
238230426Skib    }
239230426Skib    break;
240230426Skib  case VIDBUF8X:
241230426Skib    address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
242230426Skib    for (i=0; i<4; i++) {
243230426Skib      outb(0x3ce, 0x04);
244230426Skib      outb(0x3cf, (x + i)%4);
245190620Skib      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
246190620Skib        line[pos] = address[planepos];
247190620Skib      if ((x + i)%4 == 3)
248190620Skib	++address;
249190620Skib    }
250190620Skib    break;
251190620Skib  case VIDBUF8S:
252190620Skib    pos = src->VXsize * y + x;
253190620Skib    while (width > 0) {
254190620Skib      offset = VGLSetSegment(pos);
255190620Skib      i = min(VGLAdpInfo.va_window_size - offset, width);
256190620Skib      bcopy(src->Bitmap + offset, line, i);
257190620Skib      line += i;
258190620Skib      pos += i;
259145077Speter      width -= i;
260145077Speter    }
261145077Speter    break;
262145077Speter  case VIDBUF16S:
263145077Speter  case VIDBUF24S:
264145077Speter  case VIDBUF32S:
265147889Sdavidxu    width = width * src->PixelBytes;
266147889Sdavidxu    pos = (src->VXsize * y + x) * src->PixelBytes;
267190620Skib    while (width > 0) {
268190620Skib      offset = VGLSetSegment(pos);
269147889Sdavidxu      i = min(VGLAdpInfo.va_window_size - offset, width);
270145077Speter      bcopy(src->Bitmap + offset, line, i);
271145077Speter      line += i;
272145077Speter      pos += i;
273145077Speter      width -= i;
274145077Speter    }
275145077Speter    break;
276145077Speter  case VIDBUF8:
277147889Sdavidxu  case MEMBUF:
278147889Sdavidxu    address = src->Bitmap + src->VXsize * y + x;
279190620Skib    bcopy(address, line, width);
280190620Skib    break;
281147889Sdavidxu  case VIDBUF16:
282145077Speter  case VIDBUF24:
283114928Speter  case VIDBUF32:
284114928Speter    address = src->Bitmap + (src->VXsize * y + x) * src->PixelBytes;
285114928Speter    bcopy(address, line, width * src->PixelBytes);
286114928Speter    break;
287114928Speter  default:
288147889Sdavidxu    ;
289147889Sdavidxu  }
290147889Sdavidxu}
291147889Sdavidxu
292216634Sjkimint
293190620Skib__VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
294190620Skib	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
295147889Sdavidxu{
296147889Sdavidxu  int srcline, dstline;
297114928Speter
298114928Speter  if (srcx>src->VXsize || srcy>src->VYsize
299114928Speter	|| dstx>dst->VXsize || dsty>dst->VYsize)
300114928Speter    return -1;
301114928Speter  if (srcx < 0) {
302114928Speter    width=width+srcx; dstx-=srcx; srcx=0;
303114928Speter  }
304147889Sdavidxu  if (srcy < 0) {
305147889Sdavidxu    hight=hight+srcy; dsty-=srcy; srcy=0;
306147889Sdavidxu  }
307147889Sdavidxu  if (dstx < 0) {
308216634Sjkim    width=width+dstx; srcx-=dstx; dstx=0;
309190620Skib  }
310190620Skib  if (dsty < 0) {
311147889Sdavidxu    hight=hight+dsty; srcy-=dsty; dsty=0;
312147889Sdavidxu  }
313114928Speter  if (srcx+width > src->VXsize)
314114928Speter     width=src->VXsize-srcx;
315230426Skib  if (srcy+hight > src->VYsize)
316230426Skib     hight=src->VYsize-srcy;
317230426Skib  if (dstx+width > dst->VXsize)
318230426Skib     width=dst->VXsize-dstx;
319230426Skib  if (dsty+hight > dst->VYsize)
320230426Skib     hight=dst->VYsize-dsty;
321230426Skib  if (width < 0 || hight < 0)
322230426Skib     return -1;
323230426Skib  if (src->Type == MEMBUF) {
324230426Skib    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
3256874Sdg      WriteVerticalLine(dst, dstx, dstline, width,
326114029Sjhb	(src->Bitmap+(srcline*src->VXsize)+srcx));
3274Srgrimes    }
3284Srgrimes  }
32927993Sdyson  else if (dst->Type == MEMBUF) {
3304Srgrimes    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
331190620Skib      ReadVerticalLine(src, srcx, srcline, width,
332190620Skib	 (dst->Bitmap+(dstline*dst->VXsize)+dstx));
333190620Skib    }
334190620Skib  }
335190620Skib  else {
336190620Skib    byte buffer[2048];	/* XXX */
337190620Skib    byte *p;
338190620Skib
339190620Skib    if (width > sizeof(buffer)) {
340190620Skib      p = malloc(width);
341190620Skib      if (p == NULL)
342190620Skib	return 1;
343190620Skib    } else {
344190620Skib      p = buffer;
345190620Skib    }
346190620Skib    for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
347190620Skib      ReadVerticalLine(src, srcx, srcline, width, p);
348190620Skib      WriteVerticalLine(dst, dstx, dstline, width, p);
349190620Skib    }
350190620Skib    if (width > sizeof(buffer))
351190620Skib      free(p);
352190620Skib  }
353190620Skib  return 0;
354190620Skib}
355190620Skib
356190620Skibint
357190620SkibVGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
358190620Skib	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
359254025Sjeff{
360253685Sjeff  int error;
361190620Skib
362190620Skib  VGLMouseFreeze(dstx, dsty, width, hight, 0);
363190620Skib  error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
364190620Skib  VGLMouseUnFreeze();
365190620Skib  return error;
366190620Skib}
367190620Skib
368190620SkibVGLBitmap
369190620Skib*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
370190620Skib{
371190620Skib  VGLBitmap *object;
372190620Skib
373190620Skib  if (type != MEMBUF)
374190620Skib    return NULL;
375190620Skib  if (xsize < 0 || ysize < 0)
376190620Skib    return NULL;
377190620Skib  object = (VGLBitmap *)malloc(sizeof(*object));
378190620Skib  if (object == NULL)
379190620Skib    return NULL;
380190620Skib  object->Type = type;
381190620Skib  object->Xsize = xsize;
382190620Skib  object->Ysize = ysize;
383190620Skib  object->VXsize = xsize;
384190620Skib  object->VYsize = ysize;
385190620Skib  object->Xorigin = 0;
386190620Skib  object->Yorigin = 0;
387190620Skib  object->Bitmap = bits;
388190620Skib  return object;
389190620Skib}
390190620Skib
391190620Skibvoid
392190620SkibVGLBitmapDestroy(VGLBitmap *object)
393190620Skib{
394190620Skib  if (object->Bitmap)
395190620Skib    free(object->Bitmap);
396190620Skib  free(object);
397190620Skib}
398190620Skib
399190620Skibint
400190620SkibVGLBitmapAllocateBits(VGLBitmap *object)
401190620Skib{
402190620Skib  object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
403190620Skib  if (object->Bitmap == NULL)
404190620Skib    return -1;
405190620Skib  return 0;
406190620Skib}
407190620Skib