MAKIchan image format?
Moderators: XnTriq, helmut, xnview
MAKIchan image format?
Ok I've seen this format for a while now as relating to images on the Japanese computer PC98. It has a file extension of MAG. Unfortuneately all documentation I've seen so far is written in Japanese. Now I know that XNview supports this format. So I'm hoping that maybe someone here at these forums can explain to me how it works. I've tried reverse engineering this but all I get is garbage (often from only slightly altering one byte in the file). This suggests it uses some kind of compression. Now if only someone here could explain the format to me, in English.
Thanks in advance for any help you may provide.
Thanks in advance for any help you may provide.
Re: MAKIchan image format?
Ben321
Hello !
• I can't explain the structure of this format, but all I can say is from my old doc :
KR
Claude
Clo
Hello !
• I can't explain the structure of this format, but all I can say is from my old doc :
- XnView supports it at reading only…mag---- MAKIchan Graphics----ext. : mag
KR
Claude
Clo
Old user ON SELECTIVE STRIKE till further notice •
Re: MAKIchan image format?
While working on a visual novel engine, I've happened upon a few MAG images, and wrote a basic specification. It is available here: http://mooncore.eu/mimu/txt/makichan.htm
Helpful, I hope!
Helpful, I hope!
Re: MAKIchan image format?
mimulus
Hello ! Welcome aboard !
• Thank you for this link!
- Maybe Pierre (the Author) will find there some useful info…
- The best should be indeed to find a Japanese user able to translate the full specs…
Kind regards,
Claude
Clo
Hello ! Welcome aboard !
• Thank you for this link!
- Maybe Pierre (the Author) will find there some useful info…
- The best should be indeed to find a Japanese user able to translate the full specs…
Kind regards,
Claude
Clo
Old user ON SELECTIVE STRIKE till further notice •
Re: MAKIchan image format?
mimulus wrote:While working on a visual novel engine, I've happened upon a few MAG images, and wrote a basic specification. It is available here: http://mooncore.eu/mimu/txt/makichan.htm
Helpful, I hope!
Yes BIG THANKS, but you neglected a few things I'll need to know if I'm to make an encoder. What do the boolean values in flag A do? Also you explained how to use flag B to copy pixels, but not how to set flag B to make original pixels. Please explain in more detail how flags A, B, and the color array work together to make an image.
Also please list other screen modes than just mode 04 (16 color mode) if you know what the codes are for other screen modes.
Re: MAKIchan image format?
I updated the specification document, hopefully making it clearer. I also translated the screen modes as listed in the official Japanese specs.
You're hoping to write an encoder? Hmm. If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
You're hoping to write an encoder? Hmm. If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
Re: MAKIchan image format?
By the way, very good tipmimulus wrote:If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
Re: MAKIchan image format?
Does that mean that there would be no Flag B array? And does that also mean that the header entry for Flag B size would be set at 0? If so, What would I set the header entry for Flag B offset too? Would it be the same entry as the Color Index array offset? Please explain further. Your suggested technique sounds good in theory, but you didn't provide enough info for actually implementing it.mimulus wrote:I updated the specification document, hopefully making it clearer. I also translated the screen modes as listed in the official Japanese specs.
You're hoping to write an encoder? Hmm. If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
Re: MAKIchan image format?
By now you've probably gotten it to work perfectly, but just in case:Does that mean that there would be no Flag B array? And does that also mean that the header entry for Flag B size would be set at 0? If so, What would I set the header entry for Flag B offset too? Would it be the same entry as the Color Index array offset? Please explain further. Your suggested technique sounds good in theory, but you didn't provide enough info for actually implementing it.
As far as I can tell, your guesses are all correct. The Flag B array would be empty, its size would be 0 bytes, and its offset equal to the Color Index array offset. Or, you could put a bunch of garbage data in the Flag B array - a decompressor would just never read it, as long as the Flag A array is all zeroes.
This is obviously just an inefficient hack; figuring out a good algorithm for optimal Maki-chan compression is a challenge of its own, while I only needed decompressing capability.
Re: MAKIchan image format?
This is an overly complex compression scheme. The choices for DeltaX and DeltaY values make no sense, they don't seem to have any pattern:
deltax : array[0..15] of byte = (0,1,2,4,0,1,0,1,2,0,1,2,0,1,2,0);
deltay : array[0..15] of byte = (0,0,0,0,1,1,2,2,2,4,4,4,8,8,8,16);
They seem to be just arbitrary values pulled out of the inventor's hat.
The color channels are GRB instead of the standard RGB or BGR.
It uses a complicated XOR scheme:
If (next flag A bit) = TRUE
Then flag_buffer[x] = flag_buffer[x] XOR (next flag B byte)
instead of just a simple equal to scheme like
If (next flag A bit) = TRUE
Then flag_buffer[x] = (next flag B byte)
It actually bothers to keep a flag buffer such that the previous line's actions with flagB have an effect on the current line, although that is a dumb thing since the DeltaX and DeltaY already are a form of "look up previous data" type compression. So it basically is performing multiple compressions, rather than a simple single compression. Then to make the complexity worse, parts of it are handled as whole bytes, other parts are handled as nibbles, yet other parts are handled as single bits. And even other parts are handled as words (pairs of bytes). And to further complicate things, some parts are handled as different sized data units at different steps in the process.
This makes the whole compression scheme overly complicated. And if you want to even DREAM OF writing a COMPRESSER for this, the analysis that the compressor software would have to do to perform the action of compressing the image would be so INSANELY COMPLICATED that the compression algorithm is basically IMPOSSIBLE to reverse engineer from the decompressor algorithm unless you are a SUPER GENIUS SOFTWARE ENGINEER!
I thought I could make a compressor after figuring out the decompressor. But nope. I've written a VB6 implementation of the decompressor, but I'm no closer now to writing a compressor for this format than before I was before. I was hoping someone maybe could help out with that, but I doubt it given the complexity of the compression scheme. I'd basically have to find the Japanese guy who invented the compression and hope he would be willing to give me the official specs on his compressor.
deltax : array[0..15] of byte = (0,1,2,4,0,1,0,1,2,0,1,2,0,1,2,0);
deltay : array[0..15] of byte = (0,0,0,0,1,1,2,2,2,4,4,4,8,8,8,16);
They seem to be just arbitrary values pulled out of the inventor's hat.
The color channels are GRB instead of the standard RGB or BGR.
It uses a complicated XOR scheme:
If (next flag A bit) = TRUE
Then flag_buffer[x] = flag_buffer[x] XOR (next flag B byte)
instead of just a simple equal to scheme like
If (next flag A bit) = TRUE
Then flag_buffer[x] = (next flag B byte)
It actually bothers to keep a flag buffer such that the previous line's actions with flagB have an effect on the current line, although that is a dumb thing since the DeltaX and DeltaY already are a form of "look up previous data" type compression. So it basically is performing multiple compressions, rather than a simple single compression. Then to make the complexity worse, parts of it are handled as whole bytes, other parts are handled as nibbles, yet other parts are handled as single bits. And even other parts are handled as words (pairs of bytes). And to further complicate things, some parts are handled as different sized data units at different steps in the process.
This makes the whole compression scheme overly complicated. And if you want to even DREAM OF writing a COMPRESSER for this, the analysis that the compressor software would have to do to perform the action of compressing the image would be so INSANELY COMPLICATED that the compression algorithm is basically IMPOSSIBLE to reverse engineer from the decompressor algorithm unless you are a SUPER GENIUS SOFTWARE ENGINEER!
I thought I could make a compressor after figuring out the decompressor. But nope. I've written a VB6 implementation of the decompressor, but I'm no closer now to writing a compressor for this format than before I was before. I was hoping someone maybe could help out with that, but I doubt it given the complexity of the compression scheme. I'd basically have to find the Japanese guy who invented the compression and hope he would be willing to give me the official specs on his compressor.
Re: MAKIchan image format?
I finally wrote a successful MAG image file decoder in VB6, thanks to the specs provided here by Mimulus. The source code is in a zip file attached to this message.
The first line defines the constant FName has the file name (it requires the full path c:\etc...) to the mag image file. This isn't suitable in its current form for compiling as there's no way to select an image file to load at runtime (it's a constant set at design-time), but you can easily run it from the VB6 IDE as-is. Also this could be a building block for a project that is a full fledged mag viewer, or it could be used as a way to implement MAG format images in a computer game if you are writing a computer game in VB6.
The program as it is now, when run it does a number of things.
First if verifies that the path specified by the constant FName is valid. If this fails, the program quits.
(it doesn't yet check the file extension, so you could use a Makichan2 format image with a different extension like .XYZ instead of .MAG, and it would still load, but I may add file extension checking in a later version).
Then it loads the file.
The first thing it does after loading is it checks the first 6 bytes of the file to make sure they contain the string "MAKI02". If this check fails, the program quits.
If it passes these checks, it then procedes to parse the header and other data in the file and display the image, as well as in another box it displays the info provided in byte 4 of the header (the "screen mode" byte). This includes the number of colors in the palette (8, 16, or 256), the number of lines on the display that was the type of display that the image was intended to be viewed on (200 or 400), and whether the dispalay that the image was intended to be viewed on was an "analog" or "digital" display (except for the palette, these other infos seem useless, pretty much just meta data about the type of display that the artist who created the image expected it to appear best on). Also this image info box displays the width and height of the image.
This program also properly handles nonstandard image sizes. Typically a MAG image is supposed to have widths that are multiples of 8 pixels. If this isn't the case it originally caused my program to crash. I have created a workaround where the image (if its width isn't a multiple of 8 pixels) is padded to such a multiple during decompression and then prior to display the padding is removed so that it has the correct image width as stated in the header of the file. The next best program for this is Fine-View (it has the ability to do both loading and saving in MAG format) does pad it so it will decompress properly, but then it fails to remove that padding, and as such the image will have a black bar on the right side if it isn't an exact multiple of 8 pixels in width. My program doesn't make this mistake.
The first line defines the constant FName has the file name (it requires the full path c:\etc...) to the mag image file. This isn't suitable in its current form for compiling as there's no way to select an image file to load at runtime (it's a constant set at design-time), but you can easily run it from the VB6 IDE as-is. Also this could be a building block for a project that is a full fledged mag viewer, or it could be used as a way to implement MAG format images in a computer game if you are writing a computer game in VB6.
The program as it is now, when run it does a number of things.
First if verifies that the path specified by the constant FName is valid. If this fails, the program quits.
(it doesn't yet check the file extension, so you could use a Makichan2 format image with a different extension like .XYZ instead of .MAG, and it would still load, but I may add file extension checking in a later version).
Then it loads the file.
The first thing it does after loading is it checks the first 6 bytes of the file to make sure they contain the string "MAKI02". If this check fails, the program quits.
If it passes these checks, it then procedes to parse the header and other data in the file and display the image, as well as in another box it displays the info provided in byte 4 of the header (the "screen mode" byte). This includes the number of colors in the palette (8, 16, or 256), the number of lines on the display that was the type of display that the image was intended to be viewed on (200 or 400), and whether the dispalay that the image was intended to be viewed on was an "analog" or "digital" display (except for the palette, these other infos seem useless, pretty much just meta data about the type of display that the artist who created the image expected it to appear best on). Also this image info box displays the width and height of the image.
This program also properly handles nonstandard image sizes. Typically a MAG image is supposed to have widths that are multiples of 8 pixels. If this isn't the case it originally caused my program to crash. I have created a workaround where the image (if its width isn't a multiple of 8 pixels) is padded to such a multiple during decompression and then prior to display the padding is removed so that it has the correct image width as stated in the header of the file. The next best program for this is Fine-View (it has the ability to do both loading and saving in MAG format) does pad it so it will decompress properly, but then it fails to remove that padding, and as such the image will have a black bar on the right side if it isn't an exact multiple of 8 pixels in width. My program doesn't make this mistake.
- Attachments
-
- MAG Viewer.zip
- (3.33 KiB) Downloaded 169 times
-
- Posts: 39
- Joined: Sat Sep 10, 2016 11:29 pm
Re: MAKIchan image format?
I found the original asm sources of the MG.EXE v0.99. It's considered to be the one of the best Makichan/Pi encoders of that era. Maybe it can help on the development of a modern encoder?
The ana86 assembler is also supplied in that page.
The author still seems to be kicking around, and if I understood that page correctly, his e-mail is tenka at sixty eight zero nine dot net. Maybe he could also provide some help.
The ana86 assembler is also supplied in that page.
The author still seems to be kicking around, and if I understood that page correctly, his e-mail is tenka at sixty eight zero nine dot net. Maybe he could also provide some help.
- Attachments
-
- mg-lfn-v0.99c-src.zip
- (260.08 KiB) Downloaded 39 times
-
- Posts: 39
- Joined: Sat Sep 10, 2016 11:29 pm
Re: MAKIchan image format?
This ana assembly language looks like some hybrid between Pascal and 8086 asm. This is the content of the mag_wrt.ana file:
Note: All files are encoded in Shift JIS.
Code: Select all
submodule Mag
import GH
import Dos
import Pri
import Subr
import Deb
import Std
@define GHT() GH.T[ds:0]
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
cvar pdataBuf:d
cvar dbufAseg:w, dbufAsiz:w
cvar dbufBseg:w, dbufBsiz:w
cvar dbufPseg:w, dbufPszs:w, dbufPendSeg:w
cvar flgLinBufSeg:w,flgLinBufSiz:w
cvar flgLinBufSeg2:w
cvar ptrA:w, ptrB:w, ptrP:d
cvar vsizXh:w
cvar hdl:w,c256flg:b
cvar curY:w
cvar gh_t:d
cvar flagAofs:d, flagBofs:d, pdataOfs:d
cvar flagAsiz:d, flagBsiz:d
cvar pos:w(16)
cvar posX:w(16) = {0,-1,-2,-4, 0,-1, 0,-1,-2, 0,-1,-2, 0,-1,-2, 0}
cvar posY:w(16) = {0, 0, 0, 0,-1,-1,-2,-2,-2,-4,-4,-4,-8,-8,-8,-16}
proc WrtBufA(di)
// フラグA のデータを書込む
// arg di 出力するバイト数
enter
save pusha,ds
go (di == 0) RET
ds.bx = gh_t
GH.SeekW bx, flagAofs
cx = di
dx.ax = ww(0,cx)
dx.ax += flagAofs
flagAofs = dx.ax
ptrA = dx = 0
ax = dbufAseg
GH.Write bx,ax.dx,cx
Deb.Chk
if (==)
Deb.SaveReg
Pri.Fmt "フラグA 書き出し:%x->%x¥N",cx,ax
Deb.LoadReg
fi
RET:
return
endproc
cvar wkAcnt:b = 8, wkAdat:b = 0
@define ResetWkA() wkAcnt = 8;wkAdat = 0
proc WrtA()
// フラグA のバッファへ1ビット書込む
// in cf
begin
|wkAdat <<=. 1
--wkAcnt
if (wkAcnt == 0)
push ax,di,es
di = ptrA
if (di >= dbufAsiz)
WrtBufA di
di = ptrA
fi
es = dbufAseg
rep.set di, wkAdat
ptrA = di
wkAcnt = 8
pop ax,di,es
fi
//Deb.PRI "WrtA¥N"
return
endproc
proc WrtBufB(di)
// フラグB のデータを書込む
// arg di 出力するバイト数
enter
save pusha,ds
go (di == 0) RET
ds.bx = gh_t
GH.SeekW bx, flagBofs
cx = di
dx.ax = ww(0, cx)
dx.ax += flagBofs
flagBofs = dx.ax
dx.ax = flagBsiz
dx.ax += ww(0, cx)
flagBsiz = dx.ax
ptrB = dx = 0
ax = dbufBseg
GH.Write bx,ax.dx,cx
Deb.Chk
if (==)
Deb.SaveReg
Pri.Fmt "フラグB 書き出し:%x->%x¥N",cx,ax
Deb.LoadReg
fi
RET:
return
endproc
proc WrtB(al)
// フラグB のバッファへ1バイト書込む
// in cf
begin
save ax,di,es
//Deb.PRI "WrtB¥N"
di = ptrB
if (di >= dbufBsiz)
WrtBufB di
di = ptrB
fi
es = dbufBseg
rep.set di, al
ptrB = di
return
endproc
proc SetBufAddr(ax, dx, cx)
// 入力バッファの分割(フラグA,フラグB,ピクセル・データ,展開用ライン・バッファ)
// arg ax バッファのセグメント
// arg dx バッファのパラグラフ・サイズ
enter
save pusha,es,ds
local topSeg:w = ax, szs:w = dx
bx = dx
flgLinBufSiz = cx
Std.ParaSize cx, dx
cx <<= 1
go (bx <= cx) ERR
bx -= cx
dx.ax = flagAsiz
if (dx || ax > ((640/4)*512/8))
ax = Mag.RDBUFA
fi
dbufAsiz = ax
Std.ParaSize ax,dx
go (bx <= ax) ERR
bx -= ax
if (bx >= 0x1000)
ax = 0x6000
bx -= 0x600
elsif (bx >= 0x800)
ax = 0x3000
bx -= 0x300
elsif (bx > 0x100)
ax = 0x800
bx -= 0x80
else
ERR:
Subr.PriExit "Magのバッファのメモリが確保できない¥N"
fi
dbufBsiz = ax
dbufPszs = bx
flgLinBufSeg = ax = topSeg
cx = flgLinBufSiz
Std.ParaSize cx,bx
ax += cx
flgLinBufSeg2 = ax
cx = flgLinBufSiz
Std.ParaSize cx,bx
ax += cx
dbufAseg = ax
cx = dbufAsiz
Std.ParaSize cx,bx
ax += cx
dbufBseg = ax
cx = dbufBsiz
Std.ParaSize cx,bx
ax += cx
dbufPseg = ax
ptrP = ww(ax,0)
ax += dbufPszs
dbufPendSeg = ax
Deb.Chk
if (==)
Pri.Fmt "A Seg=$%04x Siz=$%04x¥N",dbufBseg, dbufAsiz
Pri.Fmt "B Seg=$%04x Siz=$%04x¥N",dbufBseg, dbufBsiz
Pri.Fmt "P Seg=$%04x Siz=$%04x0¥N",dbufPseg, dbufPszs
Pri.Fmt "Top=$%04x szs=$%04x EndSeg=$%04x¥N",topSeg,szs,dbufPendSeg
fi
return
endproc
*proc InitWrite(bx)
// Mag ファイル書込みの準備
// arg si GH.T へのポインタ
enter
save pusha,es,ds
gh_t = ds.bx
hdl = dx = GHT.wrtHdl
// フラグA,フラグB,ピクセル・データの各ブロック・サイズの数と余りサイズを計算
flagAofs = dx.ax = GHT.magWflagAofs
flagBofs = dx.ax = GHT.magWflagBofs
pdataOfs = dx.ax = GHT.magWpdataOfs
flagAsiz = dx.ax = GHT.magWflagAsiz
// 256色?
c256flg = 0
if (GHT.plnW == 8)
c256flg = 1
fi
al = c256flg
ah = 0
//pusha;Pri.Fmt "256flg:%d¥N",ax;popa
//ピクセル・データ・バッファ
pdataBuf = dx.ax = ww(GHT.pdbSeg, GHT.hisSizO)
// 横幅関係
ax = GHT.sizeXo
ax >>= 2
if (c256flg == 0)
ax >>= 1
fi
vsizXh = ax //1行分のフラグ(4ビット)がしめるバイト数
//=処理上のピクセル(16色なら4ドット.256色なら2ドット)での横幅 div 2
//pusha;Pri.Fmt "vxh=%d¥N",vsizXh;popa
//メモリ分配
GH.GetMem bx, 0x400, 0xffff
dx = cx
SetBufAddr ax, dx, vsizXh
@if 0
// フラグAのブロック・サイズの数と余りサイズを計算
dx.ax = flagAsiz
div dx.ax, dbufAsiz
blkCntA = ax
rstSizA = dx
@fi
//相対位置のオフセット値を求める.
//16色時、1dot4ビット。作業1ピクセル(2byte)は4dot単位
//256 色時、1dot8ビット。作業1ピクセル(2byte)は2dot単位
cx = GHT.sizeXo
bx = 4
if (c256flg)
bx = 2
fi
ax = 0
pos(0) = ax //( 0, 0)
ax += bx
pos(1) = ax //(-1, 0)
ax += bx
pos(2) = ax //(-2, 0)
ax += bx
ax += bx
pos(3) = ax //(-4, 0)
ax = cx
pos(4) = ax //( 0,-1)
ax += bx
pos(5) = ax //(-1,-1)
ax = cx
ax <<= 1
pos(6) = ax //( 0,-2)
ax += bx
pos(7) = ax //(-1,-2)
ax += bx
pos(8) = ax //(-2,-2)
ax = cx
ax <<= 2
pos(9) = ax //( 0,-4)
ax += bx
pos(10) = ax //(-1,-4)
ax += bx
pos(11) = ax //(-2,-4)
ax = cx
ax <<= 3
pos(12) = ax //( 0,-8)
ax += bx
pos(13) = ax //(-1,-8)
ax += bx
pos(14) = ax //(-2,-8)
ax = cx
ax <<= 4
pos(15) = ax //(0,-16)
//その他の変数初期化
ResetWkA
ax = 0
ptrA = ax
ptrB = ax
flagBsiz = ww(ax,ax)
curY = ax
// フラグ展開用のライン・バッファの初期化
di = ax // = 0
cx = flgLinBufSiz
es = flgLinBufSeg
rep.set di,al,cx
cx = flgLinBufSiz
es = flgLinBufSeg2
di = ax
rep.set di,al,cx
return
endproc
proc ChkPos(al,cx,si)
// in ds
// break di,ax
begin
save ax
go (al == 0) RET0
ah = 0
di = ax
di <<= 1
ax = posY[di]
ax += curY
go (ax .<. 0) RET0
ax = posX[di]
ax += cx
go (ax .<. 0) RET0
ax = pos[di]
di = si
di -= ax
ax = w[di]
go (ax != w[si]) RET0
if (c256flg == 0)
ax = w[di+2]
go (ax != w[si+2]) RET0
fi
stc
return
RET0:
clc
return
endproc
proc PosNo (al,cx,si)
// 相対位置のピクセルと比較し、一致する番号を求める。
// 一致しなかったばあいは、ピクセル・データを出力
// arg al 1行間上のフラグの番号
// arg si ピクセル・データ・バッファでの現在位置
// in ds ピクセル・データ・バッファのセグメント
// out al 相対位置番号 0〜15 (0:一致しなかった)
// break di
begin
//Deb.PRI "PosNo¥N"
block
ChkPos al,cx,si; break (_c_)
ChkPos 1,cx,si; break (_c_)
ChkPos 4,cx,si; break (_c_)
ChkPos 5,cx,si; break (_c_)
ChkPos 6,cx,si; break (_c_)
ChkPos 7,cx,si; break (_c_)
ChkPos 9,cx,si; break (_c_)
ChkPos 10,cx,si; break (_c_)
ChkPos 2,cx,si; break (_c_)
ChkPos 8,cx,si; break (_c_)
ChkPos 11,cx,si; break (_c_)
ChkPos 12,cx,si; break (_c_)
ChkPos 13,cx,si; break (_c_)
ChkPos 14,cx,si; break (_c_)
ChkPos 3,cx,si; break (_c_)
ChkPos 15,cx,si; break (_c_)
go L_ZERO
endblock
return
L_ZERO:
/* ピクセル・データ・バッファへ2バイト書込む */
push ax,si,es
ax.di = ptrP
if (ax >= dbufPendSeg)
Subr.PriExit "メモリが足り無くなった(ピクセル・データのバッファが溢れた)¥N"
fi
es = ax
if (c256flg)
rep.cpy.w di, si
else
rep.load.w ax,si
al <<= 4
ah &= 0x0f
al |= ah
rep.set di, al
rep.load.w ax,si
al <<= 4
ah &= 0x0f
al |= ah
rep.set di, al
fi
ax = es
Std.FpToHp ax,di, si
ptrP = ax.di
pop ax,si,es
al = 0 // 一致しなかったら、位置番号は 0
return
endproc
*proc WritePDB(ght:d,lincnt:w);cdecl
// ピクセル・データ・バッファ ax 行, MAGに変換
// arg si GH.T へのポインタ(ダミー)
// arg ax 行数
enter
save pusha,es,ds
local pdptr:d, cnt:w, ofs:w
cnt = ax = lincnt
ofs = 4
if (c256flg)
ofs = 2
fi
pdptr = dx.si = pdataBuf
// 指定行数分、ループ
loop.w
si = pdptr.l
cx = bx = 0
loop
ds = flgLinBufSeg2
ah = al = b[bx]
ds = flgLinBufSeg
b[bx] = al
ah &= 0x0f
al >>= 4
ds = pdptr.h
PosNo al,cx,si
si += ofs
++cx
al <<= 4
ah <=> al
PosNo al,cx,si
si += ofs
al |= ah
ds = flgLinBufSeg2
b[bx] = al
ds = flgLinBufSeg
b[bx] ^= al
++bx
++cx
endloop (bx < vsizXh)
pdptr.l = si
//ds = flgLinBufSeg
si = 0
cx = vsizXh
loop
rep.load al,si
if (al == 0)
clc
WrtA
else
stc
WrtA
WrtB al
fi
endloop (--cx)
@if 0
Deb.Chk
if (==)
Pri.Word curY
Pri.Chr '¥r'
fi
@fi
++curY
endloop (--cnt)
return
endproc
*proc CloseW(ght:d);cdecl
//*proc Flush(ght:d);cdecl
//バッファの残りを掃き出す
enter
save pusha,es,ds
local tmp:d
local pdataOfs:d,pdataSiz:d
//Deb.PRI "FLush¥N"
cl = wkAcnt
if (cl < 8 /* && cl > 0*/)
ch = 0
loop
clc
WrtA
endloop (--cx)
fi
WrtBufA ptrA
WrtBufB ptrB
ds.bx = ght
// フラグBのサイズを収める位置へシーク
dx.ax = GHT.magWhdrOfs
dx.ax += 20
GH.SeekW bx, dx.ax
// フラグBのサイズを書込む
dx = &tmp
ax.di = flagBsiz
tmp = ax.di
cx = 4
GH.Write bx, ss.dx, cx
//Pri.Fmt "sizeB = %ld(%lx)¥N", tmp, tmp
// ピクセル・データのオフセットを書込む
ax.di = GHT.magWflagBofs0
//Pri.Fmt "flagBofs0 = %lx¥N", ax.di
ax.di += tmp
if (di & 0x01)
ax.di += 1
fi
tmp = ax.di
pdataOfs = ax.di
GH.Write bx, ss.dx, cx
//Pri.Fmt "pdataOfs = %lx¥N", tmp
// ピクセル・データのサイズを書込む
ax.di = ptrP
ax -= dbufPseg
Std.FpToDw ax,di, cx
tmp = ax.di
pdataSiz = ax.di
GH.Write bx, ss.dx, 4
//Pri.Fmt "sizeP = %ld(%lx)¥N", tmp, tmp
// ピクセル・データの先頭へシーク
dx.ax = GHT.magWhdrOfs
//Pri.Fmt "hdrPos = %lx¥N", dx.ax
dx.ax += pdataOfs
//Pri.Fmt "pdatPos = %lx¥N", dx.ax
GH.SeekW bx, dx.ax
// ピクセル・データを書込む
di.cx = pdataSiz
//Pri.Fmt "sizeP = %ld(%lx)¥N", di.cx, di.cx
push cx
dx = 0
ax = dbufPseg
if (di)
cx = 0x8000
loop
GH.Write bx, ax.dx, cx
ax += 0x800
GH.Write bx, ax.dx, cx
ax += 0x800
endloop (--di)
fi
pop cx
if (cx)
GH.Write bx, ax.dx, cx
fi
GH.CloseW ds.bx
return
endproc
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
*proc InitW(ght:d);cdecl
enter
save ax,ds,bx
ds.bx = ght
GH.SetHisLin bx,16
GHT.wrtX8flg = 1
//GH.Df_wrtX8mode 1
GHT.fmtW = GH.MAG
return
endproc
cvar hdrHdl:w
proc InitPutC(ax)
begin
hdrHdl = ax
return
endproc
proc Err()
begin
dx = ax
Pri.S "MAGヘッダ書込みでエラー #"; Pri.Int dx; Pri.Cr
Dos.Exit(1)
endproc
proc PutC(al)
begin
save pusha,ax,bx,cx,dx,ds
var gcbuf:b
ds = bx = %var
gcbuf = al
Dos.Write hdrHdl,&gcbuf,1
if (_c_)
Err
fi
return
endproc
proc PutW(ax)
begin
save pusha,ax,bx,cx,dx,ds
var gcbuf:w
ds = bx = %var
gcbuf = ax
Dos.Write hdrHdl,&gcbuf,2
if (_c_)
Err
fi
return
endproc
proc PutD(dx.ax)
begin
save pusha,ax,bx,cx,dx,ds
var gcbuf:d
ds = bx = %var
gcbuf = dx.ax
Dos.Write hdrHdl,&gcbuf,4
if (_c_)
Err
fi
return
endproc
*proc Create(ght:d,filename:d);cdecl
// Magファイルのヘッダ出力
// arg si GH.T へのポインタ
// arg dx ファイル名
// out ax 0:成功 以外:エラー
enter
save bx,cx,dx,si,di,es,ds
cvar fmt:b() = "MAG"
ds.bx = ght
GHT.wrtFmtName = dx.ax = ww(cs,&fmt)
//GHT.fmtW = GH.MAG
//GHT.wrtX8flg = 1
es = ds
GH.Create bx, filename
InitPutC GHT.wrtHdl
//ID出力
GH.Write bx,ww(%var,"MAKI02 "),8
//セーバ機種名出力
if (GHT.macNameMode == 0)
GH.Write bx,ww(ds,&GHT.macName), 4
else
GH.Write bx,ww(%var,"MG "), 4
fi
PutC ' '
//ユーザ名出力
cx = GHT.userNameLen
if (cx)
if (cx >= 18)
cx = 18
fi
GH.Write bx, GHT.userName, cx
if (cx < 18)
cx -= 18
neg cx
GH.Write bx, ww(%var," "), cx
fi
else
GH.Write bx, ww(%var,">謎< "), 18
fi
//コメント出力
cx = GHT.commentLen
if (cx)
PutC ' '
es.di = GHT.comment
loop
al = b[es:di];++di
break (al == 0 || al == 0x1a)
PutC al
endloop
fi
PutC 0x1a
//ヘッダ先頭のシーク位置を取得
push bx
bx = GHT.wrtHdl
cx.dx = 0
al = 1
Dos.Lseek bx,cx.dx,al
if (_c_)
Subr.PriExit "シーク・エラー(Magヘッダ)¥N"
fi
pop bx
GHT.magWhdrOfs = dx.ax
//ヘッダ本体
PutC 0x00 //ヘッダ先頭
if (GHT.bakCol)
PutC 98
al = GHT.bakCol.l
--al
al |= 0x10
PutC al
else
PutC GHT.magMacNo //機種コード
PutC GHT.magMacFlg //機種依存フラグ
fi
//200ラインフラグを立てるかどうか
ah = 0
al = GHT.asp1
dl = GHT.asp2
if (al && dl)
div ax,dl
ah = al
fi
al = GHT.magScrnMode
al &= (‾(Mag.MF_200L|Mag.MF_256C))&0xff
if (ah >= 2)
al |= Mag.MF_200L
fi
//256色か
if (GHT.plnW == 8)
al |= Mag.MF_256C
fi
PutC al //スクリーン・フラグ
//始点、終点
PutW GHT.startX
PutW GHT.startY
PutW GHT.endX
PutW GHT.endY
//フラグA のオフセット
dx = ax = GHT.col
ax += ax; ax += dx // ax = ax * 3
ax += 32
dx = 0
PutD dx.ax
bx.cx = dx.ax
dx.ax += GHT.magWhdrOfs
GHT.magWflagAofs = dx.ax
//フラグA のサイズ計算
dx.ax = GHT.sizeXo * GHT.sizeY
if (GHT.plnW == 8)
@if 0
if (GHT.startXofs>3 || (GHT.endXofs>0 && GHT.endXofs<5))
Pri.Fmt "ごめん... この256MAG生成は誤変換する可能性大です.¥N"
//Dos.EXIT (1)
fi
@fi
if (ax & 0x1f)
dx.ax += 4*8
fi
dx.ax >>= 5 //dx.ax /= 4*8
else
if (ax & 0x3f)
dx.ax += 4*2*8
fi
dx.ax >>= 6 //dx.ax /= 4*2*8
fi
if (ax & 0x01)
dx.ax += 1
fi
GHT.magWflagAsiz = dx.ax
//フラグB のオフセット
dx.ax += bx.cx
PutD dx.ax
GHT.magWflagBofs0 = dx.ax
dx.ax += GHT.magWhdrOfs //seek
GHT.magWflagBofs = dx.ax
//フラグB のサイズ(ダミー...後で設定)
PutD 0
//ピクセル・データのオフセット(ダミー...後で設定)
PutD 0
//ピクセル・データのサイズ(ダミー...後で設定)
PutD 0
//パレット
cx = GHT.col
es.di = GHT.rgbPal
loop
al = b[es:di + 1] //G
PutC al
al = b[es:di + 0] //R
PutC al
al = b[es:di + 2] //B
PutC al
di += 3
endloop (--cx)
//
InitWrite bx
//ヘッダ出力おわり
ax = 0
return
endproc
endmodule
-
- Posts: 39
- Joined: Sat Sep 10, 2016 11:29 pm
Re: MAKIchan image format?
It's also worth mentioning that the Makichan supported many more platforms than just the PC98. Namely, it supported: PC98, PC88, MSX2, MSX2+, X68000, FM-Towns and Mac. I believe it's the only multi-platform image format that has full support for the MSX2/2+ advanced screen modes (interlace, high-color, etc).
More info in English can be found here.
Gazillions of MAG images for all major Japanese computer platforms can be found at the Retro Gallery. This image format was more important in Japan at that time than GIF or IFF were for the contemporary IBM-PC and Amiga.
Some Japanese artists still publish MAG files up to these days.
More info in English can be found here.
Gazillions of MAG images for all major Japanese computer platforms can be found at the Retro Gallery. This image format was more important in Japan at that time than GIF or IFF were for the contemporary IBM-PC and Amiga.
Some Japanese artists still publish MAG files up to these days.