changeset 1:b1bec4b5ccf3

Add anm and pbg3 file formats, and improve the std one.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 02 Aug 2011 14:18:01 +0200
parents f82309a9465e
children 0a7e6e3d5327
files 06/anm.xml 06/pbg3.xhtml 06/std.xhtml index.xhtml
diffstat 4 files changed, 415 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/06/anm.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet type="text/xsl" href="../html.xsl"?>
+<?xml-stylesheet type="text/css" href="../style.css"?>
+<!DOCTYPE html>
+<opcodes xmlns="urn:opcodes:description">
+	<title>ANM opcodes</title>
+
+	<op>
+		<num>0</num>
+	</op>
+
+	<op>
+		<num>1</num>
+		<name>set_sprite</name>
+		<params>
+			<param type="S">Sprite number.</param>
+		</params>
+		<desc>Displays a certain sprite, or change from the previous sprite.</desc>
+	</op>
+
+	<op>
+		<num>2</num>
+		<name>set_scale</name>
+		<params>
+			<param type="f" default="in the sprite section">X factor.</param>
+			<param type="f" default="in the sprite section">Y factor.</param>
+		</params>
+		<desc>Resizes the current sprite.</desc>
+	</op>
+
+	<op>
+		<num>3</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>4</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>5</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>7</num>
+		<name>set_mirror</name>
+		<desc>Performs a scale of -1 on the x axis.</desc>
+	</op>
+
+	<op>
+		<num>9</num>
+		<name>set_3d_rotation</name>
+		<params>
+			<param type="f">-x</param>
+			<param type="f">y</param>
+			<param type="f">-z</param>
+		</params>
+		<desc>Set a rotation for the current object.</desc>
+	</op>
+
+	<op>
+		<num>10</num>
+		<params>
+			<param type="f"></param>
+			<param type="S"></param>
+			<param type="f"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>11</num>
+		<params>
+			<param type="f"></param>
+			<param type="f"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>12</num>
+		<params>
+			<param type="S"></param>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>13</num>
+	</op>
+
+	<op>
+		<num>14</num>
+	</op>
+
+	<op>
+		<num>15</num>
+		<desc>A kind of return</desc>
+	</op>
+
+	<op>
+		<num>16</num>
+		<params>
+			<param type="S"></param>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>17</num>
+		<params>
+			<param type="f"></param>
+			<param type="f"></param>
+			<param type="f"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>18</num>
+		<params>
+			<param type="f"></param>
+			<param type="f"></param>
+			<param type="S"></param>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>19</num>
+		<params>
+			<param type="f"></param>
+			<param type="f"></param>
+			<param type="S"></param>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>20</num>
+		<params>
+			<param type="f"></param>
+			<param type="f"></param>
+			<param type="f"></param>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>21</num>
+	</op>
+
+	<op>
+		<num>22</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>23</num>
+		<name>set_origin</name>
+		<desc>Apply transformations to the center of the quad, instead of its bottom-left corner.</desc>
+	</op>
+
+	<op>
+		<num>24</num>
+	</op>
+
+	<op>
+		<num>25</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>26</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>27</num>
+		<params>
+			<param type="f"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>28</num>
+		<params>
+			<param type="f"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>29</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>30</num>
+		<params>
+			<param type="f"></param>
+			<param type="f"></param>
+			<param type="S"></param>
+		</params>
+	</op>
+
+	<op>
+		<num>31</num>
+		<params>
+			<param type="S"></param>
+		</params>
+	</op>
+</opcodes>
new file mode 100644
--- /dev/null
+++ b/06/pbg3.xhtml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet type="text/css" href="../style.css"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+	<head>
+		<title>PBG3 format</title>
+	</head>
+	<body>
+		<h1>PBG3 format</h1>
+		<p>The PBG3 format is an archive format used by EoSD.</p>
+
+		<p>It is a bitstream composed of a header, a file table, and LZSS-compressed files.</p>
+
+
+		<h2>Reading integers</h2>
+		<p>Integers in PBG3 files are never signed, they are not byte-aligned, and have a variable size.<br/>
+		Their size is given by two bits: 00 means the number is stored in one byte, 10 means it is stored in three bytes.</p>
+
+		<p>Ex:</p>
+<pre>
+    0x0012 is stored as: 0000010010
+    0x0112 is stored as: 010000000100010010
+</pre>
+
+
+		<h2>Reading strings</h2>
+		<p>Strings are stored as standard NULL-terminated sequences of bytes.<br/>
+		The only catch is they are not byte-aligned.</p>
+
+
+		<h2>Header</h2>
+		<p>The header is composed of three fields:</p>
+		<ul>
+			<li>magic (string): "PBG3"</li>
+			<li>number of entries (integer)</li>
+			<li>offset of the file table (integer)</li>
+		</ul>
+
+		<p>The size of the header is thus comprised between 52 bits and 100 bits.</p>
+
+
+		<h2>File table</h2>
+		<p>The file table starts at a byte boundary, but as the rest of the file, isn't byte-aligned.<br/>
+		It consists of a sequence of entries.<br/>
+		Each entry is composed of five fields:</p>
+		<ul>
+			<li>unknown1 (int) #TODO</li>
+			<li>unknown2 (int) #TODO</li>
+			<li>checksum (int): simple checksum of compressed data</li>
+			<li>size (int): size of uncompressed data</li>
+			<li>name (string): name of the file</li>
+		</ul>
+
+		<p>The checksum is a mere sum of the compressed data.<br/>
+		Files are compressed using the LZSS algorithm, with a dictionary size of 8192 bytes and a minimum matching length of 4 bytes.<br/>
+		The size of the offset component of (offset, length) tuples is 13 bits, whereas the size of the length component is 4 bits.<br/>
+		A file ends with a (0, 0) tuple, that is, 18 zero bits.</p>
+
+		<p>Uncompressing a LZSS-compressed file is quite easy, see lzss.py.</p>
+	</body>
+</html>
--- a/06/std.xhtml
+++ b/06/std.xhtml
@@ -1,34 +1,135 @@
 <?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet type="text/css" href="../style.css"?>
 <!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
 	<head>
 		<title>STD format</title>
 	</head>
 	<body>
 		<h1>STD format</h1>
