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