# HG changeset patch # User Emmanuel Gil Peyrot # Date 1312287481 -7200 # Node ID b1bec4b5ccf317a3c1d19346d124d99ea9775f39 # Parent f82309a9465ed8a89a9fcb51933d2e2709e341e9 Add anm and pbg3 file formats, and improve the std one. diff --git a/06/anm.xml b/06/anm.xml new file mode 100644 --- /dev/null +++ b/06/anm.xml @@ -0,0 +1,225 @@ + + + + + + ANM opcodes + + + 0 + + + + 1 + set_sprite + + Sprite number. + + Displays a certain sprite, or change from the previous sprite. + + + + 2 + set_scale + + X factor. + Y factor. + + Resizes the current sprite. + + + + 3 + + + + + + + 4 + + + + + + + 5 + + + + + + + 7 + set_mirror + Performs a scale of -1 on the x axis. + + + + 9 + set_3d_rotation + + -x + y + -z + + Set a rotation for the current object. + + + + 10 + + + + + + + + + 11 + + + + + + + + 12 + + + + + + + + 13 + + + + 14 + + + + 15 + A kind of return + + + + 16 + + + + + + + + 17 + + + + + + + + + 18 + + + + + + + + + + 19 + + + + + + + + + + 20 + + + + + + + + + + 21 + + + + 22 + + + + + + + 23 + set_origin + Apply transformations to the center of the quad, instead of its bottom-left corner. + + + + 24 + + + + 25 + + + + + + + 26 + + + + + + + 27 + + + + + + + 28 + + + + + + + 29 + + + + + + + 30 + + + + + + + + + 31 + + + + + diff --git a/06/pbg3.xhtml b/06/pbg3.xhtml new file mode 100644 --- /dev/null +++ b/06/pbg3.xhtml @@ -0,0 +1,61 @@ + + + + + + PBG3 format + + +

PBG3 format

+

The PBG3 format is an archive format used by EoSD.

+ +

It is a bitstream composed of a header, a file table, and LZSS-compressed files.

+ + +

Reading integers

+

Integers in PBG3 files are never signed, they are not byte-aligned, and have a variable size.
+ Their size is given by two bits: 00 means the number is stored in one byte, 10 means it is stored in three bytes.

+ +

Ex:

+
+    0x0012 is stored as: 0000010010
+    0x0112 is stored as: 010000000100010010
+
+ + +

Reading strings

+

Strings are stored as standard NULL-terminated sequences of bytes.
+ The only catch is they are not byte-aligned.

+ + +

Header

+

The header is composed of three fields:

+ + +

The size of the header is thus comprised between 52 bits and 100 bits.

+ + +

File table

+

The file table starts at a byte boundary, but as the rest of the file, isn't byte-aligned.
+ It consists of a sequence of entries.
+ Each entry is composed of five fields:

+ + +

The checksum is a mere sum of the compressed data.
+ Files are compressed using the LZSS algorithm, with a dictionary size of 8192 bytes and a minimum matching length of 4 bytes.
+ The size of the offset component of (offset, length) tuples is 13 bits, whereas the size of the length component is 4 bits.
+ A file ends with a (0, 0) tuple, that is, 18 zero bits.

+ +

Uncompressing a LZSS-compressed file is quite easy, see lzss.py.

+ + diff --git a/06/std.xhtml b/06/std.xhtml --- a/06/std.xhtml +++ b/06/std.xhtml @@ -1,34 +1,135 @@ + - + STD format

STD format

-

All integers are little endian, all number are hex.

Header

