<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.multimedia.cx/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cyril</id>
	<title>MultimediaWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.multimedia.cx/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cyril"/>
	<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php/Special:Contributions/Cyril"/>
	<updated>2026-04-22T08:54:11Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.5</generator>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Smush&amp;diff=9383</id>
		<title>Smush</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Smush&amp;diff=9383"/>
		<updated>2008-01-19T23:39:11Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] Smush codec. The [[SANM]] codec document is complete; the SAN codec is still under (de)construction.&lt;br /&gt;
&lt;br /&gt;
Samples from various games are located at http://samples.mplayerhq.hu/game-formats/la-san/ and http://samples.mplayerhq.hu/game-formats/la-snm/.&lt;br /&gt;
&lt;br /&gt;
== Usage Matrix ==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
! Name !! Variant !! Video Codec || Audio Codec&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/star-wars-rebel-assault Rebel Assault]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/star-wars-rebel-assault-ii-the-hidden-empire Rebel Assault II]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Rebel Assault II demo&lt;br /&gt;
| &amp;amp;nbsp; || FOBJ Codec 37 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Rebel Assault II trailer&lt;br /&gt;
| SAN || &amp;amp;nbsp; || PSAD&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/full-throttle Full Throttle]&lt;br /&gt;
| SAN/NUT || FOBJ Codec 37 || PSAD&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/dig The Dig]&lt;br /&gt;
| SAN || FOBJ Codec 37 || IACT&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/curse-of-monkey-island The Curse Of Monkey Island]&lt;br /&gt;
| SAN || FOBJ Codec 47 || IACT&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/outlaws Outlaws]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Outlaws demo&lt;br /&gt;
| &amp;amp;nbsp; || FOBJ Codec 47 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Grim Fandango demo&lt;br /&gt;
| &amp;amp;nbsp; || FOBJ Codec 47 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Grim Fandango trailer&lt;br /&gt;
| SAN || &amp;amp;nbsp; || IACT&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/grim-fandango Grim Fandango]&lt;br /&gt;
| SNM || Bl16 (blocky16) || [[VIMA]]&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-shadows-of-the-empire Shadows of the Empire (PC)]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-	 &lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-x-wing-alliance X-Wing Alliance]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-episode-i-racer Star Wars Racer]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-droidworks Star Wars DroidWorks]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/indiana-jones-and-the-infernal-machine Indiana Jones and the Infernal Machine]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-jedi-knight-mysteries-of-the-sith Jedi Knight: Mysteries of the Sith]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/mortimer-and-the-riddles-of-the-medallion Mortimer and the Riddles of the Medallion]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Making Magic CDROM (not a game but still uses smush)&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/escape-from-monkey-island Escape From Monkey Island] &lt;br /&gt;
| &amp;amp;nbsp; || apparently has Smush headers but uses [[Bink Container|Bink]] || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Star Wars Episode 1: Insider's Guide&lt;br /&gt;
| SNM || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Jar Jar's Journey Storybook&lt;br /&gt;
| SNM || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
Smush comes in two variants. [[SAN|Version 1]], FOURCC &amp;quot;ANIM&amp;quot; was used up until Grim Fandango. [[SNM|Version 2]], FOURCC &amp;quot;SANM&amp;quot; was used from Grim Fandango up until its replacement by [[Bink Container|Bink]], possibly in Escape From Monkey Island.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]]&lt;br /&gt;
[[Category:Undiscovered Game Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6045</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6045"/>
		<updated>2006-09-24T00:33:01Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Nodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |vector3 * number of mesh vertices&lt;br /&gt;
 texture vertex data                  |vector2 * number of texture vertices&lt;br /&gt;
 extra light data (see notes)         |float * number of mesh vertices&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |vector3 * number of mesh vertices&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 mesh vertex indices                   |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material index       |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |4 bytes, float&lt;br /&gt;
 yaw                       |4 bytes, float&lt;br /&gt;
 roll                      |4 bytes, float&lt;br /&gt;
 unknown                   |48 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 model radius                |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node tree.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6044</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6044"/>
		<updated>2006-09-24T00:30:26Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Nodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |vector3 * number of mesh vertices&lt;br /&gt;
 texture vertex data                  |vector2 * number of texture vertices&lt;br /&gt;
 extra light data (see notes)         |float * number of mesh vertices&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |vector3 * number of mesh vertices&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 mesh vertex indices                   |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material index       |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |4 bytes, float&lt;br /&gt;
 yaw                       |4 bytes, float&lt;br /&gt;
 roll                      |4 bytes, float&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 model radius                |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node tree.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6025</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6025"/>
		<updated>2006-09-18T03:33:45Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |vector3 * number of mesh vertices&lt;br /&gt;
 texture vertex data                  |vector2 * number of texture vertices&lt;br /&gt;
 extra light data (see notes)         |float * number of mesh vertices&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |vector3 * number of mesh vertices&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 mesh vertex indices                   |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material index       |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 model radius                |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node tree.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6024</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6024"/>
		<updated>2006-09-18T03:33:14Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |vector3 * number of mesh vertices&lt;br /&gt;
 texture vertex data                  |vector2 * number of texture vertices&lt;br /&gt;
 extra light data (see notes)         |float * number of mesh vertices&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |vector3 * number of mesh vertices&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 mesh vertex indices                   |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material index       |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 model radius                |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node graph.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6023</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6023"/>
		<updated>2006-09-18T03:23:25Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Mesh */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |vector3 * number of mesh vertices&lt;br /&gt;
 texture vertex data                  |vector2 * number of texture vertices&lt;br /&gt;
 extra light data (see notes)         |float * number of mesh vertices&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |vector3 * number of mesh vertices&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 mesh vertex indices                   |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material index       |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node graph.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6022</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6022"/>
		<updated>2006-09-18T03:22:22Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Faces */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 extra light data (see notes)         |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material index       |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node graph.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6021</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6021"/>
		<updated>2006-09-18T02:28:27Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information are specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 extra light data (see notes)         |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node graph.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Category:3D_Mesh_Formats&amp;diff=6020</id>
		<title>Category:3D Mesh Formats</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Category:3D_Mesh_Formats&amp;diff=6020"/>
		<updated>2006-09-17T23:09:18Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This category contains formats that represent 3D mesh(es).&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Category:3D_Mesh_Formats&amp;diff=6019</id>
		<title>Category:3D Mesh Formats</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Category:3D_Mesh_Formats&amp;diff=6019"/>
		<updated>2006-09-17T23:08:55Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This category includes files that represent 3D mesh(es).&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6018</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6018"/>
		<updated>2006-09-17T23:08:26Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 extra light data (see notes)         |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node graph.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:3D Mesh Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6017</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6017"/>
		<updated>2006-09-17T23:07:27Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 extra light data (see notes)         |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node's position in the breadth-first traversal of the node graph.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6016</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6016"/>
		<updated>2006-09-17T23:06:44Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 extra light data (see notes)         |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node in the breadth-first traversal of the node graph.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6015</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6015"/>
		<updated>2006-09-17T23:06:18Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 extra light data (see notes)         |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Extra-light values are used to as additional brightness values that are added to their corresponding vertex brightness value. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node in the breadth-first traversal of the node graph.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6014</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6014"/>
		<updated>2006-09-17T23:04:43Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;br /&gt;
# A &amp;quot;node id&amp;quot; refers to the node in the breadth-first traversal of the node graph.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6013</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6013"/>
		<updated>2006-09-17T22:58:24Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6012</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6012"/>
		<updated>2006-09-17T22:37:06Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* Fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6011</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6011"/>
		<updated>2006-09-17T22:35:00Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
* fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
# Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
# In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply the vertex's position in the vertex array, starting at 0.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6010</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6010"/>
		<updated>2006-09-17T22:32:50Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
* fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
1. Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
2. In order to conserve space, faces only refer to vertices in their enclosing mesh. Therefore a &amp;quot;vertex index&amp;quot; is simply its position in the vertex array, starting at 0.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6009</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6009"/>
		<updated>2006-09-17T22:29:47Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
* fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
====== Notes ======&lt;br /&gt;
* Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
The nodes header looks like this:&lt;br /&gt;
 unknown        |4 bytes&lt;br /&gt;
 number of nodes|4 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by node structures, one per node:&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Footer ===&lt;br /&gt;
The final piece is the footer, which contains some more information about the model:&lt;br /&gt;
 radius                      |4 bytes, float&lt;br /&gt;
 insertion offset (see notes)|vector3&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6008</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6008"/>
		<updated>2006-09-17T22:27:40Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
* fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
====== Notes ======&lt;br /&gt;
* Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices                        |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Nodes ===&lt;br /&gt;
 name                      |64 bytes, string&lt;br /&gt;
 flags                     |4 bytes&lt;br /&gt;
 unknown                   |4 bytes&lt;br /&gt;
 type                      |4 bytes&lt;br /&gt;
 mesh id                   |4 bytes&lt;br /&gt;
 depth                     |4 bytes&lt;br /&gt;
 has parent?               |4 bytes&lt;br /&gt;
 number of children        |4 bytes&lt;br /&gt;
 has children?             |4 bytes&lt;br /&gt;
 has sibling?              |4 bytes&lt;br /&gt;
 pivot                     |vector3&lt;br /&gt;
 position                  |vector3&lt;br /&gt;
 pitch                     |vector3&lt;br /&gt;
 yaw                       |vector3&lt;br /&gt;
 roll                      |vector3&lt;br /&gt;
 unknown                   |50 bytes (whoa!)&lt;br /&gt;
 if has parent, parent id  |4 bytes&lt;br /&gt;
 if has child, child id    |4 bytes&lt;br /&gt;
 if has sibling, sibling id|4 bytes&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6007</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6007"/>
		<updated>2006-09-17T22:15:54Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
* fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
====== Notes ======&lt;br /&gt;
* Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)                           |4 bytes&lt;br /&gt;
 face type                             |4 bytes&lt;br /&gt;
 geometry mode                         |4 bytes&lt;br /&gt;
 lighting mode                         |4 bytes&lt;br /&gt;
 texture mode                          |4 bytes&lt;br /&gt;
 number of vertices                    |4 bytes&lt;br /&gt;
 unknown                               |4 bytes&lt;br /&gt;
 has texture?                          |4 bytes&lt;br /&gt;
 has material?                         |4 bytes&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 extra light                           |4 bytes, float&lt;br /&gt;
 unknown                               |vector3&lt;br /&gt;
 normal vector                         |vector3&lt;br /&gt;
 vertex indices (see notes)            |4 bytes, one per vertex&lt;br /&gt;
 if has texture, texture vertex indices|4 bytes, one per texture vertex&lt;br /&gt;
 if has material, material id          |4 bytes&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6006</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6006"/>
		<updated>2006-09-17T22:10:31Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
* fields marked with &amp;quot;(?)&amp;quot; have not been verified. this should not be confused with an ordinary question mark &amp;quot;?&amp;quot;, which is a valid part of a field's description.&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Notes =====&lt;br /&gt;
* Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;br /&gt;
&lt;br /&gt;
===== Faces =====&lt;br /&gt;
 face id (?)       |4 bytes&lt;br /&gt;
 face type         |4 bytes&lt;br /&gt;
 geometry mode     |4 bytes&lt;br /&gt;
 lighting mode     |4 bytes&lt;br /&gt;
 texture mode      |4 bytes&lt;br /&gt;
 number of vertices|4 bytes&lt;br /&gt;
 unknown           |4 bytes&lt;br /&gt;
 has texture?      |4 bytes&lt;br /&gt;
 has material?     |4 bytes&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6005</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6005"/>
		<updated>2006-09-17T22:07:31Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows:&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
Followed the rest of the header:&lt;br /&gt;
 3d model name|32 bytes, string&lt;br /&gt;
&lt;br /&gt;
=== Geoset ===&lt;br /&gt;
The geoset header is formatted as follows:&lt;br /&gt;
 unknown          |4 bytes&lt;br /&gt;
 number of geosets|4 bytes&lt;br /&gt;
 &lt;br /&gt;
This is followed by (not very interesting) geoset structures, one per geoset:&lt;br /&gt;
 number of meshes|4 bytes&lt;br /&gt;
&lt;br /&gt;
==== Mesh ====&lt;br /&gt;
A mesh is formatted as follows:&lt;br /&gt;
 mesh name                            |32 bytes, string&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 geometry mode                        |4 bytes&lt;br /&gt;
 lighting mode                        |4 bytes&lt;br /&gt;
 texture mode                         |4 bytes&lt;br /&gt;
 number of mesh vertices              |4 bytes&lt;br /&gt;
 number of texture vertices           |4 bytes&lt;br /&gt;
 number of faces                      |4 bytes&lt;br /&gt;
 mesh vertex data                     |..., vector3&lt;br /&gt;
 texture vertex data                  |..., vector2&lt;br /&gt;
 illumination vertex data (see notes) |..., float&lt;br /&gt;
 unknown                              |4 bytes * number of mesh vertices&lt;br /&gt;
 face data (see below)                |...&lt;br /&gt;
 mesh vertex normal data              |..., vector3&lt;br /&gt;
 has shadow                           |4 bytes&lt;br /&gt;
 unknown                              |4 bytes&lt;br /&gt;
 mesh radius                          |4 bytes&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
 unknown                              |vector3&lt;br /&gt;
&lt;br /&gt;
===== Notes =====&lt;br /&gt;
* Illumination values are used to as additional brightness values that are added to their corresponding vertex. This way, for example, for a given vertex v, an illumination value of 0.5 will increase v's brightness by 0.5. Illumination values (are floats, and) are in the range [0, 1]. All encountered models so far have all illumination values of 0.00.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6004</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6004"/>
		<updated>2006-09-17T21:53:43Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows.&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name, string|32 bytes&lt;br /&gt;
&lt;br /&gt;
...followed the rest of the header:&lt;br /&gt;
 3d model name, string|32 bytes&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6003</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6003"/>
		<updated>2006-09-17T21:53:21Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
* string - character array padded with zeros (one or more) at the end&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;br /&gt;
&lt;br /&gt;
=== Header ===&lt;br /&gt;
The header is formatted as follows.&lt;br /&gt;
 &amp;quot;MODL&amp;quot; FOURCC           |4 bytes&lt;br /&gt;
 number of materials used|4 bytes&lt;br /&gt;
&lt;br /&gt;
This is followed by material name fields, one per material:&lt;br /&gt;
 material name, string|32 bytes&lt;br /&gt;
&lt;br /&gt;
...followed the rest of the header:&lt;br /&gt;
 3d model name, string            |32 bytes&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6001</id>
		<title>MODL</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=MODL&amp;diff=6001"/>
		<updated>2006-09-17T21:39:45Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the LucasArts MODL mesh format, file extension &amp;quot;.3do&amp;quot;. Work is ongoing, so no guarantees are made regarding any information on this page.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
The MODL format comes in two flavours: binary, and ASCII. The ASCII flavour is used in the Grim Fandango demo, and the binary one is used in the full version. It follows that the demo version contains ASCII-versions of models that appear in the full version. Such models should be approached with care, because it's not unlikely that corresponding models from the two versions contain slightly different data.&lt;br /&gt;
&lt;br /&gt;
This document is concerned with the binary flavour of the mesh files.&lt;br /&gt;
&lt;br /&gt;
TODO -- add more games that use MODL, if there are any; upload samples.&lt;br /&gt;
&lt;br /&gt;
== Conventions/Terminology ==&lt;br /&gt;
This document employs several terms and conventions for convenience. Most of these are concerned with data types, of course.&lt;br /&gt;
&lt;br /&gt;
* float - 4-byte IEEE floating point value&lt;br /&gt;
* vectorN - an N-dimensional array that consists of N floats&lt;br /&gt;
* All values are little-endian unless otherwise specified&lt;br /&gt;
* geoset - a collection of meshes&lt;br /&gt;
&lt;br /&gt;
== Basic Layout ==&lt;br /&gt;
The MODL format, at the highest level, has the following layout:&lt;br /&gt;
 header&lt;br /&gt;
 geoset(s)&lt;br /&gt;
  \mesh(es)&lt;br /&gt;
    \face(s)&lt;br /&gt;
 node(s)&lt;br /&gt;
 footer&lt;br /&gt;
&lt;br /&gt;
That is, mesh primitives with no relational information is specified first through geosets, meshes, and faces. Relations between mesh primitives are represented through nodes, which are specified last.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=5885</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=5885"/>
		<updated>2006-08-24T22:06:35Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Video Header */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://samples.mplayerhq.hu/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version value 1           |1 byte&lt;br /&gt;
 0x009|Version value 2           |1 byte&lt;br /&gt;
 0x00A|# of frames               |2 bytes little endian&lt;br /&gt;
 0x00C|Video's x-coordinate      |2 bytes little endian&lt;br /&gt;
 0x00E|Video's y-coordinate      |2 bytes little endian&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Image type (see notes)    |2 bytes little endian&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Maximal frame buffer size |4 bytes little endian&lt;br /&gt;
 0x01E|Color Palette             |256 colors, 4-bytes little endian each&lt;br /&gt;
 0x41E|Unused (see notes)        |16 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* It appears as though the original decoder ignores the Frame delay field completely. Instead, all movies are played with a frame delay of 66667 microseconds. For now we ignore it and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
* Image type is &amp;quot;3&amp;quot; for all encountered samples so far. It might be helpful to assert() on this to easily single out samples that deviate from this.&lt;br /&gt;
* Looks like the original decoder ignores the last 16 bytes of the header.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x01C|Unknown                  |4 bytes&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02A|Unknown                  |2 bytes&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |512 bytes, 256 color values each 2 bytes little endian&lt;br /&gt;
 0x230|Unknown                  |8 bytes&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Decompressed pixels come in 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 x = motion_vector % image_width&lt;br /&gt;
 y = motion_vector / image_width&lt;br /&gt;
 copy 8x8 block from (db2[y + cy][x + cx]) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hi8bits(indices)&lt;br /&gt;
 bg_index = lo8bits(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hi16bits(colors)&lt;br /&gt;
 bgcolor = lo16bits(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]], as little endian&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=5881</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=5881"/>
		<updated>2006-08-24T04:13:25Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Video Header */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://samples.mplayerhq.hu/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version value 1           |1 byte&lt;br /&gt;
 0x009|Version value 2           |1 byte&lt;br /&gt;
 0x00A|# of frames               |2 bytes little endian&lt;br /&gt;
 0x00C|Video's x-coordinate      |2 bytes little endian&lt;br /&gt;
 0x00E|Video's y-coordinate      |2 bytes little endian&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Image type (see notes)    |2 bytes little endian&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Maximal frame buffer size |4 bytes little endian&lt;br /&gt;
 0x01E|Color Palette             |256 colors, 4-bytes little endian each&lt;br /&gt;
 0x41E|Unknown                   |2 bytes little endian&lt;br /&gt;
 0x420|Unused (see notes)        |14 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* It appears as though the original decoder ignores the Frame delay field completely. Instead, all movies are played with a frame delay of 66667 microseconds. For now we ignore it and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
* Image type is &amp;quot;3&amp;quot; for all encountered samples so far. It might be helpful to assert() on this to easily single out samples that deviate from this.&lt;br /&gt;
* Looks like the original decoder ignores the last 14 bytes of the header.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x01C|Unknown                  |4 bytes&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02A|Unknown                  |2 bytes&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |512 bytes, 256 color values each 2 bytes little endian&lt;br /&gt;
 0x230|Unknown                  |8 bytes&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Decompressed pixels come in 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 x = motion_vector % image_width&lt;br /&gt;
 y = motion_vector / image_width&lt;br /&gt;
 copy 8x8 block from (db2[y + cy][x + cx]) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hi8bits(indices)&lt;br /&gt;
 bg_index = lo8bits(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hi16bits(colors)&lt;br /&gt;
 bgcolor = lo16bits(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]], as little endian&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5590</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5590"/>
		<updated>2006-07-15T02:24:20Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII code for each character. Each such code is 2 bytes little endian, and there are as many codes as there are characters. The code at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII code of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Character Info Table ==&lt;br /&gt;
The character code table is followed by a table that contains information about each character. Each information block is 16 bytes, and contains several fields. There are as many information blocks as there are characters. The structure of an information block is as follows, with addresses relative to the block's address:&lt;br /&gt;
&lt;br /&gt;
 0x00|Bitmap data offset    |4 bytes little endian&lt;br /&gt;
 0x04|Logical width (pixels)|1 byte&lt;br /&gt;
 0x05|Unknown               |1 byte&lt;br /&gt;
 0x06|Unknown               |1 byte&lt;br /&gt;
 0x07|Unknown               |1 byte&lt;br /&gt;
 0x08|Width (pixels)        |4 bytes little endian&lt;br /&gt;
 0x0C|Height (pixels)       |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Bitmap Data ==&lt;br /&gt;
The character info table is followed by a chunk of bitmap data. The chunk's size is the one advertised in the first field of the Preamble. A character's bitmap size is its &amp;lt;tt&amp;gt;width * height&amp;lt;/tt&amp;gt; bytes, where each byte is one pixel color value. The bitmap lines are stored in the intuitive way; that is, the pixels of each line are stored left to right, and the lines are stored from top to bottom.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5589</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5589"/>
		<updated>2006-07-15T02:23:12Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII code for each character. Each such code is 2 bytes little endian, and there are as many codes as there are characters. The code at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII code of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Character Info Table ==&lt;br /&gt;
The character code table is followed by a table that contains information about each character. Each information block is 16 bytes, and contains several fields. There are as many information blocks as there are characters. The structure of an information block is as follows, with addresses relative to the block's address:&lt;br /&gt;
&lt;br /&gt;
 0x00|Bitmap data offset    |4 bytes little endian&lt;br /&gt;
 0x04|Logical width (pixels)|1 byte&lt;br /&gt;
 0x05|Unknown               |1 byte&lt;br /&gt;
 0x06|Unknown               |1 byte&lt;br /&gt;
 0x07|Unknown               |1 byte&lt;br /&gt;
 0x08|Width (pixels)        |4 bytes little endian&lt;br /&gt;
 0x0C|Height (pixels)       |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Bitmap Data ==&lt;br /&gt;
The character info table is followed by a chunk of bitmap data. The chunk's size is the one advertised in the first field of the Preamble. A character's bitmap size is its &amp;lt;tt&amp;gt;width * height&amp;lt;/tt&amp;gt; bytes, where each byte is one pixel color value.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5588</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5588"/>
		<updated>2006-07-15T02:21:57Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII code for each character. Each such code is 2 bytes little endian, and there are as many codes as there are characters. The code at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII code of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Character Info Table ==&lt;br /&gt;
The character code table is followed by a table that contains information about each character. Each information block is 16 bytes, and contains several fields. There are as many information blocks as there are characters. The structure of an information block is as follows, with addresses relative to the block's address:&lt;br /&gt;
&lt;br /&gt;
 0x00|Bitmap data offset|4 bytes little endian&lt;br /&gt;
 0x04|Logical width     |1 byte&lt;br /&gt;
 0x05|Unknown           |1 byte&lt;br /&gt;
 0x06|Unknown           |1 byte&lt;br /&gt;
 0x07|Unknown           |1 byte&lt;br /&gt;
 0x08|Width (pixels)    |4 bytes little endian&lt;br /&gt;
 0x0C|Height (pixels)   |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Bitmap Data ==&lt;br /&gt;
The character info table is followed by a chunk of bitmap data. The chunk's size is the one advertised in the first field of the Preamble. A character's bitmap size is its &amp;lt;tt&amp;gt;width * height&amp;lt;/tt&amp;gt; bytes, where each byte is one pixel color value.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5587</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5587"/>
		<updated>2006-07-15T01:52:29Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII code for each character. Each such code is 2 bytes little endian, and there are as many codes as there are characters. The code at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII code of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Character Info Table ==&lt;br /&gt;
The character code table is followed by a table that contains information about each character. Each information block is 16 bytes, and contains several fields. There are as many information blocks as there are characters. The structure of an information block is as follows, with addresses relative to the block's address:&lt;br /&gt;
&lt;br /&gt;
 0x00|Bitmap data offset|4 bytes little endian&lt;br /&gt;
 0x04|Logical width     |1 byte&lt;br /&gt;
 0x05|Unknown           |1 byte&lt;br /&gt;
 0x06|Unknown           |1 byte&lt;br /&gt;
 0x07|Unknown           |1 byte&lt;br /&gt;
 0x08|Width (pixels)    |4 bytes little endian&lt;br /&gt;
 0x0C|Height (pixels)   |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Bitmap Data ==&lt;br /&gt;
The character info table is followed by a chunk of bitmap data. The chunk's size is the one advertised in the first field of the Preamble.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5586</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5586"/>
		<updated>2006-07-14T23:13:30Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII code for each character. Each such code is 2 bytes little endian, and there are as many codes as there are characters. The code at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII code of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Character Info Table ==&lt;br /&gt;
The character code table is followed by a table that contains information about each character. Each information block is 16 bytes, and contains several fields. There are as many information blocks as there are characters. The structure of an information block is as follows, with addresses relative to the block's address:&lt;br /&gt;
&lt;br /&gt;
 0x00|Bitmap data offset|4 bytes little endian&lt;br /&gt;
 0x04|Logical width     |1 byte&lt;br /&gt;
 0x05|Unknown           |1 byte&lt;br /&gt;
 0x06|Unknown           |1 byte&lt;br /&gt;
 0x07|Unknown           |1 byte&lt;br /&gt;
 0x08|Width (pixels)    |4 bytes little endian&lt;br /&gt;
 0x0C|Height (pixels)   |4 bytes little endian&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5585</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5585"/>
		<updated>2006-07-14T23:05:22Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII code for each character. Each such code is 2 bytes little endian, and there are as many codes as there are characters. The code at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII code of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5584</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5584"/>
		<updated>2006-07-14T23:03:44Z</updated>

		<summary type="html">&lt;p&gt;Cyril: Err, wasn't an offset table.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Code Table ==&lt;br /&gt;
After the preamble we have a table that contains the ASCII value for each character. Each such value is 2 bytes little endian, and there are as many values as there are characters. The value at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the ASCII value of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5583</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5583"/>
		<updated>2006-07-14T22:27:58Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Offset Table ==&lt;br /&gt;
After the preamble we have a table that contains the offset of each character's raw data in the file. Each such offset is 2 bytes little endian, and there are as many offsets as there are characters. The value at offset &amp;lt;tt&amp;gt;0x20 + (i * 2)&amp;lt;/tt&amp;gt; is the offset in the file of the ''i''-th character, starting at &amp;lt;tt&amp;gt;i = 0&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5582</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5582"/>
		<updated>2006-07-14T22:26:46Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the LucasArts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Offset Table ==&lt;br /&gt;
After the preamble we have a table that contains the offset of each character's raw data in the file. Each such offset is 2 bytes little endian, and there are as many offsets as there are characters. The value at offset &amp;lt;tt&amp;gt;0x20 + i&amp;lt;/tt&amp;gt; is the offset in the file of the ''i''-th character.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=User:Cyril&amp;diff=5580</id>
		<title>User:Cyril</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=User:Cyril&amp;diff=5580"/>
		<updated>2006-07-14T22:19:29Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Cyril Zorin, that is. Elephant man. Also programming and multimedia enthusiast. No relation to any other elephant men. No relation to Joseph Merrick. Email at firstname dot lastname at gmail.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5579</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5579"/>
		<updated>2006-07-14T22:19:11Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the Lucast Arts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;br /&gt;
&lt;br /&gt;
== Character Offset Table ==&lt;br /&gt;
After the preamble we have a table that contains the offset of each character's raw data in the file. Each such offset is 2 bytes little endian, and there are as many offsets as there are characters.&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5578</id>
		<title>LAF</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=LAF&amp;diff=5578"/>
		<updated>2006-07-14T22:13:14Z</updated>

		<summary type="html">&lt;p&gt;Cyril: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is some preliminary in-progress documentation for the Lucast Arts Font format (LAF).&lt;br /&gt;
&lt;br /&gt;
== Header ==&lt;br /&gt;
 0x00|Number of characters         |4 bytes little endian&lt;br /&gt;
 0x04|Raw font data size           |4 bytes little endian&lt;br /&gt;
 0x08|Max character width (pixels) |4 bytes little endian&lt;br /&gt;
 0x0C|Max character height (pixels)|4 bytes little endian&lt;br /&gt;
 0x10|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x14|Unknown                      |4 bytes little endian&lt;br /&gt;
 0x18|First character ASCII code   |4 bytes little endian&lt;br /&gt;
 0x1C|Last character ASCII code    |4 bytes little endian&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4932</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4932"/>
		<updated>2006-05-08T21:21:33Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Video */ Cleanup.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x01C|Unknown                  |4 bytes&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02A|Unknown                  |2 bytes&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |512 bytes, 256 color values each 2 bytes little endian&lt;br /&gt;
 0x230|Unknown                  |8 bytes&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Decompressed pixels come in 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 x = motion_vector % image_width&lt;br /&gt;
 y = motion_vector / image_width&lt;br /&gt;
 copy 8x8 block from (db2[y + cy][x + cx]) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hi8bits(indices)&lt;br /&gt;
 bg_index = lo8bits(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hi16bits(colors)&lt;br /&gt;
 bgcolor = lo16bits(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]], as little endian&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4931</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4931"/>
		<updated>2006-05-08T21:20:52Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Video */ Adding padding chunks for clarification of seemingly &amp;quot;mismatched&amp;quot; hex addresses.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x01C|Unknown                  |4 bytes&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02A|Unknown                  |2 bytes&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |512 bytes, 256 entries each 2 bytes little endian&lt;br /&gt;
 0x230|Unknown                  |8 bytes&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Decompressed pixels come in 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 x = motion_vector % image_width&lt;br /&gt;
 y = motion_vector / image_width&lt;br /&gt;
 copy 8x8 block from (db2[y + cy][x + cx]) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hi8bits(indices)&lt;br /&gt;
 bg_index = lo8bits(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hi16bits(colors)&lt;br /&gt;
 bgcolor = lo16bits(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]], as little endian&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4855</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4855"/>
		<updated>2006-05-06T04:39:55Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Subcodec 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |Each entry is 2 bytes little endian&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Decompressed pixels come in 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 x = motion_vector % image_width&lt;br /&gt;
 y = motion_vector / image_width&lt;br /&gt;
 copy 8x8 block from (db2[y + cy][x + cx]) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hi8bits(indices)&lt;br /&gt;
 bg_index = lo8bits(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hi16bits(colors)&lt;br /&gt;
 bgcolor = lo16bits(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]], as little endian&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4849</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4849"/>
		<updated>2006-05-05T16:48:00Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Codec */ Cleanup, clarifications.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |Each entry is 2 bytes little endian&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Decompressed pixels come in 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 x = motion_vector % image_width&lt;br /&gt;
 y = motion_vector / image_width&lt;br /&gt;
 copy 8x8 block from (db2[y + cy][x + cx]) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hi8bits(indices)&lt;br /&gt;
 bg_index = lo8bits(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hi16bits(colors)&lt;br /&gt;
 bgcolor = lo16bits(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4848</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4848"/>
		<updated>2006-05-05T16:43:56Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Subcodec 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |Each entry is 2 bytes little endian&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Output colors are 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 copy 8x8 block from (db2[cy][cx] + motion_vector) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hibyte(indices)&lt;br /&gt;
 bg_index = lobyte(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hiword(colors)&lt;br /&gt;
 bgcolor = loword(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4847</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4847"/>
		<updated>2006-05-05T16:43:16Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Subcodecs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |Each entry is 2 bytes little endian&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Output colors are 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0, loop by 16-bit values and reinterpret each one as little endian.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cx = 0, cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 copy 8x8 block from (db2[cy][cx] + motion_vector) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hibyte(indices)&lt;br /&gt;
 bg_index = lobyte(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hiword(colors)&lt;br /&gt;
 bgcolor = loword(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4846</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4846"/>
		<updated>2006-05-05T16:42:09Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Subcodec 5 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |Each entry is 2 bytes little endian&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Output colors are 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cx = 0, cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 copy 8x8 block from (db2[cy][cx] + motion_vector) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hibyte(indices)&lt;br /&gt;
 bg_index = lobyte(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hiword(colors)&lt;br /&gt;
 bgcolor = loword(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    little_endian(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=Smush&amp;diff=4821</id>
		<title>Smush</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=Smush&amp;diff=4821"/>
		<updated>2006-05-04T17:24:24Z</updated>

		<summary type="html">&lt;p&gt;Cyril: Updated samples link.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] Smush codec. Note that at this stage the document is quite incomplete as the codec is still being reverse engineered.&lt;br /&gt;
&lt;br /&gt;
Samples from various games are located at http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-san/ and http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/.&lt;br /&gt;
&lt;br /&gt;
== Usage Matrix ==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
! Name !! Variant !! Video Codec || Audio Codec&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/star-wars-rebel-assault Rebel Assault]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/star-wars-rebel-assault-ii-the-hidden-empire Rebel Assualt II]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Rebel Assault II demo&lt;br /&gt;
| &amp;amp;nbsp; || FOBJ Codec 37 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Rebel Assault II trailer&lt;br /&gt;
| SAN || &amp;amp;nbsp; || PSAD&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/full-throttle Full Throttle]&lt;br /&gt;
| SAN/NUT || FOBJ Codec 37 || PSAD&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/dos/dig The Dig]&lt;br /&gt;
| SAN || FOBJ Codec 37 || IACT&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/curse-of-monkey-island The Curse Of Monkey Island]&lt;br /&gt;
| SAN || FOBJ Codec 47 || IACT&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/outlaws Outlaws]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Outlaws demo&lt;br /&gt;
| &amp;amp;nbsp; || FOBJ Codec 47 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Grim Fandango demo&lt;br /&gt;
| &amp;amp;nbsp; || FOBJ Codec 47 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Grim Fandango trailer&lt;br /&gt;
| SAN || &amp;amp;nbsp; || IACT&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/grim-fandango Grim Fandango]&lt;br /&gt;
| SNM || Bl16 (blocky16) || [[VIMA]]&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-x-wing-alliance X-Wing Alliance]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-shadows-of-the-empire Shadows of the Empire (PC)]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-episode-i-racer Star Wars Racer]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-droidworks Star Wars DroidWorks]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/indiana-jones-and-the-infernal-machine Indiana Jones and the Infernal Machine]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/star-wars-jedi-knight-mysteries-of-the-sith Jedi Knight: Mysteries of the Sith]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/windows/mortimer-and-the-riddles-of-the-medallion Mortimer and the Riddles of the Medallion]&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Making Magic CDROM (not a game but still uses smush)&lt;br /&gt;
| &amp;amp;nbsp; || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mobygames.com/game/escape-from-monkey-island Escape From Monkey Island] &lt;br /&gt;
| &amp;amp;nbsp; || apparently has Smush headers but uses [[Bink Container|Bink]] || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| StarWars Episode 1: Insider's Guide&lt;br /&gt;
| SNM || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| Jar Jar's Journey Storybook&lt;br /&gt;
| SNM || &amp;amp;nbsp; || &amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
Smush comes in two variants. [[SAN|Version 1]], FOURCC &amp;quot;ANIM&amp;quot; was used up until Grim Fandango. [[SNM|Version 2]], FOURCC &amp;quot;SANM&amp;quot; was used from Grim Fandango up until its replacement by [[Bink Container|Bink]], possibly in Escape From Monkey Island.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
	<entry>
		<id>https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4790</id>
		<title>SANM</title>
		<link rel="alternate" type="text/html" href="https://wiki.multimedia.cx/index.php?title=SANM&amp;diff=4790"/>
		<updated>2006-05-04T02:39:28Z</updated>

		<summary type="html">&lt;p&gt;Cyril: /* Initial Setup */ Clarification.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page attempts to document the [[LucasArts]] [[Smush]] v2 codec, FOURCC &amp;quot;SANM&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A GPL'd decoder for the SNM format and relevant codecs can be found in the [http://svn.sourceforge.net/viewcvs.cgi/scummvm/residual/trunk Residual] reimplementation of the Grim Fandango Engine (GrimE), although it is largely unreadable because it was converted from the original assembler code to C.&lt;br /&gt;
