#11 Article 3227 Posted at 1989/07/10 19:30:38 by NOZOMU (MAP041) [PRG.ML1]

Subject: ML1評価版

大変お待たせしました。 ML1の暫定評価版を発表します。
 今回発表する部分は、圧縮データ本体のみで、ヘッダーや
 テキスト化に関する部分は、まだ決まっていませんので、
 今しばらくお待ち下さい。

 *** ML1 評価VER1.0 仕様 ***

 解像度 横160ドット 縦100ドット

 ドット縦横比 1:1

 色数 ドット毎に729色(RGB各9階調)中128色表示。


 *** ML1 評価VER1.0 データ形式 ***

 ML1のデータはビット単位で圧縮されています。

 ○まず最初に、色圧縮モードが2ビットあります。

  色圧縮モード = 0 : パレットデータは128色記録する。
               色コードは7ビット固定。

           1 : パレットデータは使用色だけ記録。
               色コードは7ビット固定。

           2 : パレットデータは使用色だけ記録。
               パレットデータは使用量でソートして記録。
               色コードはwyle符号(後述)で記録。

 ○次にパレットデータがあります。これは先の色圧縮モードにより形式が違います。

  色圧縮モード = 0

   パレットコード10ビット(0~728)×128 = 1280ビット

  色圧縮モード = 1

   (カラーコード7ビット+パレットコード10ビット)×色数
   画面上で使用している色数が75色までのときは、色圧縮モード0より
   こちらの方がデータ量が少なくなります。

  色圧縮モード = 2

   (カラーコード7ビット+パレットコード10ビット)×色数
   データ形式は色圧縮モード1と一緒です。
   圧縮データに記録される回数の多い順に色データをソートして記録します。
   これはwyle符号によって、使用頻度でデータ長を変える事により、圧縮
   効果を出すためです。

 ○次に圧縮データが記録されています。これはデータ形式と一緒に圧縮手順に
  ついても説明します。

  データは、「変化色コード,次の変化点までの長さ,連鎖」を一組とし、全画面分
  続いています。

  ML1では、データ圧縮のために、まず色が変化する点を抽出します。 画面左上から
  右方向に調査し、右端まで来たらそのまま1ドット下の左端から続けます。
  そして、以後この変化点と変化した色を圧縮して行きます。

  変化色コードは、変化点により、以後何色になるのかを記録します。

   色圧縮モード0,1 なら、そのまま色コードを7ビット記録します。

   色圧縮モード2の場合は、色コードをwyle符号で記録します。

    wyle符号とは、

                0n                0 -    1
               10nn               2 -    5
              110nnn              6 -   13
             1110nnnn            14 -   29
            11110nnnnn           30 -   61
           111110nnnnnn          62 -  125
          1111110nnnnnnn        126 -  253
         11111110nnnnnnnn       254 -  509
        111111110nnnnnnnnn      510 - 1021
       1111111110nnnnnnnnnn    1022 - 2045
      11111111110nnnnnnnnnnn   2046 - 4093
     111111111110nnnnnnnnnnnn  4094 - 8189
    1111111111110nnnnnnnnnnnnn 8190 - 16381

    以上のようなビットデータで、nは0か1です。
    使用頻度が高い色程小さいコードナンバーに割り当てると、データ量を
    減らすことができます。 ただし「使用頻度が高い」というのは、画面
    上のドット数を数えても判りません。 データを圧縮した際に、変化色
    コードとして何回記録されるかを数えなければいけません。
    変化色コードを数えるには、2パスで圧縮しなければならないので、メ
    モリー容量的にも時間的にもかなり負担が大きいので、8ビットマシン
    では、色圧縮モード0か1の圧縮のみというのもありですね。
    再生の方はどちらでも1パスでできますから、両方サポートしましょう。
    また、使用色数が多く、使用頻度に偏りが少ない場合、色コードをwyle
    符号で記録するより、7ビット固定にした方がデータ量が少なくなる
    場合もありますから、そういう場合も色圧縮モード0か1で記録することに
    なります。

  次の変化点までの長さは、変化点の抽出を行ったのと同じ順序で、次の変化点まで
  の長さから1を引いて記録します。wyle符号を使用します。 ただし、長さの
  チェックは、次の連鎖のチェックをした後に行います。 長さが16000ならばデータ
  終了です。

  連鎖とは、画面の縦方向の圧縮です。

   まず連鎖の有無のフラグ(1ビット)を記録します。 連鎖がある場合は1、
   ない場合は0です。

   連鎖のチェックは、今注目している変化点の1ドット下のラインに、同じ色の
   変化点があるかどうかをチェックします。 注目している変化点の真下ならば
   0、1ドット右なら100、1ドット左なら101、2ドット右なら1110、2ドット
   左なら1111、連鎖無しなら110を記録し、連鎖が無くなるまで、チェックし続
   けます。

