home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC-Online 1996 May
/
PCOnline_05_1996.bin
/
linux
/
source
/
contrib
/
seejpeg
/
seejpeg-.4
/
seejpeg-
/
seejpeg-1.4.3
/
display.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-05
|
14KB
|
537 lines
/*
* display.c
*
* Copyright (C) 1993, 1994 Evan Harris
*
* Permission is granted to freely redistribute and modify this code,
* providing the author(s) get credit for having written it.
*/
/*
* (Evan) PIX_ALIGN changes inspired by Michael Weller, who patched against
* version 1.1:
*
* Patched to not depend on illegal assumptions (xbytes==bytesperpixel*xdim),
* to obey logical_width a multiple of 8 pixels (not bytes)
* to let logical_width be an even higher multiple of a power of two
* for spike free video signal on Mach32
* 16. 3. 94 Michael Weller (eowmob@exp-math.uni-essen.de or
* eowmob@pollux.exp-math.uni-essen.de or mat42b@vm.hrz.uni-essen.de or
* mat42b@de0hrz1a.bitnet) (svgalib, mach32-driver)
*/
#include "seejpeg.h"
#include <string.h>
#include <unistd.h>
#include <vga.h>
/*
* Set PIX_ALIGN to be 64 because it seems to be a nice safe value.
* Some cards can handle values much lower (which is desirable).
* If your card can I would recommend trying values of 8, 16 or 32
* before 64 (in the Makefile).
* My CLGD5426 works correctly with a value of 8.
*/
#ifndef PIX_ALIGN
#define PIX_ALIGN 64
#endif
struct best_mode_struct {
int min_width;
int min_height;
int mode;
int mode_width;
int mode_height;
int mode_depth;
};
static struct best_mode_struct best_mode_256[] = {
{ 1024, 768, G1280x1024x256, 1280, 1024, 256 },
{ 800, 600, G1024x768x256, 1024, 768, 256 },
{ 640, 480, G800x600x256, 800, 600, 256 },
#if 0
{ 360, 480, G640x480x256, 640, 480, 256 },
/* we currently can't cope with the planar video modes */
{ 320, 400, G360x480x256, 360, 480, 256 },
{ 320, 240, G320x400x256, 320, 400, 256 },
{ 320, 200, G320x240x256, 320, 240, 256 },
#else
{ 320, 200, G640x480x256, 640, 480, 256 },
#endif
{ 0, 0, G320x200x256, 320, 200, 256 },
};
static struct best_mode_struct best_mode_32k16m[] = {
{ 1024, 768, G1280x1024x16M, 1280, 1024, 16777216 },
{ 1024, 768, G1280x1024x32K, 1280, 1024, 32768 },
{ 800, 600, G1024x768x16M, 1024, 768, 16777216 },
{ 800, 600, G1024x768x32K, 1024, 768, 32768 },
{ 640, 480, G800x600x16M, 800, 600, 16777216 },
{ 640, 480, G800x600x32K, 800, 600, 32768 },
{ 320, 200, G640x480x16M, 640, 480, 16777216 },
{ 320, 200, G640x480x32K, 640, 480, 32768 },
{ 1, 1, G320x200x16M, 320, 200, 16777216 },
{ 0, 0, G320x200x32K, 320, 200, 32768 },
};
static int logical_width, logical_height;
static int logical_byte_width, bytesperpixel;
static int mode_width, mode_height, mode_depth, start_row, mode_linewidth;
/*
* Select the best video mode for the current video card.
*
* components: 3 for RGB, 1 for grayscale or colourmapped
*/
int
best_mode(int width, int height, int components)
{
int mode, i;
#ifndef NO_32K_CASCADE
vga_modeinfo *vgainfo;
int bytesperpixel, logical_byte_width, logical_width, logical_height;
#endif
if (opt_forcemode != TEXT) {
if (vga_hasmode(opt_forcemode)) {
if (components == 1) {
i = 0;
do {
if (best_mode_256[i].mode == opt_forcemode) {
mode_width = best_mode_256[i].mode_width;
mode_height = best_mode_256[i].mode_height;
mode_depth = best_mode_256[i].mode_depth;
return opt_forcemode;
}
} while (best_mode_256[i++].min_width > 0);
} else if (components == 3) {
i = 0;
do {
if (best_mode_32k16m[i].mode == opt_forcemode) {
mode_width = best_mode_32k16m[i].mode_width;
mode_height = best_mode_32k16m[i].mode_height;
mode_depth = best_mode_32k16m[i].mode_depth;
return opt_forcemode;
}
} while (best_mode_32k16m[i++].min_width > 0);
}
error_exit("Selected mode not supported for this image type");
} else {
error_exit("Selected mode not supported by chipset");
}
}
mode = TEXT;
if (components == 1) {
i = 0;
do {
if ((opt_fuzz * width > best_mode_256[i].min_width
|| (opt_fuzz * height > best_mode_256[i].min_height
&& !opt_widthonly))
&& vga_hasmode(best_mode_256[i].mode)) {
mode = best_mode_256[i].mode;
mode_width = best_mode_256[i].mode_width;
mode_height = best_mode_256[i].mode_height;
mode_depth = best_mode_256[i].mode_depth;
}
} while (mode == TEXT && best_mode_256[i++].min_width > 0);
if (mode == TEXT) {
error_exit("Cannot find a 256 colour video mode");
}
} else if (components == 3) {
i = 0;
do {
if ((opt_fuzz * width > best_mode_32k16m[i].min_width
|| (opt_fuzz * height > best_mode_32k16m[i].min_height
&& !opt_widthonly))
&& vga_hasmode(best_mode_32k16m[i].mode)) {
mode = best_mode_32k16m[i].mode;
mode_width = best_mode_32k16m[i].mode_width;
mode_height = best_mode_32k16m[i].mode_height;
mode_depth = best_mode_32k16m[i].mode_depth;
#ifndef NO_32K_CASCADE
vgainfo = vga_getmodeinfo(mode);
bytesperpixel = vgainfo->bytesperpixel;
mode_linewidth = vgainfo->linewidth;
logical_byte_width =
MAX(mode_linewidth, width * bytesperpixel);
if (logical_byte_width % PIX_ALIGN != 0) {
logical_byte_width +=
PIX_ALIGN - logical_byte_width % PIX_ALIGN;
}
if (logical_byte_width % (bytesperpixel * PIX_ALIGN) != 0) {
logical_byte_width += (bytesperpixel * PIX_ALIGN)
- logical_byte_width % (bytesperpixel * PIX_ALIGN);
}
logical_width = logical_byte_width / bytesperpixel;
logical_height = MIN(vgainfo->maxpixels * bytesperpixel / logical_byte_width, height);
if (height > logical_height && mode_depth == 16777216) {
mode = TEXT; /* assume a 32k mode will be available */
}
#endif
}
} while (mode == TEXT && best_mode_32k16m[i++].min_width > 0);
if (mode == TEXT) {
error_exit("Cannot find a 32K/16M colour video mode");
}
} else {
error_exit("Cannot cope with number of output components");
}
return mode;
}
void
clear_screen(int mode_width, int mode_height,
int logical_width, int logical_height)
{
int line, lines;
vga_screenoff();
/* it's done by vga_setmode() but it can't hurt */
vga_clear();
vga_setpalette(0, 0, 0, 0);
vga_setcolor(0);
logical_height = MAX(logical_height, mode_height);
/* fillblit is much better, but it's not general */
if ((logical_width * logical_height + mode_width - 1) / mode_width
> mode_height) {
lines = ((logical_width * logical_height + mode_width - 1) / mode_width
- mode_height);
for (line = mode_height; line < mode_height + lines; line++) {
vga_drawline(0, line, mode_width, line);
}
}
vga_screenon();
}
/* ----------------------------------------------------------------- */
void
display_init(int image_width, int image_height, int components)
{
int mode; /* our video mode */
int width, height;
vga_modeinfo *vgainfo;
width = (opt_doublex ? 2 * image_width : image_width);
height = (opt_doubley ? 2 * image_height : image_height);
mode = best_mode(width, height, components);
vgainfo = vga_getmodeinfo(mode);
bytesperpixel = vgainfo->bytesperpixel;
mode_linewidth = vgainfo->linewidth;
logical_byte_width = MAX(mode_linewidth, width * bytesperpixel);
if (logical_byte_width % PIX_ALIGN != 0) {
logical_byte_width += PIX_ALIGN - logical_byte_width % PIX_ALIGN;
}
/*
* I don't really understand why we need this.
* I wonder if it's documented somewhere...
*
* (Michael, Mach32): well some cards want multiples of 8pixels in a row..
* it is that easy..
*/
if (logical_byte_width % (bytesperpixel * PIX_ALIGN) != 0) {
logical_byte_width += (bytesperpixel * PIX_ALIGN)
- logical_byte_width % (bytesperpixel * PIX_ALIGN);
}
while (logical_byte_width / bytesperpixel
> vgainfo->maxpixels / mode_height) {
logical_byte_width -= bytesperpixel * PIX_ALIGN;
}
logical_width = logical_byte_width / bytesperpixel;
logical_height =
MIN(vgainfo->maxpixels * bytesperpixel / logical_byte_width, height);
if (opt_verbose) {
printf("Image : %dx%dx%d\n", image_width, image_height,
1 << (8 * components));
printf("Mode : %dx%dx%d\n", mode_width, mode_height, mode_depth);
printf("Logical: %dx%d\n", logical_width, logical_height);
}
#ifdef BUG_WORKAROUND
vga_setmode(TEXT);
#endif
if (vga_getcurrentmode() != mode) {
vga_setmode(mode);
}
vga_setdisplaystart(0);
vga_setlogicalwidth(logical_byte_width);
start_row = 0;
clear_screen(mode_width, mode_height, logical_width, logical_height);
}
void
display_set_palette(int num_colors, JSAMPARRAY colormap, int components)
{
int i;
for (i = 0; i < num_colors; i++) {
/* we should put these in an array so there's only one syscall */
if (components == 1) {
vga_setpalette(i, GETJSAMPLE(colormap[0][i]) >> 2,
GETJSAMPLE(colormap[0][i]) >> 2,
GETJSAMPLE(colormap[0][i]) >> 2);
} else if (components == 3) {
vga_setpalette(i, GETJSAMPLE(colormap[0][i]) >> 2,
GETJSAMPLE(colormap[1][i]) >> 2,
GETJSAMPLE(colormap[2][i]) >> 2);
} else {
error_exit("Cannot cope with number of colour components");
}
}
}
void
display_set_greyscale_palette()
{
int i;
for (i = 0; i < 256; i++) {
vga_setpalette(i, i >> 2, i >> 2, i >> 2);
}
}
void
display_rows(int num_rows, JSAMPIMAGE pixel_data, int image_width,
int components)
{
JSAMPROW ptr0, ptr1, ptr2;
int row, col;
int width, height;
int mode_row, mode_col;
if (opt_doublex) {
width = MIN(image_width, logical_width / 2);
} else {
width = MIN(image_width, logical_width);
}
if (start_row < logical_height) {
if (logical_height < start_row + num_rows) {
height = logical_height - start_row;
} else {
height = num_rows;
}
} else {
start_row += num_rows;
return;
}
if (components == 1) {
for (row = 0; row < height; row++) {
mode_row = (((start_row + row) * logical_byte_width)
/ mode_linewidth);
mode_col = ((((start_row + row) * logical_byte_width)
% mode_linewidth) / bytesperpixel);
ptr0 = pixel_data[0][row];
/*
* Duplicated code so we only do an unnecessary test per line
* rather than per pixel.
*/
if (opt_doublex) {
for (col = 0; col < width; col++) {
vga_setcolor(GETJSAMPLE(*ptr0++));
vga_drawpixel(mode_col++, mode_row);
vga_drawpixel(mode_col++, mode_row);
if (mode_col == mode_width) {
mode_col = 0;
mode_row++;
}
}
} else {
for (col = 0; col < width; col++) {
vga_setcolor(GETJSAMPLE(*ptr0++));
vga_drawpixel(mode_col++, mode_row);
if (mode_col == mode_width) {
mode_col = 0;
mode_row++;
}
}
}
}
} else {
for (row = 0; row < height; row++) {
mode_row = (((start_row + row) * logical_byte_width)
/ mode_linewidth);
mode_col = ((((start_row + row) * logical_byte_width)
% mode_linewidth) / bytesperpixel);
ptr0 = pixel_data[0][row];
ptr1 = pixel_data[1][row];
ptr2 = pixel_data[2][row];
/*
* Duplicated code so we only do an unnecessary test per line
* rather than per pixel.
*/
if (opt_doublex) {
for (col = 0; col < width; col++) {
/* the slowest known solution... */
if (mode_depth == 32768) {
vga_setcolor(((GETJSAMPLE(*ptr0++) & 0xf8) << 7)
| ((GETJSAMPLE(*ptr1++) & 0xf8) << 2)
| (GETJSAMPLE(*ptr2++) >> 3));
} else {
vga_setcolor((GETJSAMPLE(*ptr0++) << 16)
| (GETJSAMPLE(*ptr1++) << 8)
| GETJSAMPLE(*ptr2++));
}
vga_drawpixel(mode_col++, mode_row);
vga_drawpixel(mode_col++, mode_row);
if (mode_col == mode_width) {
mode_col = 0;
mode_row++;
}
}
} else {
for (col = 0; col < width; col++) {
/* the slowest known solution... */
if (mode_depth == 32768) {
vga_setcolor(((GETJSAMPLE(*ptr0++) & 0xf8) << 7)
| ((GETJSAMPLE(*ptr1++) & 0xf8) << 2)
| (GETJSAMPLE(*ptr2++) >> 3));
} else {
vga_setcolor((GETJSAMPLE(*ptr0++) << 16)
| (GETJSAMPLE(*ptr1++) << 8)
| GETJSAMPLE(*ptr2++));
}
vga_drawpixel(mode_col++, mode_row);
if (mode_col == mode_width) {
mode_col = 0;
mode_row++;
}
}
}
}
}
start_row += num_rows;
}
#define OFFSET_ROWS 8
#define OFFSET_COLS PIX_ALIGN /* a high PIX_ALIGN is a pain here */
void
scroll_until_end()
{
int c, done = 0, offset = 0;
/*
* If this is a slideshow we don't allow scrolling, we just sleep
* for the given time.
*/
if (opt_slideshow >= 0) {
if (opt_slideshow > 0) {
sleep(opt_slideshow);
}
done = 1;
}
while (!done) {
c = vga_getch();
switch (c) {
case 'q':
opt_cycle = 0;
done = 1;
break;
case 0x1b: /* ESC */
c = vga_getch();
if (c == '[') {
c = vga_getch();
switch (c) {
case 'A': /* up */
if (offset > 0) {
offset -= OFFSET_ROWS * logical_byte_width;
while (offset < 0) {
offset += logical_byte_width;
}
vga_setdisplaystart(offset);
}
break;
case 'B': /* down */
if (offset / logical_byte_width
< logical_height - mode_height) {
offset += MIN(OFFSET_ROWS,
logical_height - mode_height
- offset / logical_byte_width)
* logical_byte_width;
vga_setdisplaystart(offset);
}
break;
case 'C': /* right */
if ((offset % logical_byte_width) / bytesperpixel
+ mode_width
< logical_width) {
offset += MIN(OFFSET_COLS * bytesperpixel,
(logical_width - mode_width)
* bytesperpixel
- offset % logical_byte_width);
vga_setdisplaystart(offset);
}
break;
case 'D': /* left */
if (offset % logical_byte_width > 0) {
offset -= MIN(OFFSET_COLS * bytesperpixel,
offset % logical_byte_width);
vga_setdisplaystart(offset);
}
break;
default:
done = 1;
}
} else {
done = 1;
}
break;
default:
done = 1;
break;
}
}
}
void
display_shutdown()
{
vga_setmode(TEXT);
}