&lt;br /&gt;
= Samples =&lt;br /&gt;
* Grim Fandango: http://www.mplayerhq.hu/MPlayer/samples/game-formats/la-snm/grimfandango/&lt;br /&gt;
* Grim Fandango Demo uses older style videos (SAN, same codecs as Monkey Island 3) and 3D Models (text not binary format).&lt;br /&gt;
* X-Wing Alliance&lt;br /&gt;
* Find more games that use SNM.&lt;br /&gt;
== Unique Samples ==&lt;br /&gt;
The following Grim Fandango movies are unique in that they (used to) make the Residual smush implementation segfault, and the issue was (never) resolved by adding 5700 bytes of padding to some buffers. When writing a decoder, they may serve as helpful potential stress tests.&lt;br /&gt;
 lol.snm, byeruba.snm, crushed.snm, eldepot.snm, heltrain.snm, hostage.snm, tb_kitty.snm&lt;br /&gt;
&lt;br /&gt;
'''Note''' - The Residual implementation's segfaulting results in from improper breakdown of the destination image into 8x8 blocks, whereby the calculation will claim that an image with N height blocks has (N+1) height blocks (or similar), at which point the segfault is imminent. This can be solved by either trimming the remaining pixels that don't fit into the last 8x8 blocks (undesirable), or set the image buffer width/height to the image size in ''blocks * 8'', not ''pixels'', to account for said remaining pixels (desirable). We'll dismiss this as a Residual implementation issue.&lt;br /&gt;
&lt;br /&gt;
== Use in Grim Fandango ==&lt;br /&gt;
SANM is used in Grim Fandango for cut-scenes and in-game animations. The actual SNM movie files are gzipped and stored inside LAB archive files (which are quite easy to extract, there are many tools). You must use a tool like *nix's &amp;quot;gunzip&amp;quot; to decompress the SNM files after extracting the SNM files out of the LAB files. A decompressed Smush file has the &amp;quot;SANM&amp;quot; FOURCC as the first four bytes.&lt;br /&gt;
&lt;br /&gt;
= Organization =&lt;br /&gt;
This section deals with the structural properties of Smush movies. In other words, we describe the various headers used.&lt;br /&gt;
&lt;br /&gt;
'''Note''': each &amp;quot;chunk size&amp;quot; entry in a particular chunk header indicates the size of the chunk's contents ''without'' the chunk's FOURCC and size.&lt;br /&gt;
&lt;br /&gt;
== Preamble ==&lt;br /&gt;
The movie begins with a basic 8-byte section that looks like this:&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;SANM&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Movie size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
== Video Header ==&lt;br /&gt;
This header immediately follows the preamble. It describes the movie's video properties.&lt;br /&gt;
&lt;br /&gt;
 0x000|&amp;quot;SHDR&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x004|Header size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Version                   |2 bytes little endian&lt;br /&gt;
 0x00A|# of frames               |4 bytes little endian&lt;br /&gt;
 0x00E|Padding?                  |2 bytes&lt;br /&gt;
 0x010|Width                     |2 bytes little endian&lt;br /&gt;
 0x012|Height                    |2 bytes little endian&lt;br /&gt;
 0x014|Padding?                  |2 bytes&lt;br /&gt;
 0x016|Frame delay (microseconds)|4 bytes little endian&lt;br /&gt;
 0x01A|Flags                     |2 bytes little endian&lt;br /&gt;
 0x01C|Unknown&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
