Editor's note: gradually, a man who is a programmer and adds a house man has gone from being no longer interested in third-dimensional things to the realm of happiness only when he watches 16-color pictures. In order to have more pictures to see, a male downloads a large number of pc98 Rom. However, the most unfortunate thing is that there is no memory mode for classic games such as alicesoft's House of Alice and Lance !! Now, we have to force image resolution. After someone sets this ambitious goal, they start looking for the DOS version everywhere ...... Unfortunately, it was not found; so someone began to look for the anti-compiler under pc98, but it was not easy to use; so someone downloaded the source code of Neko projectii, then it took 2 months to write a disassembly plug-in (http://download.csdn.net/source/1234900 )...... Then it took another week to finally work out the image ......
According to tests, except for Ayumi real, Doux City, all other file names such as ACG. dat and BCG. Dat can be unlocked.
The following describes the format.
Basically, all the. DAT files in the game are a VFS (although this term may not exist at the time), and? CG. dat is the packaging of all CG. Each graph has a relative coordinate, which can be attached to another graph to form an animation.
The word-1 in the first two bytes indicates the maximum number of pages in the file. Number of pages, the index position occupies the number of pages * 256 bytes. For example, if the value is 2, the data starts from 256th bytes (this data is not an image, and the real image index should refer to the index number)
The index in the unit of word starts to contain 3rd bytes. Each index needs to be-1 first and then * 256. For example, indicates that the image starts from H bytes. What about the size of the compressed image? It can be calculated based on the Start byte of the next index. For example, if the next byte is, it indicates that the next image starts from h, and the difference is the size of the image.
Image compression method:
The first few bytes are relative coordinates and length and width. For details, see the code. Then there is a 48-byte color palette, each color uses only four lower bits, so you need to move four to the left. (Not rough. After research, we found that pc98 is 4 K color ......) Encoding is a code similar to a process code. It scans from left to right and has eight control codes, it indicates that n Bytes are repeated, n Bytes are copied from the left column, n Bytes are copied from the previous bit plane, and so on (the bit plane knowledge is outdated, it doesn't matter if you don't know .) The compression efficiency is average, but it is better than the common process code.
No more nonsense. paste the code. Compiled on vs2003. The usage is ACG *. dat (*. Dat can be changed to another one. If an error occurs, you can specify the file directly or not. The default value is * cg.dat.pdf, And the generated file is named "number .bmp.
// ACG. cpp: defines the entry point for the console application.
//
# Include "stdafx. H"
# Include "stdlib. H"
# Include <windows. h>
# Include "Io. H"
# Pragma warning (Disable: 4996)
Typedef struct _ tag_act {
Unsigned char * Buf;
Int buf_size;
Unsigned char palette [48];
Unsigned char * work_buf;
Unsigned char * BMP _data;
} Acg_t;
Void acg_init (acg_t * REC)
{
REC-> Buf = NULL;
REC-> BMP _data = NULL;
REC-> work_buf = NULL;
}
Int acg_count (acg_t * rec, const char * filename)
{
File * fp = fopen (filename, "rb ");
Unsigned short pages = 0;
Unsigned short * indexes = NULL;
Fread (& pages, sizeof (short), 1, FP );
Int words = pages * 256/2-2;
Indexes = (unsigned short *) malloc (INT) words * 2-2 );
Fread (indexes, (INT) words * 2-2, 1, FP );
Fclose (FP );
Int COUNT = 0;
For (INT I = 0; I <words-1; ++ I ){
If (indexes [I] = 0) break;
++ Count;
}
Return count;
}
Int acg_load (acg_t * rec, const char * filename, int index)
{
File * fp = fopen (filename, "rb ");
Unsigned short pages = 0;
Unsigned short * indexes = NULL;
Fread (& pages, sizeof (short), 1, FP );
Int words = pages * 256/2-2;
Indexes = (unsigned short *) malloc (INT) words * 2-2 );
Fread (indexes, (INT) words * 2-2, 1, FP );
If (index> = words ){
Printf ("error: Index out of bound/N ");
Return 0;
}
Long offset = (INT) (indexes [Index]-1) * 256;
Long size = (INT) (indexes [index + 1]-1) * 256-offset;
REC-> Buf = (unsigned char *) malloc (size );
REC-> buf_size = size;
Fseek (FP, 0, seek_set );
Fseek (FP, offset, seek_set );
Fread (REC-> Buf, 1, size, FP );
Fclose (FP );
Return Offset> 0 & size> 0;
}
Void acg_free (acg_t * REC)
{
If (REC-> BUF ){
Free (REC-> BUF );
REC-> Buf = NULL;
}
If (REC-> BMP _data ){
Free (REC-> BMP _data );
REC-> BMP _data = NULL;
}
If (REC-> work_buf ){
Free (REC-> work_buf );
REC-> work_buf = NULL;
}
}
Void acg_decode (acg_t * rec, const char * target_file)
{
If (! REC-> BUF) return;
# Define read_word (p) * (unsigned short *) (p );
Unsigned char * P = rec-> Buf;
Unsigned char * p_max = & rec-> Buf [Rec-> buf_size];
Unsigned short left = read_word (P );
P + = 2;
Unsigned Short top = read_word (P );
P + = 2;
Unsigned short right = read_word (P );
P + = 2;
Unsigned short Bottom = read_word (P );
P + = 2;
Unsigned short width = right-left;
Unsigned short height = bottom-top;
If (left! = 0 | top! = 0 ){
/// Printf ("Warning: Not Main picture/N ");
/// Return;
Right = width;
Left = 0;
Bottom = height;
Top = 0;
}
If (width> 300 | height> 10000 ){
Printf ("bad picture/N ");
Return;
}
P + = 2; // not used
/// 48 byte palette
Memcpy (REC-> palette, P, 0x30 );
P + = 0x30;
Unsigned char bg_mask = 0;
Int BPL = width;
REC-> work_buf = (unsigned char *) malloc (BPL * 4 * Height );
Memset (REC-> work_buf, 0, BPL * 4 * Height );
Unsigned char * DEST = rec-> work_buf;
Unsigned char * dest_max = & rec-> work_buf [BPL * 4 * Height];
Unsigned short Y = top; // DX
Unsigned short x = left;
Unsigned short Cx = 0;
While (x <right ){
For (INT plane = 0; plane <4; ++ plane ){
DeST = rec-> work_buf + BPL * height * plane + X;
Y = top;
While (Y <bottom ){
If (P> = p_max) break;
Unsigned char Al = * P ++;
Unsigned char Ah = 0;
Switch (Al ){
Case 0:
{
/// Loc_2e2: copy left column for CX bytes
If (P> = p_max) break;
Al = * P ++;
Cx = Al;
++ CX;
Y + = Cx;
/// If (x = 10 & Y = 64) _ asm int 3;
Unsigned char * PBX = dest-1;
Do {
If (DEST> = dest_max) break;
* DEST = * PBX;
DeST + = BPL;
PBX + = BPL;
} While (-- CX> 0 );
}
Break;
Case 1:
{
/// Loc_311: store same color for CX bytes
If (P> = p_max) break;
Al = * P ++;
Cx = Al;
++ CX;
Y + = Cx;
If (P> = p_max) break;
Al = * P ++;
Do {
If (DEST> = dest_max) break;
* DEST = Al;
DeST + = BPL;
} While (-- CX> 0 );
}
Break;
Case 2:
{
/// Loc_326: store 2 colors for CX times
If (P> = p_max) break;
Al = * P ++;
Cx = Al;
++ CX;
Y + = Cx;
Y + = Cx;
If (P> = p_max) break;
Al = * P ++;
If (P> = p_max) break;
Ah = * P ++;
Do {
If (DEST <dest_max ){
* DEST = Al;
}
DeST + = BPL;
If (DEST <dest_max ){
* DEST = Ah;
}
DeST + = BPL;
} While (-- CX> 0 );
}
Break;
Case 3: // flash a800 // loc_349 (copy from plane0)
Case 4: // flash b000 // loc_374 (copy from plane1)
Case 5: // flash b800 // loc_39f (copy from plane2)
{
/// Loc_349: XOR original picture of bg_mask for CX bytes and clear bg_mask
Unsigned char * src = rec-> work_buf + BPL * height x (al-3) + y * BPL + X;
If (P> = p_max) break;
Al = * P ++;
Cx = Al;
++ CX;
Y + = Cx;
Ah = bg_mask;
Do {
If (SRC <dest_max & DEST <dest_max ){
* DEST = * SRC ^ Ah;
}
DeST + = BPL;
SRC + = BPL;
} While (-- CX> 0 );
Bg_mask = 0;
}
Break;
Case 6: // loc_3ca
{
Bg_mask = 0xff;
}
Break;
Case 7: // loc_3d7
{
If (DEST> = dest_max) break;
If (P> = p_max) break;
* DEST = * P ++;
++ Y;
/// If (* DEST> = 8) _ asm int 3;
DeST + = BPL;
}
Break;
Default: //> = 8
If (DEST <dest_max ){
* DEST = Al;
}
++ Y;
DeST + = BPL;
Break;
}
}
}
++ X;
}
Unsigned char * bits_buffer = (unsigned char *) malloc (BPL * 4 * Height );
Memset (bits_buffer, 0, BPL * 4 * Height );
For (Int J = 0; j Unsigned char * src0 = rec-> work_buf + (BPL * height * 0) + (height-j) * BPL;
Unsigned char * src1 = rec-> work_buf + (BPL * height * 1) + (height-j) * BPL;
Unsigned char * src2 = rec-> work_buf + (BPL * height * 2) + (height-j) * BPL;
Unsigned char * src3 = rec-> work_buf + (BPL * height * 3) + (height-j) * BPL;
DeST = bits_buffer + J * BPL * 4;
/// A0b0c0d0e0f01_h0 (src0)
/// A1b1c1d1e1f1g1h1 (src1)
/// A2b2c2d2e2f2g2h2 (src2)
/// A3b3c3d3e3f4243h3 (src3)
/// => A0123 b0123 | c0123 d0123 | e0123 f0123 | 2017123 h0123
/// Dest [0] Dest [1] Dest [2] Dest [3]
For (INT I = 0; I <BPL; ++ I, ++ src0, ++ src1, ++ src2, ++ src3 ){
If (* src0 & 0x80) Dest [0] | = 0x10;
If (* src1 & 0x80) Dest [0] | = 0x20;
If (* src2 & 0x80) Dest [0] | = 0x40;
If (* src3 & 0x80) Dest [0] | = 0x80;
If (* src0 & 0x40) Dest [0] | = 0x01;
If (* src1 & 0x40) Dest [0] | = 0x02;
If (* src2 & 0x40) Dest [0] | = 0x04;
If (* src3 & 0x40) Dest [0] | = 0x08;
If (* src0 & 0x20) Dest [1] | = 0x10;
If (* src1 & 0x20) Dest [1] | = 0x20;
If (* src2 & 0x20) Dest [1] | = 0x40;
If (* src3 & 0x20) Dest [1] | = 0x80;
If (* src0 & 0x10) Dest [1] | = 0x01;
If (* src1 & 0x10) Dest [1] | = 0x02;
If (* src2 & 0x10) Dest [1] | = 0x04;
If (* src3 & 0x10) Dest [1] | = 0x08;
If (* src0 & 0x08) Dest [2] | = 0x10;
If (* src1 & 0x08) Dest [2] | = 0x20;
If (* src2 & 0x08) Dest [2] | = 0x40;
If (* src3 & 0x08) Dest [2] | = 0x80;
If (* src0 & 0x04) Dest [2] | = 0x01;
If (* src1 & 0x04) Dest [2] | = 0x02;
If (* src2 & 0x04) Dest [2] | = 0x04;
If (* src3 & 0x04) Dest [2] | = 0x08;
If (* src0 & 0x02) Dest [3] | = 0x10;
If (* src1 & 0x02) Dest [3] | = 0x20;
If (* src2 & 0x02) Dest [3] | = 0x40;
If (* src3 & 0x02) Dest [3] | = 0x80;
If (* src0 & 0x01) Dest [3] | = 0x01;
If (* src1 & 0x01) Dest [3] | = 0x02;
If (* src2 & 0x01) Dest [3] | = 0x04;
If (* src3 & 0x01) Dest [3] | = 0x08;
DeST + = 4;
}
}
Bitmapfileheader BFH;
Bitmapinfoheader BMI;
Memset (& BFH, 0, sizeof (bitmapfileheader ));
BFH. bftype = 'mb ';
BFH. bfsize = sizeof (bitmapfileheader) + sizeof (bitmapinfoheader );
BFH. bfoffbits = sizeof (bitmapfileheader) + sizeof (bitmapinfoheader) + 64;
Memset (& BMI, 0, sizeof (bitmapinfoheader ));
BMI. bisize = sizeof (bitmapinfoheader );
BMI. bisizeimage = BPL * 4 * height;
BMI. biwidth = BPL * 8;
BMI. biheight = height;
BMI. biplanes = 1;
BMI. bibitcount = 4;
BMI. biclrused = 16;
BMI. biclrimportant = 16;
File * fp = fopen (target_file, "WB ");
Fwrite (& BFH, 1, sizeof BFH, FP );
Fwrite (& BMI, 1, sizeof BMI, FP );
Char palette [64];
/// PIC: g r B bmp: r g B
For (INT I = 0; I <16; ++ I ){
Palette [I * 4 + 0] = (REC-> palette [I * 3 + 0] <4) + 0xf;
Palette [I * 4 + 1] = (REC-> palette [I * 3 + 2] <4) + 0xf;
Palette [I * 4 + 2] = (REC-> palette [I * 3 + 1] <4) + 0xf;
Palette [I * 4 + 3] = 0;
}
Fwrite (palette, 4, 16, FP );
Fwrite (bits_buffer, 1, BPL * height * 4, FP );
Fclose (FP );
Free (bits_buffer );
}
Int _ tmain (INT argc, _ tchar * argv [])
{
Char * input_files = "* CG. dat ";
If (argc = 2 ){
Input_files = argv [1];
}
If (argc> 2 ){
Printf ("Usage: ACG [ACG files (e.g: * CG. dat)]/n ");
Return-1;
}
Acg_t REC;
Acg_init (& REC );
Struct _ finddata_t;
Long handle;
If (handle = (long) _ findfirst (input_files, & T ))! =-1)
{
Char target_file [1, 260];
Do
{
Strcpy (target_file, T. Name );
Char * dot_pos = strrchr (target_file ,'.');
Printf ("processing: % s.../N", target_file );
If (dot_pos) * dot_pos = '/0 ';
Char Templ [_ max_path];
Strcpy (Templ, target_file );
Strcat (target_file, ". BMP ");
Int n = acg_count (& rec, T. Name );
For (INT I = 0; I <n; ++ I ){
If (! Acg_load (& rec, T. Name, I) continue;
Char Buf [_ max_path];
Sprintf (BUF, "%s0000003d.bmp", Templ, I );
Printf ("generating: % s...", Buf );
Acg_decode (& rec, Buf );
Acg_free (& REC );
Printf ("done/N ");
}
Printf ("done./N ");
} While (_ findnext (handle, & T )! =-1 );
}
Return 0;
}