Merge from vendor branch DIFFUTILS:
[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  * $DragonFly: src/lib/libvgl/bitmap.c,v 1.2 2003/06/17 04:26:52 dillon Exp $
30  */
31
32 #include <sys/types.h>
33 #include <signal.h>
34 #include <machine/console.h>
35 #include "vgl.h"
36
37 #define min(x, y)       (((x) < (y)) ? (x) : (y))
38
39 static byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
40 static int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101,
41                             0x00010000, 0x00010001, 0x00010100, 0x00010101,
42                             0x01000000, 0x01000001, 0x01000100, 0x01000101,
43                             0x01010000, 0x01010001, 0x01010100, 0x01010101};
44
45 static void
46 WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line)
47 {
48   int i, pos, last, planepos, start_offset, end_offset, offset;
49   int len;
50   unsigned int word = 0;
51   byte *address;
52   byte *VGLPlane[4];
53
54   switch (dst->Type) {
55   case VIDBUF4:
56   case VIDBUF4S:
57     start_offset = (x & 0x07);
58     end_offset = (x + width) & 0x07;
59     i = (width + start_offset) / 8;
60     if (end_offset)
61         i++;
62     VGLPlane[0] = VGLBuf;
63     VGLPlane[1] = VGLPlane[0] + i;
64     VGLPlane[2] = VGLPlane[1] + i;
65     VGLPlane[3] = VGLPlane[2] + i;
66     pos = 0;
67     planepos = 0;
68     last = 8 - start_offset;
69     while (pos < width) {
70       word = 0;
71       while (pos < last && pos < width)
72         word = (word<<1) | color2bit[line[pos++]&0x0f];
73       VGLPlane[0][planepos] = word;
74       VGLPlane[1][planepos] = word>>8;
75       VGLPlane[2][planepos] = word>>16;
76       VGLPlane[3][planepos] = word>>24;
77       planepos++;
78       last += 8;
79     }
80     planepos--;
81     if (end_offset) {
82       word <<= (8 - end_offset);
83       VGLPlane[0][planepos] = word;
84       VGLPlane[1][planepos] = word>>8;
85       VGLPlane[2][planepos] = word>>16;
86       VGLPlane[3][planepos] = word>>24;
87     }
88     if (start_offset || end_offset)
89       width+=8;
90     width /= 8;
91     outb(0x3ce, 0x01); outb(0x3cf, 0x00);               /* set/reset enable */
92     outb(0x3ce, 0x08); outb(0x3cf, 0xff);               /* bit mask */
93     for (i=0; i<4; i++) {
94       outb(0x3c4, 0x02);
95       outb(0x3c5, 0x01<<i);
96       outb(0x3ce, 0x04);
97       outb(0x3cf, i);
98       pos = VGLAdpInfo.va_line_width*y + x/8;
99       if (dst->Type == VIDBUF4) {
100         if (end_offset)
101           VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset];
102         if (start_offset)
103           VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset];
104         bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width);
105       } else {  /* VIDBUF4S */
106         if (end_offset) {
107           offset = VGLSetSegment(pos + planepos);
108           VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset];
109         }
110         offset = VGLSetSegment(pos);
111         if (start_offset)
112           VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset];
113         for (last = width; ; ) { 
114           len = min(VGLAdpInfo.va_window_size - offset, last);
115           bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len);
116           pos += len;
117           last -= len;
118           if (last <= 0)
119             break;
120           offset = VGLSetSegment(pos);
121         }
122       }
123     }
124     break;
125   case VIDBUF8X:
126     address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
127     for (i=0; i<4; i++) {
128       outb(0x3c4, 0x02);
129       outb(0x3c5, 0x01 << ((x + i)%4));
130       for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
131         address[planepos] = line[pos];
132       if ((x + i)%4 == 3)
133         ++address;
134     }
135     break;
136   case VIDBUF8S:
137     pos = dst->VXsize * y + x;
138     while (width > 0) {
139       offset = VGLSetSegment(pos);
140       i = min(VGLAdpInfo.va_window_size - offset, width);
141       bcopy(line, dst->Bitmap + offset, i);
142       line += i;
143       pos += i;
144       width -= i;
145     }
146     break;
147   case VIDBUF8:
148   case MEMBUF:
149     address = dst->Bitmap + dst->VXsize * y + x;
150     bcopy(line, address, width);
151     break;
152
153   default:
154   }
155 }
156
157 static void
158 ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line)
159 {
160   int i, bit, pos, count, planepos, start_offset, end_offset, offset;
161   int width2, len;
162   byte *address;
163   byte *VGLPlane[4];
164
165   switch (src->Type) {
166   case VIDBUF4S:
167     start_offset = (x & 0x07);
168     end_offset = (x + width) & 0x07;
169     count = (width + start_offset) / 8;
170     if (end_offset)
171       count++;
172     VGLPlane[0] = VGLBuf;
173     VGLPlane[1] = VGLPlane[0] + count;
174     VGLPlane[2] = VGLPlane[1] + count;
175     VGLPlane[3] = VGLPlane[2] + count;
176     for (i=0; i<4; i++) {
177       outb(0x3ce, 0x04);
178       outb(0x3cf, i);
179       pos = VGLAdpInfo.va_line_width*y + x/8;
180       for (width2 = count; width2 > 0; ) {
181         offset = VGLSetSegment(pos);
182         len = min(VGLAdpInfo.va_window_size - offset, width2);
183         bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len);
184         pos += len;
185         width2 -= len;
186       }
187     }
188     goto read_planar;
189   case VIDBUF4:
190     address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8;
191     start_offset = (x & 0x07);
192     end_offset = (x + width) & 0x07;
193     count = (width + start_offset) / 8;
194     if (end_offset)
195       count++;
196     VGLPlane[0] = VGLBuf;
197     VGLPlane[1] = VGLPlane[0] + count;
198     VGLPlane[2] = VGLPlane[1] + count;
199     VGLPlane[3] = VGLPlane[2] + count;
200     for (i=0; i<4; i++) {
201       outb(0x3ce, 0x04);
202       outb(0x3cf, i);
203       bcopy(address, &VGLPlane[i][0], count);
204     }
205 read_planar:
206     pos = 0;
207     planepos = 0;
208     bit = 7 - start_offset;
209     while (pos < width) {
210       for (; bit >= 0 && pos < width; bit--, pos++) {
211         line[pos] = (VGLPlane[0][planepos] & (1<<bit) ? 1 : 0) |
212                     ((VGLPlane[1][planepos] & (1<<bit) ? 1 : 0) << 1) |
213                     ((VGLPlane[2][planepos] & (1<<bit) ? 1 : 0) << 2) |
214                     ((VGLPlane[3][planepos] & (1<<bit) ? 1 : 0) << 3);
215       }
216       planepos++;
217       bit = 7;
218     }
219     break;
220   case VIDBUF8X:
221     address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
222     for (i=0; i<4; i++) {
223       outb(0x3ce, 0x04);
224       outb(0x3cf, (x + i)%4);
225       for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
226         line[pos] = address[planepos];
227       if ((x + i)%4 == 3)
228         ++address;
229     }
230     break;
231   case VIDBUF8S:
232     pos = src->VXsize * y + x;
233     while (width > 0) {
234       offset = VGLSetSegment(pos);
235       i = min(VGLAdpInfo.va_window_size - offset, width);
236       bcopy(src->Bitmap + offset, line, i);
237       line += i;
238       pos += i;
239       width -= i;
240     }
241     break;
242   case VIDBUF8:
243   case MEMBUF:
244     address = src->Bitmap + src->VXsize * y + x;
245     bcopy(address, line, width);
246     break;
247   default:
248   }
249 }
250
251 int
252 __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
253               VGLBitmap *dst, int dstx, int dsty, int width, int hight)
254 {
255   int srcline, dstline;
256
257   if (srcx>src->VXsize || srcy>src->VYsize
258         || dstx>dst->VXsize || dsty>dst->VYsize)
259     return -1;  
260   if (srcx < 0) {
261     width=width+srcx; dstx-=srcx; srcx=0;    
262   }
263   if (srcy < 0) {
264     hight=hight+srcy; dsty-=srcy; srcy=0; 
265   }
266   if (dstx < 0) {    
267     width=width+dstx; srcx-=dstx; dstx=0;
268   }
269   if (dsty < 0) {
270     hight=hight+dsty; srcy-=dsty; dsty=0;
271   }
272   if (srcx+width > src->VXsize)
273      width=src->VXsize-srcx;
274   if (srcy+hight > src->VYsize)
275      hight=src->VYsize-srcy;
276   if (dstx+width > dst->VXsize)
277      width=dst->VXsize-dstx;
278   if (dsty+hight > dst->VYsize)
279      hight=dst->VYsize-dsty;
280   if (width < 0 || hight < 0)
281      return -1;
282   if (src->Type == MEMBUF) {
283     for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
284       WriteVerticalLine(dst, dstx, dstline, width, 
285         (src->Bitmap+(srcline*src->VXsize)+srcx));
286     }
287   }
288   else if (dst->Type == MEMBUF) {
289     for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
290       ReadVerticalLine(src, srcx, srcline, width,
291          (dst->Bitmap+(dstline*dst->VXsize)+dstx));
292     }
293   }
294   else {
295     byte buffer[2048];  /* XXX */
296     byte *p;
297
298     if (width > sizeof(buffer)) {
299       p = malloc(width);
300       if (p == NULL)
301         return 1;
302     } else {
303       p = buffer;
304     }
305     for (srcline=srcy, dstline=dsty; srcline<srcy+hight; srcline++, dstline++) {
306       ReadVerticalLine(src, srcx, srcline, width, p);
307       WriteVerticalLine(dst, dstx, dstline, width, p);
308     }
309     if (width > sizeof(buffer))
310       free(p);
311   }
312   return 0;
313 }
314
315 int
316 VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
317               VGLBitmap *dst, int dstx, int dsty, int width, int hight)
318 {
319   int error;
320
321   VGLMouseFreeze(dstx, dsty, width, hight, 0);
322   error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, hight);
323   VGLMouseUnFreeze();
324   return error;
325 }
326
327 VGLBitmap
328 *VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
329 {
330   VGLBitmap *object;
331
332   if (type != MEMBUF)
333     return NULL;
334   if (xsize < 0 || ysize < 0)
335     return NULL;
336   object = (VGLBitmap *)malloc(sizeof(*object));
337   if (object == NULL)
338     return NULL;
339   object->Type = type;
340   object->Xsize = xsize;
341   object->Ysize = ysize;
342   object->VXsize = xsize;
343   object->VYsize = ysize;
344   object->Xorigin = 0;
345   object->Yorigin = 0;
346   object->Bitmap = bits;
347   return object;
348 }
349
350 void
351 VGLBitmapDestroy(VGLBitmap *object)
352 {
353   if (object->Bitmap)
354     free(object->Bitmap);
355   free(object);
356 }
357
358 int
359 VGLBitmapAllocateBits(VGLBitmap *object)
360 {
361   object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize);
362   if (object->Bitmap == NULL)
363     return -1;
364   return 0;
365 }