home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magazyn Amiga Shareware Floppies
/
ma01.dms
/
ma01.adf
/
wasp
/
src
/
wriff.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-01
|
16KB
|
772 lines
/* wasp - Copyright 1991 by Steven Reiz
* see COPYING and wasp.c for further info
* wriff.c, 4/12/90 - 30/1/91,
* 5/5/91 - 2/6/91, 23/6/91, 30/6/91 - 8/7/91, 16/11/91,
* 8/12/91, 31/12/91 - 1/1/92
*/
static char *sourcefile=__FILE__;
#include "wasp.h"
#define WRIFFMAIN
#include "wriff.h"
static int ticolors;
static int mmap_size_known=1;
void
write_iff(void)
{
long t;
err=0; err2=0;
wriff_init();
decide_mode();
compute_nregs();
wrl(id('F', 'O', 'R', 'M'));
wrl(0L); /* size of the form ilbm, will be patched later */
wrl(id('I', 'L', 'B', 'M'));
write_header();
write_cmap();
write_mmap();
write_body();
write_cmap();
write_mmap();
write_body();
t=cseek_out(0L, 2);
cseek_out(4L, 0);
wrl(t-8L);
printe("IFF file written; %ld bytes, error: %ld, error2: %ld\n", t, err, err2);
}
void
wriff_init(void)
{
slicedo=0;
counts=NULL1;
cm=NULL1;
curcm=NULL1;
wf2rgbweight=NULL1;
cmrgb=NULL1;
newcol=NULL1;
error=NULL1;
error2=NULL1;
nrestricted=0;
restrict_changes= -1;
}
void
decide_mode(void)
{
float sx, sy, st;
if (directrgb>=0) {
if (directrgb%3)
error1(E0_FATAL, E1_IFF_RGB, E2_OPTION, E3_WRONG_NR_PLANES, (int)directrgb);
nplanes=directrgb;
printe("IFF output; direct rgb, %d planes\n", nplanes);
return;
}
if ((xmode!=UNSET || ymode!=UNSET) && asc)
error0(E0_FATAL, E1_IFF, E2_OPTION, E3_ASC);
if (xmode!=UNSET && hires!=HIRES_OK)
error0(E0_FATAL, E1_IFF, E2_OPTION, E3_NOHIRES);
count_pixels(0, (int)ysz-1, 1);
ticolors=icolors=count_colors(1L);
if (hires==HIRES_MAYBE)
hires=(icolors<=16 ? HIRES_OK : HIRES_NOT);
if (asc && (xsz>scrw || ysz>scrh)) {
sx=(float)scrw/(float)xsz;
sy=(float)scrh/(float)ysz;
if (sy<sx)
st=sy;
else
st=sx;
ymode=LACE;
sy=st*2.0;
if (hires==HIRES_OK) {
xmode=HIRES;
sx=st*2.0;
} else {
sx=st;
if (sy>1.0) {
sx=sx/sy;
sy=1.0;
}
}
if (sx!=sy || sx<1.0) {
scalef(1, sy);
scalef(0, sx);
}
}
if (xmode==UNSET) {
if (icolors<=32)
xmode=LORES;
else
xmode=HAM;
}
slicedo=sliced;
if (ymode==UNSET)
ymode=NOLACE;
if (ymode==LACE && (ysz&1))
do_enlarge((int)xsz, (int)ysz+1);
if (distrmeth2!=DISTRMETH_UNSET && xmode!=HAM)
error0(E0_FATAL, E1_IFF, E2_OPTION, E3_ITMETH);
if (!inoperation && distrmeth==DISTRMETH_UNSET) {
if (xmode==EHB)
distrmeth=DEF_EHB_DISTRMETH;
else
distrmeth=DEF_DISTRMETH;
}
if (countmeth==COUNTMETH_UNSET)
countmeth=(xmode==HAM ? DEF_HAM_COUNTMETH : DEF_COUNTMETH);
if (xmode==EHB && !is_ehb_distr())
error1(E0_FATAL, E1_IFF, E2_OPTION, E3_EHB_METH, dmethnam(distrmeth));
printe("IFF output; xmode: %s%s, ymode: %s, cmeth: %s, dmeth: %s",
mmapnam((int)sliced), xmodenam(xmode), ymodenam(ymode),
cmethnam(countmeth), dmethnam(distrmeth));
if (distrmeth2!=DISTRMETH_UNSET)
printe(", dmeth2: %s", dmethnam(distrmeth2));
pute('\n');
}
int
is_ehb_distr(void)
{
return (distrmeth==DISTRMETH_EHB || distrmeth==DISTRMETH_MUE ? 1 : 0);
}
void
compute_nregs(void)
{
if (directrgb>=0)
return;
switch (xmode) {
case HAM: nregs=16; nplanes=6; break;
case EHB: nregs=64; nplanes=6; break;
case LORES: nregs=32; nplanes=5; break;
case HIRES: nregs=16; nplanes=4; break;
}
if (slicedo) {
cm=Malloc((ymode==LACE && sliced!=SLICED_DYN ? (ysz+1)/2 : ysz)*nregs*sizeof(u_short));
curcm=cm;
goto compute_npixvals;
}
count_pixels(0, (int)ysz-1, 0);
icolors=count_colors(1L);
if (icolors>nregs && threshold>1) {
icolors=count_colors(threshold);
if (icolors<nregs) {
u_long mint, curt, maxt;
printe("%d colors occur at least %ld times, trying to complete to %d\n",
icolors, threshold, nregs);
mint=1;
maxt=threshold;
while (maxt>mint+1) {
curt=(mint+maxt)/2;
icolors=count_colors(curt);
if (icolors<nregs)
maxt=curt-1;
else
mint=curt;
}
threshold=(mint+maxt)/2;
icolors=count_colors(threshold);
printe("%d colors occur at least %ld times\n", icolors, threshold);
}
}
if (xmode==LORES || xmode==HIRES) {
if (icolors<nregs)
nplanes=ceillog2((u_long)icolors);
else
nplanes=ceillog2((u_long)nregs);
nregs=1<<nplanes;
}
cm=Malloc(nregs*sizeof(u_short));
curcm=cm;
compute_npixvals:
if (distrmeth2!=DISTRMETH_UNSET) {
cm0=Malloc(nregs*sizeof(u_short));
cmprev=Malloc(nregs*sizeof(u_short));
}
npixvals=1<<nplanes;
printe("%d colors", ticolors);
if (icolors!=ticolors)
printe(", counting %d colors", icolors);
printe(", %d color registers, %d planes", nregs, nplanes);
if (nregs-icolors>0)
printe(", %d registers wasted", nregs-icolors);
pute('\n');
if (nregs<2 || xsz<2 || ysz<2)
error0(E0_FATAL, E1_IFF, E2_FORMAT, E3_2SIMPLE);
assert(nplanes>0 && nplanes<=MAXNPLANES);
assert(nregs<=MAXNREGS);
}
void
write_header(void)
{
struct bmhd_t {
u_short w, h;
short x, y;
u_char nplanes, masking, compression, pad;
u_short transpcol;
u_char xaspect, yaspect;
short pagew, pageh;
} bmhd;
u_long viewmodes;
wrl(id('B', 'M', 'H', 'D'));
wrl((long)sizeof(bmhd));
bmhd.w=xsz;
bmhd.h=ysz;
bmhd.x=bmhd.y=0;
bmhd.nplanes=nplanes;
bmhd.masking=0;
bmhd.compression=compression;
bmhd.pad=0;
bmhd.transpcol=0;
bmhd.yaspect=11;
if (xmode==HIRES && ymode==NOLACE)
bmhd.xaspect=5;
else if (xmode!=HIRES && ymode==LACE)
bmhd.xaspect=20;
else
bmhd.xaspect=10;
bmhd.pagew=bmhd.w;
bmhd.pageh=bmhd.h;
cwrite(&bmhd, sizeof(bmhd));
if (directrgb>=0)
return;
wrl(id('C', 'A', 'M', 'G'));
wrl(4L);
viewmodes=0;
if (xmode==HIRES)
viewmodes|=VM_HIRES;
else if (xmode==HAM)
viewmodes|=VM_HAM;
else if (xmode==EHB)
viewmodes|=VM_EHB;
if (ymode==LACE)
viewmodes|=VM_LACE;
wrl(viewmodes);
}
void
write_cmap(void)
{
u_char *cmbuf;
long t;
short i, j, nr;
static long pos= -1;
if (directrgb>=0)
return;
if (xmode==EHB)
nr=nregs/2;
else
nr=nregs;
t=nr*3;
if (pos== -1) {
wrl(id('C', 'M', 'A', 'P'));
wrl(t);
pos=cseek_out(0L, 1);
} else
cseek_out(pos, 0);
cmbuf=Malloc(t);
for (i=0, j=0; i<nr; ++i) {
cmbuf[j++]=(cm[i]&0x0f00)>>4;
cmbuf[j++]= cm[i]&0x00f0;
cmbuf[j++]=(cm[i]&0x000f)<<4;
}
cwrite(cmbuf, (int)t);
free(cmbuf);
}
void
write_mmap(void)
{
long t;
static long pos= -1;
if (!slicedo)
return;
if (xmode==EHB)
error0(E0_FATAL, E1_IFF, E2_EHB, E3_SLICED_EHB);
t=(ymode==LACE && sliced!=SLICED_DYN ? (ysz+1)/2 : ysz)*nregs*sizeof(u_short);
if (pos== -1) {
pos=cseek_out(0L, 2);
switch (sliced) {
case SLICED_SHAM: {
short ver;
wrl(id('S', 'H', 'A', 'M'));
wrl(t+2);
ver=0;
cwrite(&ver, 2);
cwrite(cm, (int)t);
} break;
case SLICED_DYN:
wrl(id('C', 'T', 'B', 'L'));
wrl(t);
cwrite(cm, (int)t);
break;
case SLICED_PCHG:
mmap_size_known=0;
break;
default:
assert(0);
break;
}
} else {
switch (sliced) {
case SLICED_SHAM:
cseek_out(pos+10, 0);
cwrite(cm, (int)t);
break;
case SLICED_DYN:
cseek_out(pos+8, 0);
cwrite(cm, (int)t);
break;
case SLICED_PCHG:
cseek_out(pos, 0);
write_1pchg();
break;
}
if (nrestricted)
printe("restricting per line changes to %d made %lu changes unsatisfiable\n",
restrict_changes, nrestricted);
}
}
void
write_1pchg(void)
{
short Compression, Flags, StartLine, LineCount;
short ChangedLines, MinReg, MaxReg, MaxChanges;
long TotalChanges;
int firstchange, lastchange, nmaps, linemask_size, changes_size;
u_short *cmptr, *cmptr2, *cmend;
u_long *linemask;
u_short *changes, *changesp, *changesp2;
short i;
int mapnum, regnum, nchanges, nchanges32;
long linemask_index;
assert(nregs<=32);
nmaps=(ymode==LACE ? (ysz+1)/2 : ysz);
/* compute firstchange, the mapnr of the first map different
* from the first map
*/
cmptr=cm;
for (firstchange=0; firstchange<nmaps; ++firstchange) {
cmptr2=cm;
i=nregs-1;
do {
if (*cmptr++ != *cmptr2++)
goto firstchange_found;
} while (--i>=0);
}
firstchange_found:
if (firstchange>=nmaps)
return;
/* compute lastchange, the mapnr of the last map different
* from the last map, +1
*/
cmend=cm+nregs*nmaps;
cmptr=cmend;
for (lastchange=nmaps-1; lastchange>=0; --lastchange) {
cmptr2=cmend;
i=nregs-1;
do {
if (*--cmptr != *--cmptr2)
goto lastchange_found;
} while (--i>=0);
}
lastchange_found:
++lastchange;
/* fill in some of the header fields, allocate the linemask */
Compression=PCHG_COMP_NONE;
Flags=PCHGF_12BIT;
StartLine=(ymode==LACE ? 2*firstchange : firstchange);
LineCount=(ymode==LACE ? 2*lastchange : lastchange)-StartLine+1;
linemask_size=(LineCount+31)/32*4;
linemask=Calloc(linemask_size);
/* compute the other header fields, fill linemask */
ChangedLines=0;
MinReg=nregs-1;
MaxReg=0;
MaxChanges=0;
TotalChanges=0;
cmptr=cm+firstchange*nregs;
for (mapnum=firstchange; mapnum<=lastchange; ++mapnum) {
cmptr2=cmptr-nregs;
nchanges=0;
for (regnum=0; regnum<nregs; ++regnum) {
if (cmptr[regnum]!=cmptr2[regnum]) {
++nchanges;
if (regnum<MinReg)
MinReg=regnum;
if (regnum>MaxReg)
MaxReg=regnum;
}
}
if (nchanges) {
++ChangedLines;
if (nchanges>MaxChanges)
MaxChanges=nchanges;
TotalChanges+=nchanges;
linemask_index=mapnum-firstchange;
if (ymode==LACE)
linemask_index<<=1;
linemask[linemask_index>>5]|=1L<<(31-(linemask_index & 0x1f));
}
cmptr+=nregs;
}
/* allocate the changes */
changes_size=(int)ChangedLines*2+TotalChanges*2;
changes=Malloc(changes_size);
/* fill changes */
cmptr=cm+firstchange*nregs;
changesp=changes;
for (mapnum=firstchange; mapnum<=lastchange; ++mapnum) {
cmptr2=cmptr-nregs;
nchanges=0;
nchanges32=0;
changesp2=changesp+1;
for (regnum=0; regnum<nregs; ++regnum) {
if (cmptr[regnum]!=cmptr2[regnum]) {
if (regnum<16)
++nchanges;
else
++nchanges32;
*changesp2++ =(regnum<<12)|cmptr[regnum];
}
}
if (nchanges+nchanges32) {
*changesp=(nchanges<<8)|nchanges32; /* BYTEORDER */
changesp=changesp2;
}
cmptr+=nregs;
}
assert(changesp==(u_short *)((long)changes+changes_size));
/* write the chunk */
wrl(id('P', 'C', 'H', 'G'));
wrl(20L+(long)linemask_size+(long)changes_size);
wrs(Compression);
wrs(Flags);
wrs(StartLine);
wrs(LineCount);
wrs(ChangedLines);
wrs(MinReg);
wrs(MaxReg);
wrs(MaxChanges);
wrl(TotalChanges);
cwrite(linemask, linemask_size);
cwrite(changes, changes_size);
/* deallocate data */
free(linemask);
free(changes);
}
void
write_body(void)
{
static long tmpnum= -1;
static long pos;
if (tmpnum== -1) {
if (mmap_size_known) {
pos=cseek_out(0L, 2);
write_1body();
tmpnum= -2;
} else {
cout_tmp();
write_1body();
cout_default(&tmpnum, &pos); /* pos used as dummy here */
}
} else {
long endpos;
if (!mmap_size_known) {
pos=cseek_out(0L, 2);
ctmp_move(tmpnum);
}
endpos=cseek_out(0L, 2);
cseek_out(pos+4, 0);
wrl(endpos-pos-8);
}
}
void
write_1body(void)
{
int y, step;
void (*outfunc)(int);
if (directrgb<0)
fillconv();
if (xmode==HAM)
assert(nplanes==6);
if (!inoperation) {
wrl(id('B', 'O', 'D', 'Y'));
wrl(0L);
}
bytesperrow=(xsz+15)/16*2;
noutrows=MAXOUTBUFSZ/(bytesperrow*nplanes);
if (noutrows==0)
noutrows=1;
outbufsz=noutrows*bytesperrow*nplanes;
outrows=Malloc(outbufsz);
if (compression)
outcrows=Malloc(outbufsz*3/2);
body_size=0;
curcm=cm;
if (xmode==HAM) {
fill_prgbtab();
outfunc=ham_row_out;
} else
outfunc=row_out;
if (directrgb>=0) {
nzero=nplanes/3-4;
if (nzero<0)
nzero=0;
ncolor=nplanes/3;
if (ncolor>4)
ncolor=4;
init_counter(0, (int)ysz, 10, "writing RGB IFF");
for (y=0; y<ysz; ++y)
rgb_row_out(y);
} else if (slicedo) {
if (ymode==LACE && sliced!=SLICED_DYN)
step=2;
else
step=1;
init_counter(0, (int)ysz, 5, "writing multimap IFF");
for (y=0; y<ysz; y+=step) {
if (y==ysz-1)
step=1;
count_pixels(y, y+step-1, 0);
icolors=count_colors(threshold);
if (icolors<nregs && threshold>1)
printe("in row %d (and %d) only %d colors occur at least %ld times\n",
y, y+step-1, icolors, threshold);
compute_distr(y, y+step-1);
outfunc(y);
if (step==2)
outfunc(y+1);
curcm+=nregs;
}
} else {
compute_distr(0, (int)ysz-1);
init_counter(0, (int)ysz, 10, "writing IFF");
for (y=0; y<ysz; ++y)
outfunc(y);
}
if (!inoperation)
(void)next_row(1); /* to flush the row buffer */
erase_counter(NULL);
}
void
fillconv(void)
{
short i, j, k;
u_char *p;
conv=Malloc(npixvals*8*MAXNPLANES);
p=conv;
for (i=0; i<npixvals; ++i) {
for (j=128; j; j>>=1) {
for (k=0; k<nplanes; ++k) {
if (i&(1<<k))
*p++ =j;
else
*p++ =0;
}
p+=MAXNPLANES-nplanes;
}
}
}
int
cmpcolregs(short *p1, short *p2)
{
short c1, c2, i;
c1= *p1;
c2= *p2;
i=((c1>>8) + ((c1&0x00f0)>>4) + (c1&0x000f))
- ((c2>>8) + ((c2&0x00f0)>>4) + (c2&0x000f));
if (i)
return (int)i;
i=(c1>>8)-(c2>>8);
if (i)
return (int)i;
i=((c1&0x00f0)>>4)-((c2&0x00f0)>>4);
if (i)
return (int)i;
i=(c1&0x000f)-(c2&0x000f);
return (int)i;
}
void
sort_cm(void)
{
qsort((char *)curcm, (int)nregs, sizeof(u_short),
(int (*)(void *, void *))cmpcolregs);
}
static char *qm="?";
static char *sliceds[]={
"ok",
"not",
"maybe",
NULL
};
char *
slicednam(int i)
{
if (i<0 || i>2)
return qm;
return sliceds[i];
}
static char *xmodes[]={
"unset",
"hires",
"lores",
"ehb",
"ham",
NULL
};
char *
xmodenam(int i)
{
if (i<0 || i>4)
return qm;
return xmodes[i];
}
static char *ymodes[]={
"unset",
"lace",
"nolace",
NULL
};
char *
ymodenam(int i)
{
if (i<0 || i>2)
return qm;
return ymodes[i];
}
/* should be in same order as DISTRMETH_ defines in wasp.h */
static char *dmeths[]={
"unset",
"mu",
"wf",
"ehb",
"mue",
"hs",
"con",
NULL
};
char *
dmethnam(int i)
{
if (i<0 || i>6)
return qm;
return dmeths[i];
}
int
dmethnum(char *s)
{
int i;
for (i=1; dmeths[i]; ++i)
if (!strcmp(s, dmeths[i]))
return i;
return -1;
}
/* should be in same order as COUNTMETH_ defines in wasp.h */
static char *cmeths[]={
"unset",
"all1",
"alldif",
"allfdif",
"j1",
"j21",
"jdif",
"jdifsh",
"jfdif",
"jfdifsh",
"hmgs",
"hmcubic",
"hm",
NULL
};
char *
cmethnam(int i)
{
if (i<0 || i>12)
return qm;
return cmeths[i];
}
int
cmethnum(char *s)
{
int i;
for (i=1; cmeths[i]; ++i)
if (!strcmp(s, cmeths[i]))
return i;
return -1;
}
static char *mmaps[]={
"",
"sliced ",
"dynamic ",
"multipalette ",
NULL
};
char *
mmapnam(int i)
{
assert(i>=0 && i<4);
return mmaps[i];
}