It appears as though the original decoder ignores the Frame delay and Flags fields completely. Instead, all movies are played with a frame delay of 66667 microseconds. Also, it's possible that the &amp;quot;Flags&amp;quot; field is game-specific and is meaningful to a particular game engine. For now we ignore both and force the 66667 usec value, until we find a sample that breaks with this.&lt;br /&gt;
&lt;br /&gt;
== Audio/Keyframe Header ==&lt;br /&gt;
Smush supports variable-size keyframes. An example of this usage can be seen in the Full Throttle highway chase scenes, where different images are composited into the streaming video depending on the player's actions.&lt;br /&gt;
&lt;br /&gt;
Curiously enough, this header includes both audio and keyframe information.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;FLHD&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
Followed by any number of keyframe dimension chunks, which should match the number of keyframes in the movie. Dimension chunks in this header specify the dimensions of corresponding keyframes in the stream, in the order they're encountered. This information has not been rigorously verified, though.&lt;br /&gt;
 0x00|&amp;quot;Bl16&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Padding?              |2 bytes&lt;br /&gt;
 0x0A|Width                 |2 bytes little endian&lt;br /&gt;
 0x0C|Height                |2 bytes little endian&lt;br /&gt;
 0x0E|Padding?              |2 bytes&lt;br /&gt;