-
-0 - 2 - 
-2 - 2 - 
-4 - 4 - Size of something
-8 - 2 - 
-a - 6 - Always zero
-10 - 80 - Name of the stage
-90 - 80 - Name of the first song
-110 - 80 - Name of the second song
-190 - 80 - A string of only a single whitespace
-210 - 80 - A string of only a single whitespace
-290 - 80 - path to the first song (as midi)
-310 - 80 - path to the second song (as midi)
-390 - 80 - A string of only a single whitespace
-410 - 80 - A string of only a single whitespace
-490 - ... - The real data
+
+typedef struct {
+    uint16_t nb_objects; //TODO
+    uint16_t nb_faces; //TODO
+    uint32_t faces_offset; //TODO
+    uint32_t messages_offset; //TODO
+    uint32_t unknown; //TODO: always 0
+    char stage_name[128]; // Name of the stage in SHIFT_JIS
+    char song1_name[128]; // Name of the first song in SHIFT_JIS
+    char song2_name[128]; // Name of the second song in SHIFT_JIS
+    char song3_name[128]; // ? A single blank if unused
+    char song4_name[128]; // ? A single blank if unused
+    char song1_path[128];
+    char song2_path[128];
+    char song3_path[128]; // ? A single blank if unused
+    char song4_path[128]; // ? A single blank if unused
+} thstd_header_t;
+
+ +

First section

+

This section is responsible for creating objects from the stgxbg.anm file.

+
+struct object_header {
+    uint16_t id; // Always equal to the object's number. Not used by the game.
+    uint16_t unknown1; //TODO
+    float unknown2; //TODO
+    uint32_t unknown3; //TODO
+    float unknown4; //TODO
+    float unknown5; //TODO
+    float unknown6; //TODO
+    float unknown7; //TODO
+};
+
+typedef struct {
+    uint16_t unknown; // 0 means a quad, 0xffff means the end.
+    uint16_t size; // 0x1c for a quad, 4 for the end marker.
+    uint16_t script_index; // Index of a script entry in the corresponding anm file
+    uint16_t _padding; // Unused, padding
+    float x; // x coordinate of the bottom-left corner of the quad
+    float y; // y coordinate of the bottom-left corner of the quad
+    float z; // z coordinate of the bottom-left corner of the quad
+    float width; // If 0, defaults to 32.0f
+    float height; // If 0, defaults to 32.0f
+} thstd_object_t;
+
+struct object {
+    struct object_header header;
+    struct object_quad quads[]; // Stop when quads.unknown1 == 0x0004ff
+};
+
+ +

The following description is symbolic.

+
+struct section1 {
+    uint32_t offsets[]; // header.nb_objects offsets towards objects
+};*/
+
+ -

Data

-
-0 - ... - ...
+		

Second section

+

This section is responsible for placing objects from section 1 in the space.

+
+typedef struct {
+    uint16_t object_id; // must not exceed header.nb_objects
+    uint16_t unknown1; // Always 256, doesn't seem to change anything
+    float x;
+    float y;
+    float z;
+} thstd_face_t;
+// ends with 16 \xFF
+
+ + + +

Third Section

+

This section is responsible for camera movement, color effects, and such things.

+
+typedef struct {
+    uint32_t frame_num;
+    uint16_t type; // 1=colormsg
+    uint16_t unknown; //TODO: Probably the size of the message, always 0x0c, ignored by the game
+    uint32_t arg1;
+    float arg2;
+    float arg3;
+} thstd_message_t;
+
+typedef struct {
+    uint8_t b;
+    uint8_t g;
+    uint8_t r;
+    uint8_t unknown1; // Seems useless. padding?
+} color_t;
+
+typedef struct {
+    color_t color;
+    float opacity_gradient_start; //TODO
+    float opacity_gradient_stop; //TODO
+} thstd_colormsg_t;
+
+typedef struct {
+    float x;
+    float y;
+    float z;
+} thstd_cameramsg_t;
+// ends with 20 \xFF
+
+ + + + + + + +
+typedef struct {
+    thstd_header_t header;
+    uint32_t* offsets;
+    list_t objects;
+    list_t faces;
+    list_t messages;
+} PACK_ATTRIBUTE thstd_t;
 
diff --git a/index.xhtml b/index.xhtml --- a/index.xhtml +++ b/index.xhtml @@ -1,6 +1,6 @@ - + Touhou @@ -9,23 +9,26 @@

Embodiment of Scarlet Devil

Formats

Opcodes

Mountain of Faith

Subterranean Animism

+ +

The sources are here