home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
program
/
lynxlib
/
picture.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-23
|
21KB
|
676 lines
/* This source file is part of the LynxLib miscellaneous library by
Robert Fischer, and is Copyright 1990 by Robert Fischer. It costs no
money, and you may not make money off of it, but you may redistribute
it. It comes with ABSOLUTELY NO WARRANTY. See the file LYNXLIB.DOC
for more details.
To contact the author:
Robert Fischer \\80 Killdeer Rd \\Hamden, CT 06517 USA
(203) 288-9599 fischer-robert@cs.yale.edu */
/* for loading & dicompressing pictures */
/* This file is missing stuff about printing pictures from the pascal code */
/* Will load a NEO or D*E*G*A*S picture from disk
Structure of a NEO file:
2 words: unused
16 words: color palette, hardware format
46 words: unknown (rotation info, unused, etc)
32000 bytes: the picture, hardware format
Structure of a DEGAS file:
1 word: resolution
16 words: palette
32000 bytes: the picture
You can only tell the difference by size. Degas files are 32033 bytes long,
and NEO files are 32128 bytes long.
Structure of a DOODLE file:
*/
#include <stddef.h>
#include <e_osbind.h>
#include <picture.h>
#include <vfile.h>
/* -------------------------------------------------------- */
pic_type find_pictype(name) /* Figures out the type of a picture file */
char *name; /* The name */
{
TRANS_BUF *old_trans_p;
TRANS_BUF trans;
pic_type out;
GFILE h;
WORD first_2; /* First 2 bytes of SPC file. It's an SPC file */
/* if the WORD contains $5350 */
char ext[5]; /* Extender of file name */
int i;
old_trans_p = (TRANS_BUF *)Fgetdta();
Fsetdta(&trans);
out = ERROR;
if (Fsfirst(name, NO_ATTRIB) != E_OK) goto err;
if (trans.size == DEGAS_SIZE) out = DEGAS;
else if (trans.size == NEO_SIZE) out = NEO;
else if (trans.size == DOODLE_SIZE) out = DOODLE;
else if (trans.size == SPU_SIZE) out = SPU;
else if (trans.size == SCR_SIZE) out = PLAIN_SCREEN;
else { /* We think it's SPC or COMPRESS. Look in it to find out */
if ((h = Fopen(name, G_READ)) <= 0) goto err;
if (Fread(h, 2, &first_2) == 2)
if (first_2 == 0x5350) out = SPC;
#if 0
else if (first_2 == 0x9310) out = SPLAY;
else if (first_2 == 0x1f9d) out = COMPRESS;
#endif
Fclose(h);
/* It may still be unidentified, in which case we look @ name */
/* To tell if it's a TINY picture */
if (out == ERROR) {
for (i = 0; name[i] != '.'; i++) ; /* Find dot */
strncpy(ext, &name[i+1], 4);
pstrupper(ext);
if (ext[2] >= '1' && ext[2] <= '3') ext[2] = 'Y';
if (strcmp(ext, "TNY") == 0) out = TINY;
}
}
err:
Fsetdta(old_trans_p);
return out;
}
/* -------------------------------------------------------- */
raster_convert(pic, atari, ci, bi)
/* Convert one scanline from DOODLE to NEO */
DOODLE_PIC *pic;
PLANE_ARRAY atari; /* Current color place in NEO picture */
int ci,bi; /* Color index & raster byte index */
{
int ai,b,i,j,ai_base;
int color;
BOOLEAN for_bool, bak_bool;
register BYTE *k;
for (i = 0, ai_base = 0; i < 20; i++, ai_base += 8) {
for (b = 0; b < 2; b++, ci++, bi += 8) {
ai = ai_base + b;
color = pic->c[ci];
for (j = 0; j < 4; j++) {
bak_bool = (color >> j) & 1;
for_bool = (color >> (j+4)) & 1;
k = &atari[ai + (j<<1)];
if (for_bool) {
if (bak_bool) *k = 0xFF;
else *k = pic->b[bi];
} else {
if (bak_bool) *k = ~(pic->b[bi]);
else *k = 0;
}
} /* for j */
} /* for b */
} /* for i, ai_base */
}
/* --------------------------------------------------------------- */
BOOLEAN read_degas(in, res, pal, pic)
/* Reads a DEGAS picture from in */
VFILE *in; /* File to read from */
WORD *res; /* Resolution */
char *pal; /* Palette to read to */
char *pic; /* Picture data to read to */
{
read_bytes(in, 2L, res); /* Read res word */
read_bytes(in, (LONG)PAL_SIZE, pal); /* Read palette */
read_bytes(in, (LONG)SCR_SIZE, pic);
}
/* -------------------------------------------------------- */
BOOLEAN read_neo(in, res, pal, pic)
/* Reads a DEGAS picture from in */
VFILE *in; /* File to read from */
WORD *res; /* Resolution */
char *pal; /* Palette to read to */
char *pic; /* Picture data to read to */
{
*res = LOW_RES;
read_bytes(in, 4L, pic); /* Read unused bytes */
read_bytes(in, (LONG)PAL_SIZE, pal); /* Read palette */
read_bytes(in, 92L, pic); /* Read unused bytes */
read_bytes(in, (LONG)SCR_SIZE, pic); /* Read the picture data */
}
/* -------------------------------------------------------- */
BOOLEAN read_doodle(in, res, pal, pic)
/* Reads a DEGAS picture from in */
VFILE *in; /* File to read from */
WORD *res; /* Resolution */
PALETTE pal; /* Palette to read to */
char *pic; /* Picture data to read to */
{
static WORD doodle_pal[] = { /* Commodore's palette */
0x0000, 0x0777, 0x0700, 0x0066, 0x0527, 0x0160, 0x0007, 0x0771,
0x0740, 0x0530, 0x0745, 0x0333, 0x0555, 0x0573, 0x0467, 0x0666
};
DOODLE_PIC *dpic; /* Doodle picture pointer */
int row; /* current row we're converting */
int color_index, raster_index;
BYTE *cur_neo; /* Current place in neo picture */
*res = LOW_RES;
/* Load the picture */
dpic = malloc(sizeof(*dpic));
read_bytes(in, (LONG)DOODLE_SIZE, dpic);
if (dpic->load_addr != 92) {
free(dpic);
return FALSE;
}
/* Convert the data from Doodle to Neochrome format */
cur_neo = pic;
for (row = 0; row < 200; row++) {
color_index = (row >> 3) * 40;
raster_index = (color_index << 3) + (row & 0x7);
raster_convert(dpic, cur_neo, color_index, raster_index);
cur_neo += 160;
}
/* Copy the palette */
for (row = 0; row < 16; row++)
pal[row] = doodle_pal[row];
/* Free memory and leave */
free(dpic);
return TRUE;
}
/* -------------------------------------------------------- */
BOOLEAN read_plainscr(in, res, pal, pic)
/* Reads a DEGAS picture from in */
VFILE *in; /* File to read from */
WORD *res; /* Resolution */
PALETTE pal; /* Palette to read to */
char *pic; /* Picture data to read to */
{
int i;
read_bytes(in, (LONG)SCR_SIZE, pic);
/* No palette or resolution is provided -- use current */
for (i = 0; i < 16; i++) pal[i] = Setcolor(i, -1);
*res = Getres();
}
/* -------------------------------------------------------- */
BOOLEAN read_spec(in, pt, res, pal, pic)
/* Reads a SPEC picture from in */
VFILE *in; /* File to read from */
pic_type pt; /* Either SPC or SPU */
WORD *res; /* Resolution */
PALETTE pal; /* Palette to read to */
char *pic; /* Picture data to read to */
{
char *spec_pic, *spec_color;
BOOLEAN out;
/* Allocate memory for spectrum picture */
spec_pic = malloc(SCR_SIZE);
spec_color = malloc(SPEC_PAL_SIZE);
if (pt == SPC) out = load_spc(in, spec_pic, spec_color);
else out = load_spu(in, spec_pic, spec_color);
if (out) {
spu_to_degas(spec_pic, spec_color, pic, pal);
}
free(spec_pic);
free(spec_color);
*res = LOW_RES;
return out;
}
/* -------------------------------------------------------- */
BOOLEAN read_tiny(in, res, pal, pic)
/* Reads a TINY picture */
VFILE *in; /* File to read from */
WORD *res; /* Resolution */
PALETTE pal; /* Palette to read to */
char *pic; /* Picture data to read to */
{
WORD numctrl; /* # control bytes */
WORD numdata; /* # data bytes */
BYTE *ctrl_buf; /* Buffer of control bytes */
VFILE *c; /* VFILES for ctrl_buf & pic, respectively */
VFILE *p;
BYTE dum[4];
BOOLEAN out = FALSE;
WORD b;
register BYTE q, r;
/* Read resolution and possible color rotation data */
*res = vgetc(in);
if (*res > HIGH_RES) { /* This could be wrong, but I haven't */
*res -= 3; /* found a counterexample */
read_bytes(in, 4L, dum);
}
/* Read the rest of header */
read_bytes(in, (LONG)PAL_SIZE, pal);
read_bytes(in, 2L, &numctrl);
read_bytes(in, 2L, &numdata);
numdata <<= 1;
if (veof(in)) return FALSE;
/* Allocate memory for control bytes & read it in */
if ((ctrl_buf = malloc(numctrl)) == NULL) return FALSE;
read_bytes(in, (LONG)numctrl, ctrl_buf);
if (veof(in)) {
free(ctrl_buf);
return FALSE;
}
c = open_mfile(ctrl_buf, (LONG)numctrl);
p = open_mfile(pic, (LONG)SCR_SIZE);
/* Convert the data */
for (b = (WORD)vgetc(c); !veof(c); b = (WORD)vgetc(c)) {
if (b > 127) { /* Short copy-word */
b = (256-b) << 1;
for (; b > 0; b--) vputc(vgetc(in), p);
} else if (b == 0) { /* Long repeat-word */
read_bytes(c, 2L, &b);
read_bytes(in, 2L, dum);
q = dum[0];
r = dum[1];
for (; b > 0; b--) {
vputc(q, p);
vputc(r, p);
}
} else if (b == 1) { /* Long copy-word */
read_bytes(c, 2L, &b);
b <<= 1;
for (; b > 0; b--) vputc(vgetc(in), p);
} else { /* Short repeat-word */
read_bytes(in, 2L, dum);
q = dum[0];
r = dum[1];
for (; b > 0; b--) {
vputc(q, p);
vputc(r, p);
}
}
}
free(ctrl_buf);
vclose(c);
vclose(p);
}
/* -------------------------------------------------------- */
#if 0
my_uncompress(v)
VFILE_REC *v;
{
decompress(v->in, v->out);
vclose(v->in);
vclose(v->out);
}
/* -------------------------------------------------------- */
my_unsplay(v)
VFILE_REC *v;
{
unsplay(v->in, v->out);
vclose(v->in);
vclose(v->out);
}
#endif
/* -------------------------------------------------------- */
BOOLEAN load_pic(pic, name) /* Loads a picture from disk */
register pic_rec *pic; /* The place to load it to */
char *name; /* The name of the picture to load */
/* Returns TRUE if the picture loaded OK */
{
GFILE h;
pic_type pt;
char *pic_buf; /* The buffer that the picture file is read into */
LONG dum;
long size; /* Size of picture */
VFILE *in; /* Input file */
#if 0
VFILE_REC vrec; /* Arguments to uncompress */
#endif
BOOLEAN b;
BOOLEAN out = FALSE;
/* Find first useable byte in picture array */
pic->p_start = (char *)(((LONG)(pic->p) + 255) & 0xFFFFFF00L);
/* Figure out picture type */
pt = find_pictype(name);
if (pt == ERROR) return FALSE;
/* Read picture file image into memory & set up a memory VFILE */
g_file_attrib(name, &dum, &dum, &size);
pic_buf = lmalloc(size);
h = Fopen(name, READ_MODE);
if (h <= 0) goto err;
if (Fread(h, size, pic_buf) != size) {
Fclose(h);
goto err;
}
if (Fclose(h) != E_OK) goto vclose_err;
in = open_mfile(pic_buf, size);
/* in = open_ffile(name, "rb");*/
#if 0
/* Change in to a cofile handle on uncompress(), if pic is compressed */
if (pt == SPLAY) {
/* Rearrange file handles */
vrec.in = in;
in = open_cofile(&my_unsplay, &vrec, 2000L, &vrec.out);
/* Find size and type */
pt = vgetc(in);
read_bytes(in, 4L, &size);
}
if (pt == COMPRESS) {
/* Rearrange file handles */
vrec.in = in;
in = open_cofile(&my_uncompress, &vrec, 2000L, &vrec.out);
/* Find size and type */
pt = vgetc(in);
read_bytes(in, 4L, &size);
}
#endif
/* Read in the file to appropriate data structure */
switch(pt) {
case SPC :
case SPU :
b = read_spec(in, pt, &(pic->rez), pic->pal, pic->p_start);
break;
case DEGAS :
b = read_degas(in, &(pic->rez), pic->pal, pic->p_start);
break;
case NEO :
b = read_neo(in, &(pic->rez), pic->pal, pic->p_start);
break;
case DOODLE :
b = read_doodle(in, &(pic->rez), pic->pal, pic->p_start);
break;
case TINY :
b = read_tiny(in, &(pic->rez), pic->pal, pic->p_start);
break;
case PLAIN_SCREEN : /* No data other than bit image */
b = read_plainscr(in, &(pic->rez), pic->pal, pic->p_start);
break;
} /* Switch */
out = TRUE;
vclose_err:
vclose(in);
err:
free(pic_buf);
return out;
}
/* -------------------------------------------------------- */
setres(res) /* Sets the current resolution to res, if possible */
/* This needs 32256 bytes in malloc'able memory, if the resolution changes */
int res;
{
int ores;
char *pic;
char *p;
char *old_phys, *old_log;
/* Try to save effort */
ores = Getres();
if (res == HIGH_RES || ores == HIGH_RES) return;
if (res == ores) return;
/* Now, really do it! */
pic = malloc(32256);
p = (char *)(((LONG)(pic) + 255) & 0xFFFFFF00L);
old_phys = Physbase();
old_log = Logbase();
Setscreen(p, -1, -1);
Setscreen(-1, p, -1);
Setscreen(-1, -1, res);
Setscreen(old_log, -1, -1);
Setscreen(-1, old_phys, -1);
free(pic);
}
/* -------------------------------------------------------- */
switch_pic(pic) /* Switches screen to the specified picture */
register pic_rec *pic; /* The picture to switch to */
{
int i;
/* Take care of resolution */
pic->old_rez = Getres();
setres(pic->rez);
/* Take care of screen location */
pic->old_phys = Physbase();
pic->old_log = Logbase();
Setscreen(pic->p_start, pic->p_start, -1);
/* Take care of palette */
for (i = 0; i <= 15; i++) {
pic->old_pal[i] = Setcolor(i, pic->pal[i]);
}
}
/* -------------------------------------------------------- */
switch_norm(pic) /* Switches back to the normal screen */
register pic_rec *pic; /* The picture to switch from */
{
setres(pic->old_rez);
Setscreen(pic->old_log, pic->old_phys, -1);
/* Take care of pallette */
Setpalette(pic->old_pal);
}
/* -------------------------------------------------------- */
BOOLEAN save_neo(pic, name)
register pic_rec *pic; /* The place to load it to */
char *name; /* The name of the picture to load */
/* Returns TRUE if the picture saved OK */
{
int h; /* File handle */
WORD filler[46]; /* Zeros to write in neo file */
if (pic->rez != LOW_RES) return FALSE; /* NEO format only low resolution */
for (h = 0; h < 46; h++)
filler[h] = 0;
h = Fcreate(name, 0);
if (h <= 0) return FALSE;
if (Fwrite(h, (LONG)(2*sizeof(WORD)), filler) != 2*sizeof(WORD)) goto err;
if (Fwrite(h, (LONG)sizeof(PALETTE), pic->pal) != sizeof(PALETTE)) goto err;
if (Fwrite(h, (LONG)(46*sizeof(WORD)), filler) != 46*sizeof(WORD)) goto err;
if (Fwrite(h, (LONG)SCR_SIZE, pic->p_start) != SCR_SIZE) goto err;
Fclose(h);
return TRUE;
err:
Fclose(h);
return FALSE;
}
/* -------------------------------------------------------- */
/* Picture conversion routines -- usually, convert between resolutions */
/* -------------------------------------------------------- */
/* -------------------------------------------------------- */
/* Convert a low-res picture to a high-res picture */
/* This great-o routine was created by Roland Lieger in 1988. */
/* He was so gratious to let Robert Fischer steal it while */
/* only including this little message */
ltoh(pic)
pic_rec *pic;
{
register WORD l1,l2,l3,l4;
WORD temp1,temp2,temp3,temp4;
WORD *p1,*p2,*p3,*p4;
LONG *line1,*line2;
WORD buffer[80];
int curcol;
int red,green,blue,brightness;
int grayscale[16];
int code[16];
register int currcol;
int i,j,k,line;
int lev1,lev2,lev3;
LONG long1,long2;
static BYTE data[]={0x09,0x03,0x0a,0x06,0x0c,0x05,0x09,0x03,0x0a,
0x06,0x0c,0x05,0x09,0x03,0x06,0x0a};
/* different patterns of 2 bits in 4 in a good order */
/* ----------- Calculate the palette ----------- */
for (i=0;i<16;i++) {
curcol=pic->pal[i];
red=(curcol>>8)&7;
green=(curcol>>4)&7;
blue=curcol&7;
brightness=red*red+green*green+blue*blue;
if (brightness>108) grayscale[i]=0;
else if (brightness>70) grayscale[i]=1;
else if (brightness>43) grayscale[i]=2;
else if (brightness>7) grayscale[i]=3;
else grayscale[i]=4;
}
lev1=0;
lev2=0;
lev3=0;
for (i=0;i<16;i++) {
for (j=0;j<i;j++) {
if (pic->pal[i]==pic->pal[j]) {
code[i]=code[j];
break;
}
}
if (i==j) {
if (grayscale[i]==0) {
code[i]=0;
} else if (grayscale[i]==4) {
code[i]=0xf;
} else if (grayscale[i]==1) {
code[i]=1<<(lev1&3);
lev1++;
} else if (grayscale[i]==2) {
lev2++;
code[i]=data[lev2];
} else {
code[i]=(0xee>>(lev3&3)&0xf);
lev3++;
}
}
}
/*---------------- Process the picture -----------------*/
p1=((WORD*)(pic->p_start))+3;
p2=((WORD*)(pic->p_start))+2;
p3=((WORD*)(pic->p_start))+1;
p4=((WORD*)(pic->p_start));
line1=((LONG*)pic->p_start);
line2=((LONG*)pic->p_start)+20; /* 20 LONGs make up a 640 dot line */
for (line=0;line<200;line++) {
j=0;
for (i=0;i<20;i++) {
l1=*p1;
l2=*p2;
l3=*p3;
l4=*p4;
temp1=(l1&0x5555)<<1; /* Flip all the bits around to be able to */
temp2=(l2&0xaaaa)>>1; /* Get the colors out */
l1=(l1&0xaaaa)+temp2;
l2=(l2&0x5555)+temp1;
temp3=(l3&0x5555)<<1;
temp4=(l4&0xaaaa)>>1;
l3=(l3&0xaaaa)+temp4;
l4=(l4&0x5555)+temp3;
temp1=l1&0x3333;
temp2=l2&0x3333;
temp3=l3&0xcccc;
temp4=l4&0xcccc;
l1=(l1&0xcccc)+(temp3>>2);
l2=(l2&0xcccc)+(temp4>>2);
l3=(l3&0x3333)+(temp1<<2);
l4=(l4&0x3333)+(temp2<<2);
buffer[j++]=l1;
buffer[j++]=l2;
buffer[j++]=l3;
buffer[j++]=l4;
p1+=4;
p2+=4;
p3+=4;
p4+=4;
} /* end of the for loop - one color (= 2 monochrome )pictureline done */
for (i=0;i<80;i+=4) {
l1=buffer[i];
l2=buffer[i+1];
l3=buffer[i+2];
l4=buffer[i+3];
for (k=0;k<4;k++) {
currcol=code[((l1&0xf000)>>12)];
l1<<=4;
long1<<=2;
long2<<=2;
long1+=((currcol&0x0c)>>2);
long2+=(currcol&0x03);
currcol=code[((l2&0xf000)>>12)];
l2<<=4;
long1<<=2;
long2<<=2;
long1+=((currcol&0x0c)>>2);
long2+=(currcol&0x03);
currcol=code[((l3&0xf000)>>12)];
l3<<=4;
long1<<=2;
long2<<=2;
long1+=((currcol&0x0c)>>2);
long2+=(currcol&0x03);
currcol=code[((l4&0xf000)>>12)];
l4<<=4;
long1<<=2;
long2<<=2;
long1+=((currcol&0x0c)>>2);
long2+=(currcol&0x03);
}
*line1=long1;
*line2=long2;
line1++;
line2++;
}
line1+=20; /* One 640 dot line has 20 LONGs */
line2+=20; /* line1 and line 2 each skip over each others screenlines */
} /* end of for (line... */
/* Change the palette so it's the "standard" for B&W: */
/* White backround, black forground */
pic->pal[0] = 1;
} /* end of ltoh */
/* -------------------------------------------------------- */
BOOLEAN change_res(pic, dest_res)
/* Converts a picture from its current resolution to the destination res */
pic_rec *pic; /* Picture to convert */
int dest_res; /* Destination resolution */
{
if (pic->rez == dest_res) return TRUE;
if (pic->rez == LOW_RES && dest_res == HIGH_RES) {
ltoh(pic);
pic->rez = HIGH_RES;
return TRUE;
}
return FALSE;
}
/* -------------------------------------------------------- */