&lt;br /&gt;
Followed by exactly one audio info chunk.&lt;br /&gt;
 0x00|&amp;quot;Wave&amp;quot; FOURCC         |4 bytes big endian&lt;br /&gt;
 0x04|Header size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Frequency (Hz)        |4 bytes little endian&lt;br /&gt;
 0x0C|# of channels         |4 bytes little endian&lt;br /&gt;
 0x10|See notes             |4 bytes&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
* For some movies, the &amp;quot;Wave&amp;quot; chunk contains an extra 4-byte field at its end, the purpose of which is unknown.&lt;br /&gt;
* Movies without audio do not contain an audio info chunk.&lt;br /&gt;
* The order in which Wave/Bl16 chunks are organized in the FLHD header is unspecified and is known to vary between movies.&lt;br /&gt;
&lt;br /&gt;
== Annotation ==&lt;br /&gt;
Movies may contain an optional plaintext annotation. In Grim Fandango, the only such movies are in-game animations. Keep in mind that the string itself may not always be as large as the advertised annotation size. In that case, the remaining space is padded with zeros until the advertised length is reached.&lt;br /&gt;
&lt;br /&gt;
 0x00|&amp;quot;ANNO&amp;quot; FOURCC             |4 bytes big endian&lt;br /&gt;
 0x04|Annotation size (in bytes)|4 bytes big endian&lt;br /&gt;
 0x08|Null-terminated string    |(Annotation size) bytes&lt;br /&gt;