以下に、C言語によるML1評価用プログラムをuploadします。

X68000用ですが、機種依存するぶぶんは印を付けていますので、他機種の人も

修正して使ってみて下さい。

#include	<stdio.h>
#include	<string.h>
#include	<graph.h>
#include	<basic0.h>
#include	<iocslib.h>

#define DLEN	int
#define	NOLINK	3
#define ENDLINK	5
#define EOD	16000
#define	MAXY	100
#define	MAXX	160

short	palt[128];
unsigned char  vram[ MAXY ][ MAXX ];

long	data_ptr=0;
DLEN	data[36000];

DLEN	bit_data_ptr=0;
unsigned char bit_data[32000];
unsigned char bit_fild=0x80;

DLEN	palet_index1[128];
DLEN	palet_index2[128];
DLEN	palt_count[128];
char	f_name[24]={"test.nl3"};
DLEN	offset_value[6]={0,1,-1,2,-2, NOLINK };

DLEN	color_mode=2;

void	main( int , char *[] ) ;
void	ms1_pass1( void ) ;
DLEN	get_length( DLEN , DLEN ) ;
void	hunt_v_link( DLEN , DLEN , DLEN ) ;
DLEN	search_v_link( DLEN , DLEN , DLEN ) ;
void	ms1_pass2( void ) ;
void	sort_palt( void ) ;
void	store_wyle( DLEN ) ;
void	store_bit_data( DLEN , DLEN ) ;
void	search_diff(void);
void	ml1_pass1(void);
DLEN	restore_wyle(void);
DLEN	restore_bit_data( DLEN );
void	release_v_link( DLEN , DLEN , DLEN );

void main(argc,argv)
int	argc;
char	*argv[];
{
	DLEN	x,y;
	DLEN	color;
	DLEN	i,j;
	unsigned char *v;

	/***************画面初期化+NL3データ読み込み**************/
	screen(1,2,1,1);
	apage(0);
	vpage(1);

	if (argc==2)
		strcpy(f_name,argv[1]);
	fprintf(stdout,"%s\n",f_name);
	nloader(f_name,palt,vram);

	for (i=128;i<256;++i)
		GPALET(i,GPALET(i-128,-1)^0xfffe);
	fill(0,0,511,511,0);
	for (y=0;y< MAXY ;++y)
		for (x=0;x< MAXX ;++x)
			pset(x,y,vram[y][x]);
	/**********************************************************/

	ms1_pass1();

	fprintf(stdout,"\ndata_ptr=%d\n",data_ptr);

	ms1_pass2();

	fprintf(stdout,"\ncolor wyle bit_data_ptr=%d\n",bit_data_ptr);

	memset(vram,0,16000);

	ml1_pass1();
}


/********************** ML1関係関数始まりぃ~~~! ******************/


void ms1_pass1(void)
{
	DLEN	x,y,color,length,i;
	long	temp_ptr;

	for (i=0;i<128;++i)
	{
		palet_index2[i]=i;
		palt_count[i]=0;
	}
	search_diff();

	for (y=0;y< MAXY ;++y)
	{
		for (x=0;x< MAXX ;++x)
		{
			if (vram[y][x]&0x80)
			{
				temp_ptr=data_ptr;
				data_ptr+=2;

				vram[y][x]&=0x7f;
				color=vram[y][x];

				hunt_v_link(x,y,color);

				length=get_length(x,y);
				data[temp_ptr++]=length-1;

				data[temp_ptr]=color;
				++palt_count[color];

			}
		}
	}
	data[data_ptr++]= EOD ;
}

