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