Initial import from FreeBSD RELENG_4:
[dragonfly.git] / lib / libvgl / bitmap.c
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: src/lib/libvgl/bitmap.c,v 1.4 1999/11/08 11:37:39 yokota Exp $
29  */
30
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <machine/console.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 VIDBUF8:
147   case MEMBUF:
148     address = dst->Bitmap + dst->VXsize * y + x;
149     bcopy(line, address, width);
150     break;
151
152   default:
153   }
154 }
155
156 static void
157 ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
158 {
159   int i, bit, pos, count, planepos, start_offset, end_offset, offset;
160   int width2, len;
161   byte *address;
162   byte *VGLPlane[4];
163
164   switch (src->Type) {
165   case VIDBUF4S:
166     start_offset = (x & 0x07);
167     end_offset = (x + width) & 0x07;
168     count = (width + start_offset) / 8;
169     if (end_offset)
170       count++;
171     VGLPlane[0] = VGLBuf;
172     VGLPlane[1] = VGLPlane[0] + count;
173     VGLPlane[2] = VGLPlane[1] + count;
174     VGLPlane[3] = VGLPlane[2] + count;
175     for (i=0; i<4; i++) {
176       outb(0x3ce, 0x04);
177       outb(0x3cf, i);
178       pos = VGLAdpInfo.va_line_width*y + x/8;
179       for (width2 = count; width2 > 0; ) {
180         offset = VGLSetSegment(pos);
181         len = min(VGLAdpInfo.va_window_size - offset, width2);
182         bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
183         pos += len;
184         width2 -= len;
185       }
186     }
187     goto read_planar;
188   case VIDBUF4:
189     address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
190     start_offset = (x & 0x07);
191     end_offset = (x + width) & 0x07;
192     count = (width + start_offset) / 8;
193     if (end_offset)
194       count++;
195     VGLPlane[0] = VGLBuf;
196     VGLPlane[1] = VGLPlane[0] + count;
197     VGLPlane[2] = VGLPlane[1] + count;
198     VGLPlane[3] = VGLPlane[2] + count;
199     for (i=0; i<4; i++) {
200       outb(0x3ce, 0x04);
201       outb(0x3cf, i);
202       bcopy(address, &VGLPlane[i][0], count);
203     }
204 read_planar:
205     pos = 0;
206     planepos = 0;
207     bit = 7 - start_offset;
208     while (pos < width) {
209       for (; bit >= 0 && pos < width; bit--, pos++) {
210         line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
211                     ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
212                     ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
213                     ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
214       }
215       planepos++;
216       bit = 7;
217     }
218     break;
219   case VIDBUF8X:
220     address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
221     for (i=0; i<4; i++) {
222       outb(0x3ce, 0x04);
223       outb(0x3cf, (x + i)%4);
224       for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
225         line[pos] = address[planepos];
226       if ((x + i)%4 == 3)
227         ++address;
228     }
229     break;
230   case VIDBUF8S:
231     pos = src->VXsize * y + x;
232     while (width > 0) {
233       offset = VGLSetSegment(pos);
234       i = min(VGLAdpInfo.va_window_size - offset, width);
235       bcopy(src->Bitmap + offset, line, i);
236       line += i;
237       pos += i;
238       width -= i;
239     }
240     break;
241   case VIDBUF8:
242   case MEMBUF:
243     address = src->Bitmap + src->VXsize * y + x;
244     bcopy(address, line, width);
245     break;
246   default:
247   }
248 }
249
250 int
251 __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
252               VGLBitmap *dst, int dstx, int dsty, int width, int hight)
253 {
254   int srcline, dstline;
255
256   if (srcx>src->VXsize || srcy>src->VYsize
257         || dstx>dst->VXsize || dsty>dst->VYsize)
258     return -1;  
259   if (srcx < 0) {
260     width=width+srcx; dstx-=srcx; srcx=0;    
261   }
262   if (srcy < 0) {
263     hight=hight+srcy; dsty-=srcy; srcy=0; 
264   }
265   if (dstx < 0) {    
266     width=width+dstx; srcx-=dstx; dstx=0;
267   }
268   if (dsty < 0) {
269     hight=hight+dsty; srcy-=dsty; dsty=0;
270   }
271   if (srcx+width > src->VXsize)
272      width=src->VXsize-srcx;
273   if (srcy+hight > src->VYsize)
274      hight=src->VYsize-srcy;
275   if (dstx+width > dst->VXsize)
276      width=dst->VXsize-dstx;
277   if (dsty+hight > dst->VYsize)
278      hight=dst->VYsize-dsty;
279   if (width < 0 || hight < 0)
280      return -1;
281   if (src->Type == MEMBUF) {
282     for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
283       WriteVerticalLine(dst, dstx, dstline, width, 
284         (src->Bitmap+(srcline*src->VXsize)+srcx));
285     }
286   }
287   else if (dst->Type == MEMBUF) {
288     for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
289       ReadVerticalLine(src, srcx, srcline, width,
290          (dst->Bitmap+(dstline*dst->VXsize)+dstx));
291     }
292   }
293   else {
294     byte buffer[2048];  /* XXX */
295     byte *p;
296
297     if (width > sizeof(buffer)) {
298       p = malloc(width);
299       if (p == NULL)
300         return 1;
301     } else {
302       p = buffer;
303     }
304     for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
305       ReadVerticalLine(src, srcx, srcline, width, p);
306       WriteVerticalLine(dst, dstx, dstline, width, p);
307     }
308     if (width > sizeof(buffer))
309       free(p);
310   }
311   return 0;
312 }
313
314 int
315 VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
316               VGLBitmap *dst, int dstx, int dsty, int width, int hight)
317 {
318   int error;
319
320   VGLMouseFreeze(dstx, dsty, width, hight, 0);
321   error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
322   VGLMouseUnFreeze();
323   return error;
324 }
325
326 VGLBitmap
327 *VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
328 {
329   VGLBitmap *object;
330
331   if (type != MEMBUF)
332     return NULL;
333   if (xsize < 0 || ysize < 0)
334     return NULL;
335   object = (VGLBitmap *)malloc(sizeof(*object));
336   if (object == NULL)
337     return NULL;
338   object->Type = type;
339   object->Xsize = xsize;
340   object->Ysize = ysize;
341   object->VXsize = xsize;
342   object->VYsize = ysize;
343   object->Xorigin = 0;
344   object->Yorigin = 0;
345   object->Bitmap = bits;
346   return object;
347 }
348
349 void
350 VGLBitmapDestroy(VGLBitmap *object)
351 {
352   if (object->Bitmap)
353     free(object->Bitmap);
354   free(object);
355 }
356
357 int
358 VGLBitmapAllocateBits(VGLBitmap *object)
359 {
360   object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
361   if (object->Bitmap == NULL)
362     return -1;
363   return 0;
364 }