DLEN get_length(x,y)
DLEN	x,y;
{
	register DLEN	length=0;
	register unsigned char	*v;
	register unsigned char  *ve;

	ve=&vram[ MAXY -1][ MAXX -1];
	for (v=&vram[y][x];(v<=ve)&&(*v<0x80);++v)
		++length;
	return length;
}

void hunt_v_link(x,y,color)
DLEN	x , y , color ;
{
	DLEN	offset;

	offset=search_v_link(x,y,color);
	data[data_ptr++]=offset;
	if (offset== ENDLINK )	return;
	x+=offset_value[offset];
	y+=1;
	vram[y][x]&=0x7f;
	hunt_v_link(x,y,color);
	return;
}

DLEN search_v_link(x,y,c)
DLEN	x,y,c;
{
	unsigned char	color=c|0x80;
	unsigned char	*v;

	if (++y== MAXY )	return	ENDLINK ;
	v=&vram[y][x];
	if (*v==color)	return 0;
	if ((x+1< MAXX )&&(*(v+1)==color))	return 1;
	if ((x-1>=0    )&&(*(v-1)==color))	return 2;
	if ((x+2< MAXX )&&(*(v+2)==color))	return 3;
	if ((x-2>=0    )&&(*(v-2)==color))	return 4;
	return	ENDLINK ;
}

void ms1_pass2(void)
{
	DLEN	temp_data_ptr=0;
	DLEN	color,length,offset;
	DLEN	i;
	DLEN	j,k;

	bit_data_ptr=0;
	bit_fild=0x80;

	sort_palt();

	j=palt_count[palet_index1[0]]*2;
	j+=palt_count[palet_index1[1]]*2;
	for (i=2;i<6;++i)
		j+=palt_count[palet_index1[i]]*4;
	for (i=6;i<14;++i)
		j+=palt_count[palet_index1[i]]*6;
	for (i=14;i<30;++i)
		j+=palt_count[palet_index1[i]]*8;
	for (i=30;i<62;++i)
		j+=palt_count[palet_index1[i]]*10;
	for (i=62;i<126;++i)
		j+=palt_count[palet_index1[i]]*12;
	for (i=126;i<128;++i)
		j+=palt_count[palet_index1[i]]*14;

	for (i=k=0;i<128;k+=palt_count[i++]*7);

	if (j<k)	color_mode=2;
	else		color_mode=0;

	for (i=0;palt_count[palet_index1[i]]>0;++i);

	if (color_mode==0)
	{
		if (i>75)
		{
			store_bit_data(2,0);
			for (i=0;i<128;++i)
				store_bit_data(10,palt[i]);
		}
		else
		{
			store_bit_data(2,1);
			store_bit_data(7,i);
			for (i=0;i<128;++i)
			{
				if (palt_count[i]!=0)
				{
					store_bit_data(7,i);
					store_bit_data(10,palt[i]);
				}
			}
		}
	}
	else
	{
		store_bit_data(2,2);
		store_bit_data(7,i);
		for (i=0;palt_count[palet_index1[i]]>0;++i)
		{
			store_bit_data(7,palet_index1[i]);
			store_bit_data(10,palt[palet_index1[i]]);
		}

	}

	while ((length=data[temp_data_ptr++])!= EOD )
	{
		store_wyle(length);
		color=data[temp_data_ptr++];
		if (color_mode==2)	store_wyle(palet_index2[color]);
		else			store_bit_data(7,color);
		if ((offset=data[temp_data_ptr++])== ENDLINK )
			store_bit_data(1,0);
		else
		{
			store_bit_data(1,1);
			do
			{
				if (offset==0)	store_bit_data(1,0);
				if (offset==1)	store_bit_data(3,4);
				if (offset==2)	store_bit_data(3,5);
				if (offset==3)	store_bit_data(4,0xe);
				if (offset==4)	store_bit_data(4,0xf);
			}
			while ((offset=data[temp_data_ptr++])!= ENDLINK );
			store_bit_data(3,6);
		}
	};
	store_wyle( EOD );
	return;
}

void sort_palt(void)
{
	DLEN	i,j;
	DLEN	dummy;

	for (i=0;i<128;++i)
		palet_index1[i]=i;
	for (i=0;i<127;++i)
		for (j=i+1;j<128;++j)
			if (palt_count[palet_index1[i]]<palt_count[palet_index1[j]])
			{
				dummy=palet_index1[i];
				palet_index1[i]=palet_index1[j];
				palet_index1[j]=dummy;
			}
	for (i=0;i<128;++i)
		palet_index2[palet_index1[i]]=i;
}

