SvgaLib/gl/grlib.c

994 lines
25 KiB
C

/* Framebuffer Graphics Libary for Linux, Copyright 1993 Harm Hanemaayer */
/* grlib.c Main module */
#include <stdlib.h>
#include <stdio.h>
#include <vga.h>
#include "inlstring.h" /* include inline string operations */
#include "vgagl.h"
#include "def.h"
#include "driver.h"
/* Global variables */
#ifdef DLL_CONTEXT_SHADOW
/* The current context variable is shadowed in a read-only variable for */
/* external use. */
GraphicsContext __currentcontext; /* Internal current context. */
GraphicsContext currentcontext; /* Copy for external use. */
#else
GraphicsContext currentcontext;
#endif
void (*__svgalib_nonaccel_fillbox)(int, int, int, int, int);
static int screenoffset = 0; /* Used by copy(box)toscreen. */
/* Framebuffer function pointers */
static framebufferfunctions ff8 =
{
__svgalib_driver8_setpixel,
__svgalib_driver8_getpixel,
__svgalib_driver8_hline,
__svgalib_driver8_fillbox,
__svgalib_driver8_putbox,
__svgalib_driver8_getbox,
__svgalib_driver8_putboxmask,
__svgalib_driver8_putboxpart,
__svgalib_driver8_getboxpart,
__svgalib_driver8_copybox
};
static framebufferfunctions ff16 =
{
__svgalib_driver16_setpixel,
__svgalib_driver16_getpixel,
__svgalib_driver16_hline,
__svgalib_driver16_fillbox,
__svgalib_driver16_putbox,
__svgalib_driver16_getbox,
__svgalib_driver16_putboxmask,
__svgalib_driver16_putboxpart,
__svgalib_driver16_getboxpart,
__svgalib_driver16_copybox
};
static framebufferfunctions ff24 =
{
__svgalib_driver24_setpixel,
__svgalib_driver24_getpixel,
__svgalib_driver24_hline,
__svgalib_driver24_fillbox,
__svgalib_driver24_putbox,
__svgalib_driver24_getbox,
__svgalib_driver24_putboxmask,
__svgalib_driver24_putboxpart,
__svgalib_driver24_getboxpart,
__svgalib_driver24_copybox
};
static framebufferfunctions ff32 =
{
__svgalib_driver32_setpixel,
__svgalib_driver32_getpixel,
__svgalib_driver32_hline,
__svgalib_driver32_fillbox,
__svgalib_driver32_putbox,
__svgalib_driver32_getbox,
__svgalib_driver32_putboxmask,
__svgalib_driver32_putboxpart,
__svgalib_driver32_getboxpart,
__svgalib_driver32_copybox
};
static framebufferfunctions ff8paged =
{
__svgalib_driver8p_setpixel,
__svgalib_driver8p_getpixel,
__svgalib_driver8p_hline,
__svgalib_driver8p_fillbox,
__svgalib_driver8p_putbox,
__svgalib_driver8p_getbox,
__svgalib_driver8p_putboxmask,
__svgalib_driver8p_putboxpart,
__svgalib_driver8p_getboxpart,
__svgalib_driver8p_copybox
};
static framebufferfunctions ff16paged =
{
__svgalib_driver16p_setpixel,
__svgalib_driver16p_getpixel,
__svgalib_driver16p_hline,
__svgalib_driver16p_fillbox,
__svgalib_driver16p_putbox,
__svgalib_driver16p_getbox,
__svgalib_driver16p_putboxmask,
__svgalib_driver16p_putboxpart,
__svgalib_driver16p_getboxpart,
__svgalib_driver16p_copybox
};
static framebufferfunctions ff24paged =
{
__svgalib_driver24p_setpixel,
__svgalib_driver24p_getpixel,
__svgalib_driver24p_hline,
__svgalib_driver24p_fillbox,
__svgalib_driver24p_putbox,
__svgalib_driver24p_getbox,
__svgalib_driver24p_putboxmask,
__svgalib_driver24p_putboxpart,
__svgalib_driver24p_getboxpart,
__svgalib_driver24p_copybox
};
static framebufferfunctions ff32paged =
{
__svgalib_driver32p_setpixel,
__svgalib_driver32p_getpixel,
__svgalib_driver32p_hline,
__svgalib_driver32p_fillbox,
__svgalib_driver32p_putbox,
__svgalib_driver32p_getbox,
__svgalib_driver32p_putboxmask,
__svgalib_driver32p_putboxpart,
__svgalib_driver32p_getboxpart,
__svgalib_driver32p_copybox
};
static framebufferfunctions ffplanar256 =
{
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
__svgalib_driverplanar256_putbox,
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
(void *) __svgalib_driverplanar256_nothing,
};
#if 0 /* Not yet used */
static framebufferfunctions ffplanar16 =
{
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
(void *) __svgalib_driverplanar16_nothing,
};
#endif
/* Initialization and graphics contexts */
#define SCREENSIZE(gc) ((gc).bytewidth * (gc).height)
static int colorbits(int c)
{
switch (c) {
default:
case 256:
return 8;
case 32768:
return 15;
case 65536:
return 16;
case 256 * 65536:
return 24;
}
}
int gl_setcontextvga(int m)
{
framebufferfunctions *ff;
vga_modeinfo *modeinfo;
int accelfuncs;
if (!vga_hasmode(m))
return -1;
modeinfo = vga_getmodeinfo(m);
/* Set graphics context */
WIDTH = modeinfo->width;
HEIGHT = modeinfo->height;
BYTESPERPIXEL = modeinfo->bytesperpixel;
COLORS = modeinfo->colors;
BITSPERPIXEL = colorbits(COLORS);
BYTEWIDTH = modeinfo->linewidth;
VBUF = vga_getgraphmem();
MODEFLAGS = 0;
__clip = 0;
ff = &(__currentcontext.ff);
if (modeinfo->flags & IS_MODEX) {
/* Pretend it's a regular (linear) context. */
BYTESPERPIXEL = 1;
BYTEWIDTH *= 4;
MODETYPE = CONTEXT_MODEX;
if (BYTEWIDTH * HEIGHT * 2 <= 256 * 1024)
MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
if (BYTEWIDTH * HEIGHT * 3 <= 256 * 1024)
MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
__currentcontext.ff = ffplanar256;
} else if (modeinfo->colors == 16) {
/* Pretend it's a regular one byte per pixel context. */
BYTESPERPIXEL = 1;
BYTEWIDTH *= 8;
MODETYPE = CONTEXT_PLANAR16;
if (BYTEWIDTH * HEIGHT <= 256 * 1024)
MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
if (BYTEWIDTH * HEIGHT * 3 / 2 <= 256 * 1024)
MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
} else if ((m == G320x200x256 && modeinfo->maxpixels <= 65536) ||
(modeinfo->flags & IS_LINEAR)
#if 1 /* svgalib doesn't VT-switch correctly with linear addressing. */
|| ((modeinfo->flags & CAPABLE_LINEAR)
/* Creepy. Try linear addressing only if the mode is set. */
&& vga_getcurrentmode() == m && (vga_setlinearaddressing() != -1))
#endif
) {
/* No banking. */
/* Get get the fb address in case we set linear addressing. */
VBUF = vga_getgraphmem();
MODETYPE = CONTEXT_LINEAR;
if (modeinfo->maxpixels >= WIDTH * HEIGHT * 2)
MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
if (modeinfo->maxpixels >= WIDTH * HEIGHT * 3)
MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
switch (BYTESPERPIXEL) {
case 1:
__currentcontext.ff = ff8;
break;
case 2:
__currentcontext.ff = ff16;
break;
case 3:
__currentcontext.ff = ff24;
break;
case 4:
__currentcontext.ff = ff32;
break;
}
if (modeinfo->flags & RGB_MISORDERED)
MODEFLAGS |= MODEFLAG_32BPP_SHIFT8;
} else {
/* Banked mode. */
MODETYPE = CONTEXT_PAGED;
if (modeinfo->maxpixels >= WIDTH * HEIGHT * 2)
MODEFLAGS |= MODEFLAG_PAGEFLIPPING_CAPABLE;
if (modeinfo->maxpixels >= WIDTH * HEIGHT * 3)
MODEFLAGS |= MODEFLAG_TRIPLEBUFFERING_CAPABLE;
if ((modeinfo->startaddressrange & 0x1ffff) == 0x10000) {
/* This hack is required for 320x200x256 page flipping */
/* on Trident, which doesn't work with bank boundary */
/* within the second page. */
MODEFLAGS |= MODEFLAG_FLIPPAGE_BANKALIGNED;
}
switch (BYTESPERPIXEL) {
case 1:
__currentcontext.ff = ff8paged;
break;
case 2:
__currentcontext.ff = ff16paged;
break;
case 3:
__currentcontext.ff = ff24paged;
break;
case 4:
__currentcontext.ff = ff32paged;
break;
}
if (modeinfo->flags & RGB_MISORDERED)
MODEFLAGS |= MODEFLAG_32BPP_SHIFT8;
}
if (vga_getcurrentmode() == m) {
accelfuncs = vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_ACCEL);
__svgalib_nonaccel_fillbox = __currentcontext.ff.driver_fillbox_func;
if (accelfuncs & ACCELFLAG_FILLBOX)
__currentcontext.ff.driver_fillbox_func =
__svgalib_driver8a_fillbox;
if (accelfuncs & ACCELFLAG_SCREENCOPY)
__currentcontext.ff.driver_copybox_func =
__svgalib_driver8a_copybox;
}
#ifdef DLL_CONTEXT_SHADOW
currentcontext = __currentcontext;
#endif
return 0;
}
int gl_setcontextvgavirtual(int m)
{
vga_modeinfo *modeinfo;
if (!vga_hasmode(m))
return -1;
modeinfo = vga_getmodeinfo(m);
/* Set graphics context */
WIDTH = modeinfo->width;
HEIGHT = modeinfo->height;
if (modeinfo->flags & IS_MODEX) {
/* Use a regular virtual screen for planar 256 color modes. */
BYTESPERPIXEL = 1;
BYTEWIDTH = modeinfo->linewidth * 4;
} else if (modeinfo->colors == 16) {
/* Use a regular one byte per pixel virtual screen for */
/* planar 16 color modes. */
BYTESPERPIXEL = 1;
BYTEWIDTH = modeinfo->linewidth * 8;
} else {
BYTESPERPIXEL = modeinfo->bytesperpixel;
BYTEWIDTH = modeinfo->linewidth;
}
COLORS = modeinfo->colors;
BITSPERPIXEL = colorbits(COLORS);
VBUF = malloc(SCREENSIZE(__currentcontext));
MODETYPE = CONTEXT_VIRTUAL;
MODEFLAGS = 0;
__clip = 0;
switch (BYTESPERPIXEL) {
case 1:
__currentcontext.ff = ff8;
break;
case 2:
__currentcontext.ff = ff16;
break;
case 3:
__currentcontext.ff = ff24;
break;
case 4:
__currentcontext.ff = ff32;
break;
}
#ifdef DLL_CONTEXT_SHADOW
currentcontext = __currentcontext;
#endif
return 0;
}
void gl_setcontextvirtual(int w, int h, int bpp, int bitspp, void *v)
{
WIDTH = w;
HEIGHT = h;
BYTESPERPIXEL = bpp;
BITSPERPIXEL = bitspp;
COLORS = 1 << bitspp;
BYTEWIDTH = WIDTH * BYTESPERPIXEL;
VBUF = v;
MODETYPE = CONTEXT_VIRTUAL;
MODEFLAGS = 0;
switch (BYTESPERPIXEL) {
case 1:
__currentcontext.ff = ff8;
break;
case 2:
__currentcontext.ff = ff16;
break;
case 3:
__currentcontext.ff = ff24;
break;
case 4:
__currentcontext.ff = ff32;
break;
}
__clip = 0;
#ifdef DLL_CONTEXT_SHADOW
currentcontext = __currentcontext;
#endif
}
GraphicsContext *
gl_allocatecontext()
{
return malloc(sizeof(GraphicsContext));
}
void gl_setcontext(GraphicsContext * gc)
{
__currentcontext = *gc;
#ifdef DLL_CONTEXT_SHADOW
currentcontext = *gc;
#endif
}
void gl_getcontext(GraphicsContext * gc)
{
*gc = __currentcontext;
}
void gl_freecontext(GraphicsContext * gc)
{
if (gc->modetype == CONTEXT_VIRTUAL)
free(gc->vbuf);
}
void gl_setcontextwidth(int w)
{
__currentcontext.width = currentcontext.width = w;
__currentcontext.bytewidth = currentcontext.bytewidth =
w * BYTESPERPIXEL;
}
void gl_setcontextheight(int h)
{
__currentcontext.height = currentcontext.height = h;
}
/* Clipping */
void gl_setclippingwindow(int x1, int y1, int x2, int y2)
{
__clip = 1;
__clipx1 = x1;
__clipy1 = y1;
__clipx2 = x2;
__clipy2 = y2;
}
void gl_enableclipping()
{
__clip = 1;
__clipx1 = 0;
__clipy1 = 0;
__clipx2 = WIDTH - 1;
__clipy2 = HEIGHT - 1;
}
void gl_disableclipping()
{
__clip = 0;
}
/* Primitive functions */
void gl_setpixel(int x, int y, int c)
{
if (__clip && outside(x, y))
return;
setpixel(x, y, c);
}
int gl_getpixel(int x, int y)
{
if (__clip && outside(x, y))
return -1;
return getpixel(x, y);
}
void gl_hline(int x1, int y, int x2, int c)
{
if (__clip) {
if (y_outside(y))
return;
clipxleft(x1);
clipxright(x2);
}
if (x1 > x2)
return;
hline(x1, y, x2, c);
}
#define ADJUSTBITMAPBOX() \
nw = w; nh = h; nx = x; ny = y; \
if (nx + nw < __clipx1 || nx > __clipx2) \
return; \
if (ny + nh < __clipy1 || ny > __clipy2) \
return; \
if (nx < __clipx1) { /* left adjust */ \
nw += nx - __clipx1; \
nx = __clipx1; \
} \
if (ny < __clipy1) { /* top adjust */ \
nh += ny - __clipy1; \
ny = __clipy1; \
} \
if (nx + nw > __clipx2) /* right adjust */ \
nw = __clipx2 - nx + 1; \
if (ny + nh > __clipy2) /* bottom adjust */ \
nh = __clipy2 - ny + 1; \
void gl_fillbox(int x, int y, int w, int h, int c)
{
if (__clip) {
if (x + w < __clipx1 || x > __clipx2)
return;
if (y + h < __clipy1 || y > __clipy2)
return;
if (x < __clipx1) {
w -= __clipx1 - x;
x = __clipx1;
}
if (y < __clipy1) {
h -= __clipy1 - y;
y = __clipy1;
}
if (x + w > __clipx2 + 1)
w = __clipx2 - x + 1;
if (y + h > __clipy2 + 1)
h = __clipy2 - y + 1;
}
if (w <= 0 || h <= 0)
return;
fillbox(x, y, w, h, c);
}
void gl_putboxpart(int x, int y, int w, int h, int ow, int oh, void *b,
int ox, int oy)
{
putboxpart(x, y, w, h, ow, oh, b, ox, oy);
}
void gl_putbox(int x, int y, int w, int h, void *b)
{
uchar *bp = b;
if (w <= 0 || h <= 0)
return;
if (__clip) {
int nx, ny, nw, nh;
ADJUSTBITMAPBOX();
if (nw <= 0 || nh <= 0)
return;
if (nw != w || nh != h) {
putboxpart(nx, ny, nw, nh, w, h, bp, nx - x, ny - y);
return;
}
}
putbox(x, y, w, h, bp, w);
}
static void emulate_putboxmask(int x, int y, int w, int h, void *b)
{
void *box;
GraphicsContext gc;
box = alloca(w * h * BYTESPERPIXEL);
gl_getbox(x, y, w, h, box); /* does clipping */
gl_getcontext(&gc); /* save context */
/* create context that is only the box */
gl_setcontextvirtual(w, h, BYTESPERPIXEL, BITSPERPIXEL, box);
gl_putboxmask(0, 0, w, h, b);
gl_setcontext(&gc); /* restore context */
gl_putbox(x, y, w, h, box);
}
void gl_putboxmask(int x, int y, int w, int h, void *b)
{
if (w <= 0 || h <= 0)
return;
if (__clip) {
if (x + w < __clipx1 || x > __clipx2)
return;
if (y + h < __clipy1 || y > __clipy2)
return;
if (x < __clipx1 || y < __clipy1
|| x + w > __clipx2 + 1 || y + h > __clipy2 + 1) {
/* clipping is not directly implemented */
emulate_putboxmask(x, y, w, h, b);
return;
}
}
if (MODETYPE == CONTEXT_PAGED)
/* paged primitive is not implemented */
emulate_putboxmask(x, y, w, h, b);
else
putboxmask(x, y, w, h, b);
}
void gl_getbox(int x, int y, int w, int h, void *b)
{
if (__clip) {
int nx, ny, nw, nh;
ADJUSTBITMAPBOX();
if (nw <= 0 || nh <= 0)
return;
if (nw != w || nh != h) {
getboxpart(nx, ny, nw, nh, w, h, b, nx - x, ny - y);
return;
}
}
getbox(x, y, w, h, b, w);
}
void gl_copybox(int x1, int y1, int w, int h, int x2, int y2)
{
/* Doesn't handle clipping. */
if (MODETYPE == CONTEXT_PAGED) {
/* Paged primitive is not implemented. */
void *box;
box = alloca(w * h * BYTESPERPIXEL);
getbox(x1, y1, w, h, box, w);
putbox(x2, y2, w, h, box, w);
return;
}
copybox(x1, y1, w, h, x2, y2);
}
/* Miscellaneous functions */
void gl_clearscreen(int c)
{
gl_fillbox(0, 0, WIDTH, HEIGHT, c);
}
int gl_rgbcolor(int r, int g, int b)
{
unsigned v;
switch (BITSPERPIXEL) {
case 8:
/* assumes RGB palette at index 0-255 */
/* bits 0-2 = blue (3 bits) */
/* 3-5 = green (3 bits) */
/* 6-7 = red (2 bits) */
return (r & 0xc0) + ((g & 0xe0) >> 2) + (b >> 5);
case 24:
case 32:
v = (r << 16) + (g << 8) + b;
if (MODEFLAGS & MODEFLAG_32BPP_SHIFT8)
return v << 8;
return v;
case 15:
return ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + (b >> 3);
case 16:
return ((r & 0xf8) << 8) + ((g & 0xfc) << 3) + (b >> 3);
case 4:
/* Now this is real fun. Map to standard EGA palette. */
v = 0;
if (b >= 64)
v += 1;
if (g >= 64)
v += 2;
if (r >= 64)
v += 4;
if (b >= 192 || g >= 192 || r >= 192)
v += 8;
return v;
}
return -1;
}
void gl_setpixelrgb(int x, int y, int r, int g, int b)
{
/* Color components range from 0 to 255 */
if (__clip && outside(x, y))
return;
setpixel(x, y, gl_rgbcolor(r, g, b));
}
void gl_getpixelrgb(int x, int y, int *r, int *g, int *b)
{
unsigned c;
if (__clip && outside(x, y)) {
*r = *g = *b = -1;
return;
}
c = getpixel(x, y);
switch (BITSPERPIXEL) {
case 8:
*b = (c & (1 + 2 + 4)) << 5; /* bits 0-2 */
*g = (c & (8 + 16 + 32)) << 2; /* bits 3-5 */
*r = (c & (64 + 128)); /* bits 6-7 */
break;
case 32:
if (MODEFLAGS & MODEFLAG_32BPP_SHIFT8) {
*b = (c & 0xff00) >> 8;
*g = (c & 0xff0000) >> 16;
*r = c >> 24;
break;
}
case 24:
*b = c & 0xff;
*g = (c & 0xff00) >> 8;
*r = c >> 16;
break;
case 15:
*b = (c & (1 + 2 + 4 + 8 + 16)) << 3;
*g = (c & (32 + 64 + 128 + 256 + 512)) >> 2;
*r = (c & (1024 + 2048 + 4096 + 8192 + 16384)) >> 7;
break;
case 16:
*b = (c & (1 + 2 + 4 + 8 + 16)) << 3;
*g = (c & (32 + 64 + 128 + 256 + 512 + 1024)) >> 3;
*r = (c & (2048 + 4096 + 8192 + 16384 + 32768)) >> 8;
break;
case 4:
*b = (c & 1) * ((c & 8) ? 255 : 128);
*g = (c & 2) * ((c & 8) ? 255 : 128);
*r = (c & 4) * ((c & 8) ? 255 : 128);
break;
}
}
void gl_setdisplaystart(int x, int y)
{
vga_setdisplaystart(y * BYTEWIDTH + x * BYTESPERPIXEL);
}
/* Screen copying */
void gl_setscreenoffset(int o)
{
screenoffset = o;
}
int gl_enablepageflipping(GraphicsContext * gc)
{
if (gc->modeflags & MODEFLAG_PAGEFLIPPING_CAPABLE) {
gc->modeflags |= MODEFLAG_PAGEFLIPPING_ENABLED;
}
if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_CAPABLE) {
gc->modeflags &= ~(MODEFLAG_PAGEFLIPPING_ENABLED);
gc->modeflags |= MODEFLAG_TRIPLEBUFFERING_ENABLED;
}
gc->flippage = 0;
if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_ENABLED)
return 3;
if (gc->modeflags & MODEFLAG_PAGEFLIPPING_ENABLED)
return 2;
return 0;
}
void gl_copyscreen(GraphicsContext * gc)
{
int size;
void *svp, *dvp;
if (gc->modeflags & MODEFLAG_PAGEFLIPPING_ENABLED)
gc->flippage ^= 1;
if (gc->modeflags & MODEFLAG_TRIPLEBUFFERING_ENABLED)
gc->flippage = (gc->flippage + 1) % 3;
if (gc->modeflags & (MODEFLAG_PAGEFLIPPING_ENABLED |
MODEFLAG_TRIPLEBUFFERING_ENABLED)) {
/* Calculate screen offset in bytes. */
screenoffset = gc->bytewidth * HEIGHT * gc->flippage;
if (gc->modeflags & MODEFLAG_FLIPPAGE_BANKALIGNED)
screenoffset = ((screenoffset + 0xffff) & ~0xffff);
}
if (gc->modetype == CONTEXT_MODEX) {
vga_copytoplanar256(VBUF, BYTEWIDTH, screenoffset / 4,
gc->bytewidth / 4, WIDTH, HEIGHT);
goto end;
}
if (gc->modetype == CONTEXT_PLANAR16) {
if (WIDTH == 1024 && HEIGHT >= 512 &&
((screenoffset / 8) & 0xffff) == 0) {
/* Kludge to allow 1024x768x16 with page flipping. */
int page;
page = (screenoffset / 8) >> 16;
vga_setpage(page);
vga_copytoplanar16(VBUF, BYTEWIDTH, 0,
gc->bytewidth / 8, WIDTH, 512);
vga_setpage(page + 1);
vga_copytoplanar16(VBUF + WIDTH * 512, BYTEWIDTH,
0, gc->bytewidth / 8, WIDTH, HEIGHT - 512);
return;
}
if (WIDTH * HEIGHT >= 512 * 1024)
/* We don't handle banking. */
return;
vga_copytoplanar16(VBUF, BYTEWIDTH, screenoffset / 8,
gc->bytewidth / 8, WIDTH, HEIGHT);
goto end;
}
if (BYTESPERPIXEL == 4 && gc->bytesperpixel == 3) {
/* Special case. */
int soffset, doffset;
if (BYTEWIDTH / 4 != gc->bytewidth / 3) {
/* Even more special case for physical truecolor */
/* modes that have extra scanline padding. */
/* This has the effect of slowing down */
/* '3d' in some truecolor modes on ATI mach32. */
gl_copyboxtocontext(0, 0, WIDTH, HEIGHT, gc, 0, 0);
goto end;
}
soffset = 0;
doffset = screenoffset;
size = WIDTH * HEIGHT;
while (soffset / 4 < size) {
int schunk, dchunk;
int count;
schunk = __svgalib_driver_setread(&__currentcontext, soffset, &svp);
dchunk = __svgalib_driver_setwrite(gc, doffset, &dvp);
if (dchunk == 1) {
/* One byte left in segment. */
int pix;
pix = *(unsigned *) svp; /* 32-bit pixel */
*(unsigned char *) dvp = pix;
dchunk = __svgalib_driver_setwrite(gc, doffset + 1, &dvp);
*(unsigned short *) dvp = pix >> 8;
count = 1; /* 1 pixel handled. */
} else if (dchunk == 2) {
/* Two bytes left. */
int pix;
pix = *(unsigned *) svp; /* 32-bit pixel */
*(unsigned short *) dvp = pix;
dchunk = __svgalib_driver_setwrite(gc, doffset + 2, &dvp);
*(unsigned char *) dvp = pix >> 16;
count = 1; /* 1 pixel handled. */
} else {
count = min(min(schunk / 4, dchunk / 3),
size - (soffset / 4));
__svgalib_memcpy4to3(dvp, svp, count);
}
soffset += count * 4;
doffset += count * 3;
}
goto end;
}
if (BYTESPERPIXEL == 4 && gc->bytesperpixel == 4 &&
(gc->modeflags & MODEFLAG_32BPP_SHIFT8)) {
int soffset = 0;
int doffset = screenoffset;
size = SCREENSIZE(__currentcontext);
while (soffset < size) {
int schunk, dchunk;
int count;
schunk = __svgalib_driver_setread(&__currentcontext, soffset, &svp);
dchunk = __svgalib_driver_setwrite(gc, doffset, &dvp);
count = min(min(schunk, dchunk), (size - soffset));
__svgalib_memcpy32shift8(dvp, svp, count / 4);
soffset += count;
doffset += count;
}
} else {
int soffset = 0;
int doffset = screenoffset;
size = SCREENSIZE(__currentcontext);
while (soffset < size) {
int schunk, dchunk;
int count;
schunk = __svgalib_driver_setread(&__currentcontext, soffset, &svp);
dchunk = __svgalib_driver_setwrite(gc, doffset, &dvp);
count = min(min(schunk, dchunk), (size - soffset));
__memcpy(dvp, svp, count);
soffset += count;
doffset += count;
}
}
end:
if (gc->modeflags & (MODEFLAG_PAGEFLIPPING_ENABLED |
MODEFLAG_TRIPLEBUFFERING_ENABLED)) {
GraphicsContext save;
/* setdisplaystart will use BYTEWIDTH of the virtual screen, */
/* which is what we want since vga_setdisplaystart is */
/* defined in terms of pixel offset (except for hicolor */
/* modes, which are defined in terms of bytes). */
gl_getcontext(&save);
gl_setcontext(gc);
if (gc->modeflags & MODEFLAG_FLIPPAGE_BANKALIGNED)
vga_setdisplaystart(screenoffset);
else
gl_setdisplaystart(0, gc->height * gc->flippage);
gl_setcontext(&save);
/* For page flipping, it might be appropriate to add a */
/* waitverticalretrace here. */
}
screenoffset = 0;
}
void gl_copyboxtocontext(int x1, int y1, int w, int h, GraphicsContext * gc,
int x2, int y2)
{
/* This is now reasonably efficient if clipping is not enabled. */
void *buf;
GraphicsContext save;
gl_getcontext(&save);
if ((MODETYPE == CONTEXT_LINEAR || MODETYPE == CONTEXT_VIRTUAL) &&
(BYTESPERPIXEL == gc->bytesperpixel) &&
!__clip && !gc->clip) {
#ifdef DLL_CONTEXT_SHADOW
__currentcontext = *gc;
#else
gl_setcontext(gc);
#endif
/*
* Note: Using save.bytewidth / BYTESPERPIXEL is probably not an optimal hack here.
* it would be better to transfer save.bytewidth to putbox as it is what is really
* used there. However, putbox is used all over interpreting the last entry as a
* pixel count, so we keep it this way to avoid problems if some other place not
* updated by accident.
*/
putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, save.vbuf +
y1 * save.bytewidth + x1 * BYTESPERPIXEL,
save.bytewidth / BYTESPERPIXEL);
goto end;
}
buf = alloca(w * h * BYTESPERPIXEL);
gl_getbox(x1, y1, w, h, buf);
#ifdef DLL_CONTEXT_SHADOW
__currentcontext = *gc;
#else
gl_setcontext(gc);
#endif
if (save.bytesperpixel == 4 && gc->bytesperpixel == 3) {
/* Special case conversion from 32-bit virtual screen to */
/* 24-bit truecolor framebuffer. */
if (gc->modetype == CONTEXT_PAGED || gc->clip) {
/* For paged modes or clipping, use another buffer. */
void *buf2;
buf2 = alloca(w * h * 3);
__svgalib_memcpy4to3(buf2, buf, w * h);
gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h,
buf2);
} else
/* No clipping, linear. */
__svgalib_driver24_putbox32(x2, y2, w, h, buf, w);
} else /* Contexts assumed to have same pixel size. */
gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, buf);
end:
#ifdef DLL_CONTEXT_SHADOW
__currentcontext = save;
#else
gl_setcontext(&save);
#endif
}
void gl_copyboxfromcontext(GraphicsContext * gc, int x1, int y1, int w, int h,
int x2, int y2)
{
void *buf;
GraphicsContext save;
if ((gc->modetype == CONTEXT_LINEAR || gc->modetype == CONTEXT_VIRTUAL) &&
(BYTESPERPIXEL == gc->bytesperpixel) &&
!__clip && !gc->clip) {
/*
* see above on gc->bytewidth / BYTESPERPIXEL.
*/
putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, gc->vbuf +
y1 * gc->bytewidth + x1 * BYTESPERPIXEL,
gc->bytewidth / BYTESPERPIXEL);
return;
}
gl_getcontext(&save);
#ifdef DLL_CONTEXT_SHADOW
__currentcontext = *gc;
#else
gl_setcontext(gc);
#endif
buf = alloca(w * h * BYTESPERPIXEL);
gl_getbox(x1, y1, w, h, buf);
#ifdef DLL_CONTEXT_SHADOW
__currentcontext = save;
#else
gl_setcontext(&save);
#endif
if (gc->bytesperpixel == 4 && save.bytesperpixel == 3) {
/* Special case conversion from 32-bit virtual screen to */
/* 24-bit truecolor framebuffer. */
if (save.modetype == CONTEXT_PAGED || save.clip) {
/* For paged modes or clipping, use another buffer. */
void *buf2;
buf2 = alloca(w * h * 3);
__svgalib_memcpy4to3(buf2, buf, w * h);
gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h,
buf2);
} else
/* No clipping, linear. */
__svgalib_driver24_putbox32(x2, y2, w, h, buf, w);
} else /* Contexts assumed to have same pixel size. */
gl_putbox(x2, y2 + screenoffset / BYTEWIDTH, w, h, buf);
}