&lt;br /&gt;
== Frame ==&lt;br /&gt;
This header is used as a container for a video frame and/or an audio frame, stored in an arbitrary order. In itself, it's just a FOURCC and a size.&lt;br /&gt;
 0x00|&amp;quot;FRME&amp;quot; FOURCC        |4 bytes big endian&lt;br /&gt;
 0x04|Chunk size (in bytes)|4 bytes big endian&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
Please see the appropriate section in [[VIMA]] for an audio frame's header/codec details. Note that as far as we know right now, this codec is specific to Grim Fandango Smush files.&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
This chunk stores a potentially encoded video frame, as well as various opcodes and other stuff that's used to decode it. More details downstairs.&lt;br /&gt;
 0x000|&amp;quot;Bl16&amp;quot; FOURCC            |4 bytes big endian&lt;br /&gt;
 0x004|Chunk size (in bytes)    |4 bytes big endian&lt;br /&gt;
 0x008|Unknown                  |8 bytes&lt;br /&gt;
 0x010|Width                    |4 bytes little endian&lt;br /&gt;
 0x014|Height                   |4 bytes little endian&lt;br /&gt;
 0x018|Sequence #               |2 bytes little endian&lt;br /&gt;
 0x01A|Subcodec ID              |1 byte&lt;br /&gt;
 0x01B|Diff buffer rotate code  |1 byte&lt;br /&gt;
 0x020|Small codebook           |8 bytes, 4 color values 2 bytes little endian each&lt;br /&gt;
 0x028|Background colour        |2 bytes little endian&lt;br /&gt;
 0x02C|RLE output size (bytes)  |4 bytes little endian&lt;br /&gt;
 0x030|Codebook                 |Each entry is 2 bytes little endian&lt;br /&gt;
 0x238|Video stream             |...&lt;br /&gt;