void store_wyle(num)
DLEN	num;
{
	DLEN	l;
	
     	for (l=1;num>=(2<<l)-2;++l);
	store_bit_data(l,(1<<l)-2);
	store_bit_data(l,num-((1<<l)-2));
}

void store_bit_data(bit,num)
DLEN	bit,num;
{
	DLEN	bit_mask=1<<bit-1;
	DLEN	i;

	for (i=0;i<bit;++i)
	{
		if (num&bit_mask)
			bit_data[bit_data_ptr]|=bit_fild;
		else
			bit_data[bit_data_ptr]&=bit_fild^0xff;
		bit_mask>>=1;
		if ((bit_fild>>=1)==0)
		{
			bit_data_ptr++;
			bit_fild=0x80;
		}
	}
}

void search_diff(void)
{
	register unsigned char	c=128;
	register unsigned char	*v;
	register unsigned char	*ve;

	ve=&vram[ MAXY -1][ MAXX -1];
	for (v=&vram[0][0];v<=ve;++v)
		if (*v!=c)
		{
			c=*v;
			*v|=0x80;
		}
}



void ml1_pass1(void)
{
	DLEN	x=0,y=0,i,j;
	DLEN	color,length,color_num;


	bit_data_ptr=0;
	bit_fild=0x80;

	color_mode=restore_bit_data(2);
	switch (color_mode)
	{
		case 0:
			for (i=0;i<128;++i)
				palt[i]=restore_bit_data(10);
			break;
		case 1:
			color_num=restore_bit_data(7);
			for (i=0;i<color_num;++i)
			{
				j=restore_bit_data(7);
				palt[j]=restore_bit_data(10);
			}
			break;
		case 2:
			color_num=restore_bit_data(7);
			for (i=0;i<color_num;++i)
			{
				palet_index1[i]=restore_bit_data(7);
				palt[palet_index1[i]]=restore_bit_data(10);
			}
			break;
		default:;
	}
	while ((length=restore_wyle())!= EOD )
	{
		length++;
		if (color_mode==2)	color=palet_index1[restore_wyle()];
		else			color=restore_bit_data(7);
		vram[y][x]=color|0x80;
		pset(x,y+100,color|0x80);/***************/
		if (restore_bit_data(1))
			release_v_link(x,y,color);
		x+=length;
		y+=(x/ MAXX );
		x%= MAXX ;
	};

	/**************** 画面表示 ********************/
	for (i=0;i<128;++i)
		palet(i,(palt[i]/81*3<<6)+((palt[i] % 81)/9*3<<11)+((palt[i] % 9)*3<<1));

	for (y=0;y< MAXY ;++y)
		for (x=0;x< MAXX ;++x)
		{
			if (vram[y][x]&0x80)
				color=(vram[y][x]&0x7f);
			vram[y][x]=color;
			pset(x,y+100,color);
		}
	/**********************************************/
}

DLEN restore_wyle(void)
{
	DLEN	l;

	for (l=1;restore_bit_data(1);++l);
	return	restore_bit_data(l)+(1<<l)-2;
}

DLEN restore_bit_data(bit)
DLEN	bit;
{
	DLEN	i,n=0;
 
	for (i=0;i<bit;++i)
	{
		n<<=1;
		if (bit_data[bit_data_ptr]&bit_fild)
			n++;
		if ((bit_fild>>=1)==0)
		{
			bit_data_ptr++;
			bit_fild=0x80;
		}
	}
	return n;
}

void release_v_link(x,y,color)
DLEN	x,y,color;
{
	DLEN	offset;

	offset=restore_bit_data(1);
	if (offset==1)
	{
		offset=restore_bit_data(2)+1;
		if (offset==3)	offset=ENDLINK;
		if (offset==4)
		{
			if (!restore_bit_data(1))	offset=3;
			else				offset=4;
		}
	}
	if (offset!= ENDLINK )
	{
		x+=offset_value[offset];
		y++;
		vram[y][x]=color|0x80;
		pset(x,y+100,color|0x80);/*****************/
		release_v_link(x,y,color);
	}
}