-		<p>All integers are little endian, all number are hex.</p>
 
 		<h2>Header</h2>
-		<pre>
-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</pre>
+<pre>
+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;
+</pre>
+
+		<h2>First section</h2>
+		<p>This section is responsible for creating objects from the stgxbg.anm file.</p>
+<pre>
+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
+};
+</pre>
+
+		<p>The following description is symbolic.</p>
+<pre>
+struct section1 {
+    uint32_t offsets[]; // header.nb_objects offsets towards objects
+};*/
+</pre>
+
 
-		<h2>Data</h2>
-		<pre>
-0 - ... - ...
+		<h2>Second section</h2>
+		<p>This section is responsible for placing objects from section 1 in the space.</p>
+<pre>
+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
+</pre>
+
+
+
+		<h2>Third Section</h2>
+		<p>This section is responsible for camera movement, color effects, and such things.</p>
+<pre>
+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
+</pre>
+
+
+
+
+
+
+
+<pre>
+typedef struct {
+    thstd_header_t header;
+    uint32_t* offsets;
+    list_t objects;
+    list_t faces;
+    list_t messages;
+} PACK_ATTRIBUTE thstd_t;
 </pre>
 	</body>
 </html>
--- a/index.xhtml
+++ b/index.xhtml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
 	<head>
 		<title>Touhou</title>
 	</head>
@@ -9,23 +9,26 @@
 		<h2>Embodiment of Scarlet Devil</h2>
 		<h3>Formats</h3>
 		<ul>
+			<li><a href="06/pbg3.xhtml">PBG3</a> (dat archives)</li>
 			<li><a href="06/std.xhtml">STD</a> (stages)</li>
 		</ul>
 		<h3>Opcodes</h3>
 		<ul>
-			<li><a href="06/std.xhtml">STD</a> (stages)</li>
+			<li><a href="06/anm.xml">STD</a> (stages)</li>
 			<li><a href="06/ecl.xml">ECL</a> (enemy comportement)</li>
 			<li><a href="06/msg.xml">MSG</a> (dialogs)</li>
 		</ul>
 
 		<h2>Mountain of Faith</h2>
 		<ul>
-			<li><a href="10/ecl.xml">ECL</a> (<a href="http://code.google.com/p/thtk/wiki/Ecl10Reference">original</a>)</li>
+			<li><a href="10/ecl.xml">ECL</a> (<a href="//code.google.com/p/thtk/wiki/Ecl10Reference">original</a>)</li>
 		</ul>
 
 		<h2>Subterranean Animism</h2>
 		<ul>
-			<li><a href="http://code.google.com/p/thtk/wiki/Ecl11Reference">ECL</a></li>
+			<li><a href="//code.google.com/p/thtk/wiki/Ecl11Reference">ECL</a></li>
 		</ul>
+
+		<p>The sources are <a href="//hg.linkmauve.fr/touhou-doc">here</a></p>
 	</body>
 </html>