&lt;br /&gt;
= Codec =&lt;br /&gt;
The codec is actually a combination of several subcodecs. The subcodec that's used for a particular frame is indicated by the appropriate field in the &amp;quot;Bl16&amp;quot; chunk of the frame.&lt;br /&gt;
&lt;br /&gt;
Output colors are 16-bit little endian, using the &amp;quot;565&amp;quot; bit arrangmenet.&lt;br /&gt;
&lt;br /&gt;
== Triple Diff Buffering ==&lt;br /&gt;
Smush uses a triple diff buffer mechanism to decode image data. A decoder's state includes three buffers, which are occasionally referenced by various subcodecs to decode individual frames. We will hereafter refer to said buffers as &amp;quot;db0&amp;quot;, &amp;quot;db1&amp;quot;, and &amp;quot;db2&amp;quot;, where &amp;quot;db0&amp;quot; is the logical &amp;quot;current&amp;quot; diff buffer. It is crucial to note that &amp;quot;dbX&amp;quot; is only an ''alias'' to a particular diff buffer and does not stand for the ''contents'' of the buffer itself. In other words, it's a pointer. &lt;br /&gt;
&lt;br /&gt;
Each frame contains an opcode that specifies how said buffers are rotated. Only two opcodes are used. Any other opcodes are ignored as &amp;quot;no-ops.&amp;quot;&lt;br /&gt;
 Opcode 1:&lt;br /&gt;
    swap(db0, db2)&lt;br /&gt;
 Opcode 2:&lt;br /&gt;
    swap(db1, db2)&lt;br /&gt;
    swap(db2, db0) &lt;br /&gt;
&lt;br /&gt;
== Initial Setup ==&lt;br /&gt;
We need to initialize two codebooks of 4x4 and 8x8 glyphs. The glyphs themselves are monochrome and thus consist of a foreground and background. We hereafter refer to said codebooks as glyph4_cb and glyph8_cb.&lt;br /&gt;
&lt;br /&gt;
The construction algorithm iterates through two coordinate vectors, and interpolates an NxN glyph using every position in the x-vector with every position in the y-vector. Each vector contains 16 coordinates for a grand total of 256 glyphs per glyph size.&lt;br /&gt;
&lt;br /&gt;
The vectors are defined for 4x4 and 8x8 glyphs as follows.&lt;br /&gt;
 const int xvector4[] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 };&lt;br /&gt;
 const int yvector4[] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 };&lt;br /&gt;
&lt;br /&gt;
 const int xvector8[] = { 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 };&lt;br /&gt;
 const int yvector8[] = { 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 };&lt;br /&gt;