以上なんですが、nloader()関数がアセンブラ記述だったのを忘れてました、
X68000のかたは以下のプログラムを、他機種の方はNL3データを読み込む関数を
自作して下さい。 うぅ~む、どうもすみません。

*************************************************************************
*	nloader:							*
*		void	nloader(file);					*
*		char	*file;						*
*************************************************************************
savsiz		equ		4*12			. レジスタ退避領域

		xdef		_nloader

		include		iocscall.mac
		include		doscall.mac

	.offset		4

file		ds.l		1			. ファイルネーム
palt		ds.l		1
vram		ds.l		1

	.text

_nloader:
		movem.l		d3-d7/a0-a6,-(sp)

		move.l		savsiz+file(sp),d2	* file name
		move.l		savsiz+palt(sp),a3
		move.l		savsiz+vram(sp),a4	* vram

		dc.w		_FFLUSH
		clr.w		-(sp)
		move.l		d2,-(sp)
		dc.w		_OPEN
		addq.l		#6,sp
		tst.l		d0
		bmi		doserror
		move.w		d0,fileno

		lea.l		buffer,a5
		move.l		#17000,-(sp)
		move.l		a5,-(sp)
		move.w		fileno,-(sp)
		dc.w		_READ
		lea		10(sp),sp
		tst.l		d0
		bmi		doserror


		clr.l		d1		; Loop counter *64
ploop
		bsr		read
		move.l		d0,d2
		bsr		read
		lsl.l		#7,d0
		or.l		d0,d2
		move.w		d2,(a3)+
		move.l		d2,d4
		move.l		d2,d5
		move.l		d2,d6
		divu		#81,d4
		move.w		d4,d0
		mulu		#81,d0
		sub.w		d0,d5
		sub.w		d0,d6
		divu		#9,d5
		move.w		d5,d0
		mulu		#9,d0
		sub.w		d0,d6

		mulu		#3,d4
		lsl.w		#6,d4
		mulu		#3,d5
		lsl.w		#6,d5
		lsl.w		#5,d5
		mulu		#6,d6

		clr.l		d2
		or.w		d4,d2
		or.w		d5,d2
		or.w		d6,d2

		moveq.l		#_GPALET,d0
		trap		#15

		addq.w		#1,d1
		cmp.w		#64,d1
		bne		ploop

		clr.l		d3
		clr.l		d4
loopg
		bsr		read		; Color + Run-Length flag
		bclr.l		#6,d0
		beq		one

		move.w		d0,d5		; Color
		bsr		read
		addq.w		#1,d0		; Length
loopc
		move.b		d5,(a4)
		add.l		#160,a4

		add.w		#1,d4		; y = y + 1
		cmp.w		#100,d4
		bne		skip2
		clr.l		d4
		sub.l		#160*100-1,a4
		add.w		#1,d3		; x = x + 1
		cmp.w		#160,d3
		beq		exit
skip2:		dbra		d0,loopc
		bra		loopg


one
		move.b		d0,(a4)
		add.l		#160,a4

		add.w		#1,d4		; y = y + 1
		cmp.w		#100,d4
		bne		loopg
		clr.l		d4
		sub.l		#160*100-1,a4

		add.w		#1,d3		; x = x + 1
		cmp.w		#160,d3
		bne		loopg
exit
		move.w		fileno,-(sp)
		dc.w		_CLOSE
		addq.l		#2,sp
		movem.l		(sp)+,d3-d7/a0-a6
		rts

read
		clr.l		d0
		move.b		(a5)+,d0
		sub.b		#32,d0
		bcs		read
		cmp.b		#127,d0
		bcs		next
		sub.b		#33,d0
		cmp.b		#159,d0
		bcs		next
		sub.b		#$1d,d0
next:		rts

doserror:
		movem.l		(sp)+,d3-d7/a0-a6
		rts

	.bss

fileno:		ds.w		1
buffer:		ds.b		17000

	.end



以上ですが、コメントの部分の、引数に関する記述はウソです。

という訳で、コア部分のみの暫定版ですから、データのuploadはしないでね。

あと、ヘッダーにくっつけたいデータや、テキストコンバートの形式なんかに

ついてのご意見、お待ちしております。

*** さてさて、いかがなもんでしょね。 Resよろしく。 望 ***