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