#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よろしく。 望 ***