&lt;br /&gt;
Here's how we make 4x4 glyphs. The algorithm for 8x8 glyphs is intuitively analogous.&lt;br /&gt;
&lt;br /&gt;
 for i = 0..16&lt;br /&gt;
 {&lt;br /&gt;
    for j = 0..16&lt;br /&gt;
    {&lt;br /&gt;
       glyph[4][4] = all zeros&lt;br /&gt;
 &lt;br /&gt;
       vert1.x = xvector4[i]&lt;br /&gt;
       vert1.y = yvector4[i]&lt;br /&gt;
       vert2.x = xvector4[j]&lt;br /&gt;
       vert2.y = yvector4[j]&lt;br /&gt;
       &lt;br /&gt;
       edge1 = get_edge(vert1.x, vert1.y)&lt;br /&gt;
       edge2 = get_edge(vert2.x, vert2.y)&lt;br /&gt;
       direction = get_direction(edge1, edge2)&lt;br /&gt;
 &lt;br /&gt;
       width = largest side of line's bounding rectangle&lt;br /&gt;
       for each discrete point in _width_ points of our line (including the tips)&lt;br /&gt;
       {&lt;br /&gt;
          if direction is up, while row = point.y is &amp;gt;= 0, glyph[row--][point.x] = 1;&lt;br /&gt;
          if direction is down, while row = point.y is &amp;lt; 4, glyph[row++][point.x] = 1;&lt;br /&gt;
          if direction is left, while col = point.x is &amp;gt;= 0, glyph[point.y][col--] = 1;&lt;br /&gt;
          if direction is right, while col = point.x is &amp;lt; 4, glyph[point.y][col++] = 1;&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       codebook4.push_back(glyph) // order is important here, so yes, it's a push_back or equivalent&lt;br /&gt;
    }&lt;br /&gt;
 }  &lt;br /&gt;
&lt;br /&gt;
And here are the supplementary functions:&lt;br /&gt;
 get_edge(x, y)&lt;br /&gt;
 {&lt;br /&gt;
    if y == 0, return bottom_edge&lt;br /&gt;
    else if y == 3, return top_edge&lt;br /&gt;
    else if x == 0, return left_edge&lt;br /&gt;
    else if x == 3, return right_edge&lt;br /&gt;
    else, return no_edge&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 get_direction(2 edges)&lt;br /&gt;
 {&lt;br /&gt;
    if (edges are left/right or right/left) or (edges are bottom/!top or !top/bottom), return up&lt;br /&gt;
    else if (edges are !bottom/top or top/!bottom), return down&lt;br /&gt;
    else if (edges are left/!right or !right/left), return left,&lt;br /&gt;
    else if (edges are bottom/top or top/bottom) or (edges are right/!left or !left/right), return right&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Main Algorithm ==&lt;br /&gt;
 if 0 == sequence number:&lt;br /&gt;
 {&lt;br /&gt;
    // this is a keyframe&lt;br /&gt;
    fill db1 and db2 with background color.&lt;br /&gt;
 }&lt;br /&gt;
 handle subcodec according to ID.&lt;br /&gt;
 copy contents of db0 into output image.&lt;br /&gt;
 rotate buffers according to opcode.&lt;br /&gt;
&lt;br /&gt;
== Subcodecs ==&lt;br /&gt;
This section explains what the individual subcodecs mean, and how to suck out image data in each case. Note that ImageSize, in bytes, is defined as (Width * Height * 2)&lt;br /&gt;
&lt;br /&gt;
 ID|What&lt;br /&gt;
  0|Keyframe. Copy ImageSize bytes from video stream into db0.&lt;br /&gt;
  1|Never encountered so far.&lt;br /&gt;
  2|Hierarchical VQ and motion compensation.&lt;br /&gt;
  3|Copy ImageSize bytes from db2 into db0.&lt;br /&gt;
  4|Copy ImageSize bytes from db1 into db0.&lt;br /&gt;
  5|RLE decode. See below.&lt;br /&gt;
  6|Simple lookup/write. See below.&lt;br /&gt;
  7|Never encountered so far.&lt;br /&gt;
  8|RLE-encoded codebook indices. See below.&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 2 ===&lt;br /&gt;
This codec is broken up into a three-level hierarchy, where each level decodes differently sized image blocks. The decoding algorithms are chosen based on opcodes provided by the video stream. Block sizes are 8x8, 4x4, and 2x2. Even though different block sizes exist, one pass through the decoding algorithm will always(!) decode an 8x8 block by either decoding an entire 8x8 block, by breaking the 8x8 block into four 4x4 blocks (and decoding each one), or by breaking a 4x4 block into four 2x2 blocks (and decoding each one). Any combination of said breakdown is possible and is up to the video stream.&lt;br /&gt;
 &lt;br /&gt;
* We indicate the current x/y coordinates in db0 by &amp;quot;cx&amp;quot; and &amp;quot;cy&amp;quot;, respectively. &lt;br /&gt;
* We assume that two-dimensional arrays are row-major. That is, to access pixel(s) (x, y) at array, we write array[y][x]. &lt;br /&gt;
&lt;br /&gt;
Decoding is done by breaking the image into 8x8 blocks (rounding up where appropriate), and starting at the top, decoding each row from left to right with Level1. (Level1 will invoke any required levels, as described below.) For example:&lt;br /&gt;
 int hblocks = round Height to next multiple of 8&lt;br /&gt;
 int wblocks = round Width to next multiple of 8&lt;br /&gt;
 &lt;br /&gt;
 cx = 0, cy = 0&lt;br /&gt;
 for hblock in range(0, hblocks)&lt;br /&gt;
 {&lt;br /&gt;
    for wblock in range(0, wblocks)&lt;br /&gt;
    {&lt;br /&gt;
       level1(cx, cy)&lt;br /&gt;
       cx += 8 // 8 pixels right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    cx = 0 // beginning of row&lt;br /&gt;
    cy += 8 // 8 pixels down&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
We now describe the decoding algorithm for each opcode, per level. The general decoding algorithm of a level looks like this:&lt;br /&gt;
 opcode = next byte in stream&lt;br /&gt;
 handle opcode (see below)&lt;br /&gt;
&lt;br /&gt;
==== Level 1 (8x8 blocks) ====&lt;br /&gt;
===== 0x00 ... 0xF4 =====&lt;br /&gt;
 x, y = motion_vectors[opcode]&lt;br /&gt;
 copy 8x8 block from db2[y + cy][x + cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF5 =====&lt;br /&gt;
 motion_vector = next 2 bytes of stream, little endian&lt;br /&gt;
 copy 8x8 block from (db2[cy][cx] + motion_vector) to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF6 =====&lt;br /&gt;
 copy 8x8 block from db1[cy][cx] to db0[cy][cx]&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 indices = next 2 bytes of stream, little endian&lt;br /&gt;
 fg_index = hibyte(indices)&lt;br /&gt;
 bg_index = lobyte(indices)&lt;br /&gt;
 fgcolor = codebook[fg_index]&lt;br /&gt;
 bgcolor = codebook[bg_index]    &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF8 =====&lt;br /&gt;
 glyph8_index = next byte of stream&lt;br /&gt;
 colors = next 4 bytes of stream, little endian&lt;br /&gt;
 fgcolor = hiword(colors)&lt;br /&gt;
 bgcolor = loword(colors)   &lt;br /&gt;
 draw 8x8 glyph from glyph8_cb[glyph8_index] into db0[cy][cx] using fgcolor and bgcolor&lt;br /&gt;
&lt;br /&gt;
===== 0xF9, 0xFA, 0xFB, 0xFC =====&lt;br /&gt;
 color = value from small_codebook[opcode - 0xf9], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFD =====&lt;br /&gt;
 index = value of next byte in stream&lt;br /&gt;
 color = value from codebook[index], little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFE =====&lt;br /&gt;
 color = next 2 bytes in stream, little endian&lt;br /&gt;
 fill 8x8 block in db0[cy][cx] with color&lt;br /&gt;
&lt;br /&gt;
===== 0xFF =====&lt;br /&gt;
This effectively breaks this block up into four 4x4 blocks and invokes the next level to decode them.&lt;br /&gt;
 next_level(cx    , cy)&lt;br /&gt;
 next_level(cx + 4, cy)&lt;br /&gt;
 next_level(cx    , cy + 4)&lt;br /&gt;
 next_level(cx + 4, cy + 4)&lt;br /&gt;
&lt;br /&gt;
==== Level 2 (4x4 blocks) ====&lt;br /&gt;
Exactly the same as Level 1, except with 4x4 blocks.&lt;br /&gt;
&lt;br /&gt;
==== Level 3 (2x2 blocks) ====&lt;br /&gt;
Same as the other levels except with 2x2 blocks, and with the following differences.&lt;br /&gt;
&lt;br /&gt;
===== 0xF7 =====&lt;br /&gt;
 indices[2][2] = next 4 bytes of stream, little endian&lt;br /&gt;
 write a 2x2 block into db0[cy][cx] using codebook[indices[][]] for colors&lt;br /&gt;
&lt;br /&gt;
===== 0xF8, 0xFF =====&lt;br /&gt;
 db0[cy][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx] = next 2 bytes of stream, little endian&lt;br /&gt;
 db0[cy + 1][cx + 1] = next 2 bytes of stream, little endian&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 5 ===&lt;br /&gt;
This is an RLE scheme, with the added touch that colours are stored in big-endian.&lt;br /&gt;
 size = RLE output size field from Bl16 header&lt;br /&gt;
 rle_decode(db0, video stream, size)&lt;br /&gt;
 for each 16-bit value of (size / 2) values starting at db0&lt;br /&gt;
 {&lt;br /&gt;
    flip_bytes(value)&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And here's the routine itself:&lt;br /&gt;
 rle_decode(dst, src, const size)&lt;br /&gt;
 {&lt;br /&gt;
    remaining = size&lt;br /&gt;
    while (remaining)&lt;br /&gt;
    {&lt;br /&gt;
       code = next byte of stream&lt;br /&gt;
       line_length = (code &amp;gt;&amp;gt; 1) + 1&lt;br /&gt;
  &lt;br /&gt;
       if (code &amp;amp; 1) // RLE run&lt;br /&gt;
       {&lt;br /&gt;
          color = next byte of input stream&lt;br /&gt;
          fill line_length bytes in dst with color&lt;br /&gt;
       }&lt;br /&gt;
       else // raw image data&lt;br /&gt;
       {&lt;br /&gt;
          copy line_length bytes from src into dst&lt;br /&gt;
       }&lt;br /&gt;
    &lt;br /&gt;
       remaining -= line_length&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 6 ===&lt;br /&gt;
This is a straightforward codebook lookup/write routine.&lt;br /&gt;
 for each pixel in db0:&lt;br /&gt;
 {&lt;br /&gt;
    index = value of next byte in video stream;&lt;br /&gt;
    pixel = (2 bytes little endian) codebook[index];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Subcodec 8 ===&lt;br /&gt;
Used by loladies.snm, and repmec3c.snm.&lt;br /&gt;
&lt;br /&gt;
Another RLE scheme, where the actual indices into the codebook are RLE-compressed. The decompression algorithm uses the same RLE decoding as in Subcodec 5.&lt;br /&gt;
 indices = []&lt;br /&gt;
 rle_decode(indices, video stream, width * height)&lt;br /&gt;
 for each pixel in db0, i in range(0, indices.size())&lt;br /&gt;
 {&lt;br /&gt;
    pixel = codebook[indices[i]]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix A: Motion Vectors =&lt;br /&gt;
This is the static motion vector table used in Subcodec 2. Each element is an (x, y) pair.&lt;br /&gt;
 int motion_vectors[256][2] =&lt;br /&gt;
 {&lt;br /&gt;
    {0,   0}, {-1, -43}, {6, -43},  {-9, -42},  {13, -41},&lt;br /&gt;
    {-16, -40},  {19, -39}, {-23, -36},  {26, -34},  {-2, -33},&lt;br /&gt;
    {4, -33}, {-29, -32},  {-9, -32},  {11, -31}, {-16, -29},&lt;br /&gt;
    {32, -29},  {18, -28}, {-34, -26}, {-22, -25},  {-1, -25},&lt;br /&gt;
    {3, -25},  {-7, -24},   {8, -24},  {24, -23},  {36, -23},&lt;br /&gt;
    {-12, -22},  {13, -21}, {-38, -20},   {0, -20}, {-27, -19},&lt;br /&gt;
    {-4, -19},   {4, -19}, {-17, -18},  {-8, -17},   {8, -17},&lt;br /&gt;
    {18, -17},  {28, -17},  {39, -17}, {-12, -15},  {12, -15},&lt;br /&gt;
    {-21, -14},  {-1, -14},   {1, -14}, {-41, -13},  {-5, -13},&lt;br /&gt;
    {5, -13},  {21, -13}, {-31, -12}, {-15, -11},  {-8, -11},&lt;br /&gt;
    {8, -11},  {15, -11},  {-2, -10},   {1, -10},  {31, -10},&lt;br /&gt;
    {-23,  -9}, {-11,  -9},  {-5,  -9},   {4,  -9},  {11,  -9},&lt;br /&gt;
    {42,  -9},   {6,  -8},  {24,  -8}, {-18,  -7},  {-7,  -7},&lt;br /&gt;
    {-3,  -7},  {-1,  -7},   {2,  -7},  {18,  -7}, {-43,  -6},&lt;br /&gt;
    {-13,  -6},  {-4,  -6},   {4,  -6},   {8,  -6}, {-33,  -5},&lt;br /&gt;
    {-9,  -5},  {-2,  -5},   {0,  -5},   {2,  -5},   {5,  -5},&lt;br /&gt;
    {13,  -5}, {-25,  -4},  {-6,  -4},  {-3,  -4},   {3,  -4},&lt;br /&gt;
    {9,  -4}, {-19,  -3},  {-7,  -3},  {-4,  -3},  {-2,  -3},&lt;br /&gt;
    {-1,  -3},   {0,  -3},   {1,  -3},   {2,  -3},   {4,  -3},&lt;br /&gt;
    {6,  -3},  {33,  -3}, {-14,  -2}, {-10,  -2},  {-5,  -2},&lt;br /&gt;
    {-3,  -2},  {-2,  -2},  {-1,  -2},   {0,  -2},   {1,  -2},&lt;br /&gt;
    {2,  -2},   {3,  -2},   {5,  -2},   {7,  -2},  {14,  -2},&lt;br /&gt;
    {19,  -2},  {25,  -2},  {43,  -2},  {-7,  -1},  {-3,  -1},&lt;br /&gt;
    {-2,  -1},  {-1,  -1},   {0,  -1},   {1,  -1},   {2,  -1},&lt;br /&gt;
    {3,  -1},  {10,  -1},  {-5,   0},  {-3,   0},  {-2,   0},&lt;br /&gt;
    {-1,   0},   {1,   0},   {2,   0},   {3,   0},   {5,   0},&lt;br /&gt;
    {7,   0}, {-10,   1},  {-7,   1},  {-3,   1},  {-2,   1},&lt;br /&gt;
    {-1,   1},   {0,   1},   {1,   1},   {2,   1},   {3,   1},&lt;br /&gt;
    {-43,   2}, {-25,   2}, {-19,   2}, {-14,   2},  {-5,   2},&lt;br /&gt;
    {-3,   2},  {-2,   2},  {-1,   2},   {0,   2},   {1,   2},&lt;br /&gt;
    {2,   2},   {3,   2},   {5,   2},   {7,   2},  {10,   2},&lt;br /&gt;
    {14,   2}, {-33,   3},  {-6,   3},  {-4,   3},  {-2,   3},&lt;br /&gt;
    {-1,   3},   {0,   3},   {1,   3},   {2,   3},   {4,   3},&lt;br /&gt;
    {19,   3},  {-9,   4},  {-3,   4},   {3,   4},   {7,   4},&lt;br /&gt;
    {25,   4}, {-13,   5},  {-5,   5},  {-2,   5},   {0,   5},&lt;br /&gt;
    {2,   5},   {5,   5},   {9,   5},  {33,   5},  {-8,   6},&lt;br /&gt;
    {-4,   6},   {4,   6},  {13,   6},  {43,   6}, {-18,   7},&lt;br /&gt;
    {-2,   7},   {0,   7},   {2,   7},   {7,   7},  {18,   7},&lt;br /&gt;
    {-24,   8},  {-6,   8}, {-42,   9}, {-11,   9},  {-4,   9},&lt;br /&gt;
    {5,   9},  {11,   9},  {23,   9}, {-31,  10},  {-1,  10},&lt;br /&gt;
    {2,  10}, {-15,  11},  {-8,  11},   {8,  11},  {15,  11},&lt;br /&gt;
    {31,  12}, {-21,  13},  {-5,  13},   {5,  13},  {41,  13},&lt;br /&gt;
    {-1,  14},   {1,  14},  {21,  14}, {-12,  15},  {12,  15},&lt;br /&gt;
    {-39,  17}, {-28,  17}, {-18,  17},  {-8,  17},   {8,  17},&lt;br /&gt;
    {17,  18},  {-4,  19},   {0,  19},   {4,  19},  {27,  19},&lt;br /&gt;
    {38,  20}, {-13,  21},  {12,  22}, {-36,  23}, {-24,  23},&lt;br /&gt;
    {-8,  24},   {7,  24},  {-3,  25},   {1,  25},  {22,  25},&lt;br /&gt;
    {34,  26}, {-18,  28}, {-32,  29},  {16,  29}, {-11,  31},&lt;br /&gt;
    {9,  32},  {29,  32},  {-4,  33},   {2,  33}, {-26,  34},&lt;br /&gt;
    {23,  36}, {-19,  39},  {16,  40}, {-13,  41},   {9,  42},&lt;br /&gt;
    {-6,  43},   {1,  43},   {0,   0},   {0,   0},   {0,   0}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Formats]] [[Category:Video Codecs]] [[Category: Video FourCCs]]&lt;/div&gt;</summary>
		<author><name>Cyril</name></author>
	</entry>
</feed>