1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991-1997 S��ren Schmidt
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer,
12 *    in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/types.h>
32#include <signal.h>
33#include <sys/fbio.h>
34#include "vgl.h"
35
36#define min(x, y)	(((x) < (y)) ? (x) : (y))
37
38static byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
39static int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101,
40			    0x00010000, 0x00010001, 0x00010100, 0x00010101,
41			    0x01000000, 0x01000001, 0x01000100, 0x01000101,
42			    0x01010000, 0x01010001, 0x01010100, 0x01010101};
43
44static void
45WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line)
46{
47  int bwidth, 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    bwidth = (width + start_offset) / 8;
59    if (end_offset)
60	bwidth++;
61    VGLPlane[0] = VGLBuf;
62    VGLPlane[1] = VGLPlane[0] + bwidth;
63    VGLPlane[2] = VGLPlane[1] + bwidth;
64    VGLPlane[3] = VGLPlane[2] + bwidth;
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    outb(0x3ce, 0x01); outb(0x3cf, 0x00);		/* set/reset enable */
88    outb(0x3ce, 0x08); outb(0x3cf, 0xff);		/* bit mask */
89    for (i=0; i<4; i++) {
90      outb(0x3c4, 0x02);
91      outb(0x3c5, 0x01<<i);
92      outb(0x3ce, 0x04);
93      outb(0x3cf, i);
94      pos = VGLAdpInfo.va_line_width*y + x/8;
95      if (dst->Type == VIDBUF4) {
96	if (end_offset)
97	  VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset];
98	if (start_offset)
99	  VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset];
100	bcopy(&VGLPlane[i][0], dst->Bitmap + pos, bwidth);
101      } else {	/* VIDBUF4S */
102	if (end_offset) {
103	  offset = VGLSetSegment(pos + planepos);
104	  VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset];
105	}
106	offset = VGLSetSegment(pos);
107	if (start_offset)
108	  VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset];
109	for (last = bwidth; ; ) {
110	  len = min(VGLAdpInfo.va_window_size - offset, last);
111	  bcopy(&VGLPlane[i][bwidth - last], dst->Bitmap + offset, len);
112	  pos += len;
113	  last -= len;
114	  if (last <= 0)
115	    break;
116	  offset = VGLSetSegment(pos);
117	}
118      }
119    }
120    break;
121  case VIDBUF8X:
122    address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4;
123    for (i=0; i<4; i++) {
124      outb(0x3c4, 0x02);
125      outb(0x3c5, 0x01 << ((x + i)%4));
126      for (planepos=0, pos=i; pos<width; planepos++, pos+=4)
127        address[planepos] = line[pos];
128      if ((x + i)%4 == 3)
129	++address;
130    }
131    break;
132  case VIDBUF8S:
133  case VIDBUF16S:
134  case VIDBUF24S:
135  case VIDBUF32S:
136    width = width * dst->PixelBytes;
137    pos = (dst->VXsize * y + x) * dst->PixelBytes;
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 MEMBUF:
148  case VIDBUF8:
149  case VIDBUF16:
150  case VIDBUF24:
151  case VIDBUF32:
152    address = dst->Bitmap + (dst->VXsize * y + x) * dst->PixelBytes;
153    bcopy(line, address, width * dst->PixelBytes);
154    break;
155  default:
156    ;
157  }
158}
159
160int
161__VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
162	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
163{
164  byte *buffer, *p;
165  int mousemerge, srcline, dstline, yend, yextra, ystep;
166
167  mousemerge = 0;
168  if (hight < 0) {
169    hight = -hight;
170    mousemerge = (dst == VGLDisplay &&
171		  VGLMouseOverlap(dstx, dsty, width, hight));
172    if (mousemerge)
173      buffer = alloca(width*src->PixelBytes);
174  }
175  if (srcx>src->VXsize || srcy>src->VYsize
176	|| dstx>dst->VXsize || dsty>dst->VYsize)
177    return -1;
178  if (srcx < 0) {
179    width=width+srcx; dstx-=srcx; srcx=0;
180  }
181  if (srcy < 0) {
182    hight=hight+srcy; dsty-=srcy; srcy=0;
183  }
184  if (dstx < 0) {
185    width=width+dstx; srcx-=dstx; dstx=0;
186  }
187  if (dsty < 0) {
188    hight=hight+dsty; srcy-=dsty; dsty=0;
189  }
190  if (srcx+width > src->VXsize)
191     width=src->VXsize-srcx;
192  if (srcy+hight > src->VYsize)
193     hight=src->VYsize-srcy;
194  if (dstx+width > dst->VXsize)
195     width=dst->VXsize-dstx;
196  if (dsty+hight > dst->VYsize)
197     hight=dst->VYsize-dsty;
198  if (width < 0 || hight < 0)
199     return -1;
200  yend = srcy + hight;
201  yextra = 0;
202  ystep = 1;
203  if (src->Bitmap == dst->Bitmap && srcy < dsty) {
204    yend = srcy - 1;
205    yextra = hight - 1;
206    ystep = -1;
207  }
208  for (srcline = srcy + yextra, dstline = dsty + yextra; srcline != yend;
209       srcline += ystep, dstline += ystep) {
210    p = src->Bitmap+(srcline*src->VXsize+srcx)*dst->PixelBytes;
211    if (mousemerge && VGLMouseOverlap(dstx, dstline, width, 1)) {
212      bcopy(p, buffer, width*src->PixelBytes);
213      p = buffer;
214      VGLMouseMerge(dstx, dstline, width, p);
215    }
216    WriteVerticalLine(dst, dstx, dstline, width, p);
217  }
218  return 0;
219}
220
221int
222VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy,
223	      VGLBitmap *dst, int dstx, int dsty, int width, int hight)
224{
225  int error;
226
227  if (hight < 0)
228    return -1;
229  if (src == VGLDisplay)
230    src = &VGLVDisplay;
231  if (src->Type != MEMBUF)
232    return -1;		/* invalid */
233  if (dst == VGLDisplay) {
234    VGLMouseFreeze();
235    __VGLBitmapCopy(src, srcx, srcy, &VGLVDisplay, dstx, dsty, width, hight);
236    error = __VGLBitmapCopy(src, srcx, srcy, &VGLVDisplay, dstx, dsty,
237                            width, hight);
238    if (error != 0)
239      return error;
240    src = &VGLVDisplay;
241    srcx = dstx;
242    srcy = dsty;
243  } else if (dst->Type != MEMBUF)
244    return -1;		/* invalid */
245  error = __VGLBitmapCopy(src, srcx, srcy, dst, dstx, dsty, width, -hight);
246  if (dst == VGLDisplay)
247    VGLMouseUnFreeze();
248  return error;
249}
250
251VGLBitmap
252*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits)
253{
254  VGLBitmap *object;
255
256  if (type != MEMBUF)
257    return NULL;
258  if (xsize < 0 || ysize < 0)
259    return NULL;
260  object = (VGLBitmap *)malloc(sizeof(*object));
261  if (object == NULL)
262    return NULL;
263  object->Type = type;
264  object->Xsize = xsize;
265  object->Ysize = ysize;
266  object->VXsize = xsize;
267  object->VYsize = ysize;
268  object->Xorigin = 0;
269  object->Yorigin = 0;
270  object->Bitmap = bits;
271  object->PixelBytes = VGLDisplay->PixelBytes;
272  return object;
273}
274
275void
276VGLBitmapDestroy(VGLBitmap *object)
277{
278  if (object->Bitmap)
279    free(object->Bitmap);
280  free(object);
281}
282
283int
284VGLBitmapAllocateBits(VGLBitmap *object)
285{
286  object->Bitmap = malloc(object->VXsize*object->VYsize*object->PixelBytes);
287  if (object->Bitmap == NULL)
288    return -1;
289  return 0;
290}
291
292void
293VGLBitmapCvt(VGLBitmap *src, VGLBitmap *dst)
294{
295  u_long color;
296  int dstpos, i, pb, size, srcpb, srcpos;
297
298  size = src->VXsize * src->VYsize;
299  srcpb = src->PixelBytes;
300  if (srcpb <= 0)
301    srcpb = 1;
302  pb = dst->PixelBytes;
303  if (pb == srcpb) {
304    bcopy(src->Bitmap, dst->Bitmap, size * pb);
305    return;
306  }
307  if (srcpb != 1)
308    return;		/* not supported */
309  for (srcpos = dstpos = 0; srcpos < size; srcpos++) {
310    color = VGLrgb332ToNative(src->Bitmap[srcpos]);
311    for (i = 0; i < pb; i++, color >>= 8)
312        dst->Bitmap[dstpos++] = color;
313  }
314}
315