mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2024-11-25 17:18:12 -05:00
679 lines
24 KiB
TeX
679 lines
24 KiB
TeX
|
%-------------------------------------------------------------------------------
|
||
|
% Document: OpenCTM Format Specification
|
||
|
% Author: Marcus Geelnard
|
||
|
% Compile: pdflatex FormatSpecification.tex
|
||
|
%-------------------------------------------------------------------------------
|
||
|
% Note: You need a LaTeX environment to build this document as PDF. The
|
||
|
% recommended way is to install TeX Live (http://www.tug.org/texlive/) and
|
||
|
% a decent LaTeX editor (e.g. texmaker, LEd, etc).
|
||
|
%
|
||
|
% Ubuntu: sudo apt-get install texlive-full
|
||
|
% Mac OS X: http://www.tug.org/mactex/ (MacTeX.mpkg.zip)
|
||
|
%
|
||
|
% To build the PDF document, run pdflatex twice on this .tex file (in order to
|
||
|
% correctly build the TOC).
|
||
|
%-------------------------------------------------------------------------------
|
||
|
|
||
|
% Use the OpenCTM TeX style
|
||
|
\input{openctm-tex.sty}
|
||
|
|
||
|
% Document properties
|
||
|
\author{Marcus Geelnard}
|
||
|
\title{OpenCTM Format Specification}
|
||
|
|
||
|
% PDF specific document properties
|
||
|
\hypersetup{pdftitle={OpenCTM Format Specification}}
|
||
|
\hypersetup{pdfauthor={Marcus Geelnard}}
|
||
|
\hypersetup{pdfkeywords={OpenCTM,format,specification}}
|
||
|
|
||
|
% Document contents
|
||
|
\begin{document}
|
||
|
|
||
|
%--[ Title page ]---------------------------------------------------------------
|
||
|
|
||
|
\begin{titlepage}
|
||
|
\begin{center}
|
||
|
~
|
||
|
\vspace{5cm}
|
||
|
|
||
|
\includegraphics[width=10.0cm]{logo.pdf}
|
||
|
\vspace{0.4cm}
|
||
|
|
||
|
{\large File format version 5}
|
||
|
|
||
|
\vspace{1.0cm}
|
||
|
|
||
|
{\Large Format Specification}
|
||
|
\vspace{1.5cm}
|
||
|
|
||
|
Copyright \copyright \ 2009-2010 Marcus Geelnard
|
||
|
\end{center}
|
||
|
\end{titlepage}
|
||
|
|
||
|
|
||
|
%--[ Table of contents ]--------------------------------------------------------
|
||
|
|
||
|
\tableofcontents
|
||
|
|
||
|
|
||
|
%-------------------------------------------------------------------------------
|
||
|
|
||
|
\chapter{Overview}
|
||
|
This document describes version 5 of the OpenCTM file format.
|
||
|
|
||
|
\section{File structure}
|
||
|
The structure of an OpenCTM file is as follows:
|
||
|
|
||
|
[Header]\newline
|
||
|
[Body data]
|
||
|
|
||
|
Each part of the file is described in the following chapters.
|
||
|
|
||
|
\section{Data formats}
|
||
|
All integer fields are stored in 32-bit little endian format (least significant
|
||
|
byte first).
|
||
|
|
||
|
All floating point fields are stored in 32-bit binary IEEE 754 format (little
|
||
|
endian).
|
||
|
|
||
|
All strings are stored as a 32-bit integer string length (number of bytes)
|
||
|
followed by a UTF-8 format string (there is no zero termination and no BOM).
|
||
|
|
||
|
\section{Packed data}
|
||
|
\label{sec:PackedData}
|
||
|
Some portions of the file are be packed by the lossless LZMA entropy coder,
|
||
|
and are encoded as follows:
|
||
|
|
||
|
\begin{tabular}{|l|l|p{11cm}|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Packed size (number of bytes, $p$).\\ \hline
|
||
|
4 & - & LZMA specific props (five bytes, required by the LZMA decoder).\\ \hline
|
||
|
9 & - & LZMA packed stream ($p$ bytes long) that has been generated by the LzmaCompress() function of the LZMA API.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of the unpacked data is always known from the context (e.g. the
|
||
|
triangle count uniquely defines the number of bytes required for the
|
||
|
uncompressed triangle indices array).
|
||
|
|
||
|
\subsection{Element interleaving}
|
||
|
Some packed data arrays use element level interleaving, meaning that the
|
||
|
data values are rearranged at the element level. For instance, in a data array
|
||
|
with three elements per value (stride = 3), $x$, $y$ and $z$, the elements are
|
||
|
rearranged as follows:
|
||
|
|
||
|
\begin{center}
|
||
|
$x_1,y_1,z_1,x_2,y_2,z_2,\ldots,x_N,y_N,z_N \Rightarrow
|
||
|
x_1,x_2,\ldots,x_N,y_1,y_2,\ldots,y_N,z_1,z_2,\ldots,z_N$
|
||
|
\end{center}
|
||
|
|
||
|
When decompressing an array that uses element interleaving, the process is
|
||
|
reversed.
|
||
|
|
||
|
\subsection{Byte interleaving}
|
||
|
All packed data arrays use byte level interleaving, meaning that data values
|
||
|
are rearranged at the byte level. For instance, in an integer array, where each
|
||
|
element consists of four bytes: $a$, $b$, $c$ and $d$, the bytes are rearranged
|
||
|
as follows:
|
||
|
|
||
|
\begin{center}
|
||
|
$a_1,b_1,c_1,d_1,a_2,b_2,c_2,d_2,\ldots,a_N,b_N,c_N,d_N \Rightarrow
|
||
|
a_1,a_2,\ldots,a_N,b_1,b_2,\ldots,b_N,c_1,c_2,\ldots,c_N,d_1,d_2,\ldots,d_N$
|
||
|
\end{center}
|
||
|
|
||
|
When decompressing an array that uses byte interleaving, the process is
|
||
|
reversed.
|
||
|
|
||
|
\subsection{Signed magnitude representation}
|
||
|
Some packed integer arrays use signed magnitude representation.
|
||
|
|
||
|
A signed magnitude value, $x'$, is converted to a two's complement value,
|
||
|
$x$, with the following method:
|
||
|
|
||
|
$x = \begin{cases}
|
||
|
x'\; shr\; 1 & x'_0 = 0 \\
|
||
|
-((x'+1)\; shr\; 1) & x'_0 = 1
|
||
|
\end{cases}$
|
||
|
|
||
|
...where $x'_0$ is the least significant bit of $x'$.
|
||
|
|
||
|
|
||
|
%-------------------------------------------------------------------------------
|
||
|
|
||
|
\chapter{Header}
|
||
|
The file must start with a header, which looks as follows:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Magic identifier (0x4d54434f, or "OCTM" when read as ASCII).\\ \hline
|
||
|
4 & Integer & File format version (0x00000005 = version 5).\\ \hline
|
||
|
8 & Integer & Compression method, which must be one of the following:\\
|
||
|
& & 0x00574152 - Use the RAW compression method.\\
|
||
|
& & 0x0031474d - Use the MG1 compression method.\\
|
||
|
& & 0x0032474d - Use the MG2 compression method.\\ \hline
|
||
|
12 & Integer & Vertex count.\\ \hline
|
||
|
16 & Integer & Triangle count.\\ \hline
|
||
|
20 & Integer & UV map count.\\ \hline
|
||
|
24 & Integer & Attribute map count.\\ \hline
|
||
|
28 & Integer & Boolean flags, or:ed together:\\
|
||
|
& & 0x00000001 - The file contains per-vertex normals.\\ \hline
|
||
|
32 & String & File comment ($p$ bytes long string).\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of the file header is $36+p$ bytes, where $p$ is the length of the
|
||
|
comment string.
|
||
|
|
||
|
|
||
|
%-------------------------------------------------------------------------------
|
||
|
|
||
|
\chapter{Body data}
|
||
|
The body data follows immediately after the file header. Its file offset is
|
||
|
dictated by the length of the file header.
|
||
|
|
||
|
The format of the body data is specific for each compression method, which is
|
||
|
defined by the "Compression method" field in the header.
|
||
|
|
||
|
The body data contains the vertex, index, normal, UV map and attribute map
|
||
|
data, usually in a compressed form.
|
||
|
|
||
|
|
||
|
\section{RAW}
|
||
|
The layout of the body data for the RAW compression method is:
|
||
|
|
||
|
[Indices]\newline
|
||
|
[Vertices]\newline
|
||
|
[Normals]\newline
|
||
|
[UV map 0]\newline
|
||
|
[UV map 1]\newline
|
||
|
...\newline
|
||
|
[UV map N]\newline
|
||
|
[Attribute map 0]\newline
|
||
|
[Attribute map 1]\newline
|
||
|
...\newline
|
||
|
[Attribute map M]
|
||
|
|
||
|
\subsection{Indices}
|
||
|
The indices are stored as an integer identifier, 0x58444e49 ("INDX"), followed
|
||
|
by all the triangle indices. Each index is an unsigned integer value. There are
|
||
|
three indices per triangle, and the number of triangles is given by the
|
||
|
"Triangle count" field in the header:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x58444e49, or "INDX" when read as ASCII).\\ \hline
|
||
|
4 & Integer & Vertex index for the 1st corner of the 1st triangle.\\ \hline
|
||
|
8 & Integer & Vertex index for the 2nd corner of the 1st triangle.\\ \hline
|
||
|
12 & Integer & Vertex index for the 3rd corner of the 1st triangle.\\ \hline
|
||
|
16 & Integer & Vertex index for the 1st corner of the 2nd triangle.\\ \hline
|
||
|
... & & \\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of the indices section is $4(1+3N)$ bytes, where $N$ is the triangle
|
||
|
count.
|
||
|
|
||
|
\subsection{Vertices}
|
||
|
The vertices are stored as an integer identifier, 0x54524556 ("VERT"), followed
|
||
|
by all the vertex coordinates. Each vertex coordinate is stored as three
|
||
|
floating point values ($x,y,z$), and the number of vertices is given by the
|
||
|
"Vertex count" field in the header:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x54524556, or "VERT" when read as ASCII).\\ \hline
|
||
|
4 & Float & $x$ coordinate of the 1st vertex.\\ \hline
|
||
|
8 & Float & $y$ coordinate of the 1st vertex.\\ \hline
|
||
|
12 & Float & $z$ coordinate of the 1st vertex.\\ \hline
|
||
|
16 & Float & $x$ coordinate of the 2nd vertex.\\ \hline
|
||
|
... & & \\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of the vertices section is $4(1+3N)$ bytes, where $N$ is the vertex
|
||
|
count.
|
||
|
|
||
|
\subsection{Normals}
|
||
|
The normals section is optional, and only present if the per-vertex normals
|
||
|
flag is set in the header.
|
||
|
|
||
|
The normals are stored as an integer identifier, 0x4d524f4e ("NORM"), followed
|
||
|
by all the normal coordinates. Each normal is stored as three floating point
|
||
|
values ($x,y,z$), and the number of normals is given by the "Vertex count" field
|
||
|
in the header:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x4d524f4e, or "NORM" when read as ASCII).\\ \hline
|
||
|
4 & Float & $x$ coordinate of the 1st normal.\\ \hline
|
||
|
8 & Float & $y$ coordinate of the 1st normal.\\ \hline
|
||
|
12 & Float & $z$ coordinate of the 1st normal.\\ \hline
|
||
|
16 & Float & $x$ coordinate of the 2nd normal.\\ \hline
|
||
|
... & & \\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of the normals section is $4(1+3N)$ bytes, where $N$ is the vertex
|
||
|
count.
|
||
|
|
||
|
\subsection{UV maps}
|
||
|
There can be zero or more UV maps. The number of UV maps is given by the
|
||
|
UV map count in the header.
|
||
|
|
||
|
Each UV map starts with an integer identifier, 0x43584554 ("TEXC"), followed
|
||
|
by two strings (the UV map name and the UV map file name reference), and
|
||
|
finally all the UV coordinates. Each UV coordinate is stored as two floating point
|
||
|
values ($u,v$), and the number of UV coordinates is given by the "Vertex count"
|
||
|
field in the header:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x43584554, or "TEXC" when read as ASCII).\\ \hline
|
||
|
4 & String & Unique UV map name ($p$ bytes long string).\\ \hline
|
||
|
$8+p$ & String & UV map file name reference ($q$ bytes long string).\\ \hline
|
||
|
$12+p+q$ & Float & $u$ coordinate of the 1st UV coordinate.\\ \hline
|
||
|
$16+p+q$ & Float & $v$ coordinate of the 1st UV coordinate.\\ \hline
|
||
|
$20+p+q$ & Float & $u$ coordinate of the 2nd UV coordinate.\\ \hline
|
||
|
... & & \\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of a UV map section is $4(3+2N)+p+q$ bytes, where $N$ is the vertex
|
||
|
count, $p$ is the name string length, and $q$ is the file name reference string
|
||
|
length.
|
||
|
|
||
|
\subsection{Attribute maps}
|
||
|
There can be zero or more attribute maps. The number of attribute maps is given by the
|
||
|
attribute map count in the header.
|
||
|
|
||
|
Each attribute map starts with an integer identifier, 0x52545441 ("ATTR"), followed
|
||
|
by the attribute map name string, and finally all the attribute values. Each attribute
|
||
|
value is stored as four floating point values ($a,b,c,d$), and the number of
|
||
|
attribute values is given by the "Vertex count" field in the header:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x52545441, or "ATTR" when read as ASCII).\\ \hline
|
||
|
4 & String & Unique attribute map name ($p$ bytes long string).\\ \hline
|
||
|
$8+p$ & Float & $a$ component of the 1st attribute value.\\ \hline
|
||
|
$12+p$ & Float & $b$ component of the 1st attribute value.\\ \hline
|
||
|
$16+p$ & Float & $c$ component of the 1st attribute value.\\ \hline
|
||
|
$20+p$ & Float & $d$ component of the 1st attribute value.\\ \hline
|
||
|
$24+p$ & Float & $a$ component of the 2nd attribute value.\\ \hline
|
||
|
... & & \\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The length of an attribute map section is $4(2+4N)+p$ bytes, where $N$ is the vertex
|
||
|
count, and $p$ is the name string length.
|
||
|
|
||
|
|
||
|
\section{MG1}
|
||
|
The layout of the body data for the MG1 compression method is:
|
||
|
|
||
|
[Indices]\newline
|
||
|
[Vertices]\newline
|
||
|
[Normals]\newline
|
||
|
[UV map 0]\newline
|
||
|
[UV map 1]\newline
|
||
|
...\newline
|
||
|
[UV map N]\newline
|
||
|
[Attribute map 0]\newline
|
||
|
[Attribute map 1]\newline
|
||
|
...\newline
|
||
|
[Attribute map M]
|
||
|
|
||
|
\subsection{Indices}
|
||
|
\label{sec:MG1Indices}
|
||
|
The triangle indices are stored as an integer identifier, 0x58444e49 ("INDX"),
|
||
|
followed by a packed integer array with element interleaving (see
|
||
|
\ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x58444e49, or "INDX" when read as ASCII).\\ \hline
|
||
|
4 & - & Packed indices data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The unpacked indices array contains delta-encoded indices:
|
||
|
|
||
|
$i'_{1,1}, i'_{1,2}, i'_{1,3}, i'_{2,1}, i'_{2,2}, i'_{2,3} ..., i'_{M,1}, i'_{M,2}, i'_{M,3}$
|
||
|
|
||
|
...that translate into the original triangle indices with the following method:
|
||
|
|
||
|
$i_{k,1} = \begin{cases}
|
||
|
i'_{k,1} + i_{k-1,1} & (k \geq 2) \\
|
||
|
i'_{k,1} & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
$i_{k,2} = \begin{cases}
|
||
|
i'_{k,2} + i_{k-1,2} & (k \geq 2, i_{k,1} = i_{k-1,1}) \\
|
||
|
i'_{k,2} + i_{k,1} & (\text{otherwise})
|
||
|
\end{cases}$
|
||
|
|
||
|
$i_{k,3} = i'_{k,3} + i_{k,1}$
|
||
|
|
||
|
...where $i_{k,1}, i_{k,2}$ and $i_{k,3}$ are the 1:st, 2:nd and 3:rd vertex index of the
|
||
|
$k$:th triangle, respectively.
|
||
|
|
||
|
Please note that the indices should be sorted in such a manner that
|
||
|
$i'_{k,1} \geq 0, i'_{k,2} \geq 0$ and $i'_{k,3} \geq 0 \; \forall \: k$.
|
||
|
|
||
|
\subsection{Vertices}
|
||
|
The vertices are stored as an integer identifier, 0x54524556 ("VERT"), followed
|
||
|
by a packed float array without element interleaving (see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x54524556, or "VERT" when read as ASCII).\\ \hline
|
||
|
4 & - & Packed vertices data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The unpacked vertex array is stored as in the RAW format ($x, y, z$).
|
||
|
|
||
|
\subsection{Normals}
|
||
|
The normals section is optional, and only present if the per-vertex normals
|
||
|
flag is set in the header.
|
||
|
|
||
|
The normals are stored as an integer identifier, 0x4d524f4e ("NORM"), followed
|
||
|
by a packed float array with element interleaving (see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x4d524f4e, or "NORM" when read as ASCII).\\ \hline
|
||
|
4 & - & Packed normals data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The unpacked normal array is stored as in the RAW format ($x, y, z$).
|
||
|
|
||
|
\subsection{UV maps}
|
||
|
There can be zero or more UV maps. The number of UV maps is given by the
|
||
|
UV map count in the header.
|
||
|
|
||
|
Each UV map starts with an integer identifier, 0x43584554 ("TEXC"), followed
|
||
|
by two strings (the UV map name and the UV map file name reference), and
|
||
|
finally the packed UV coordinate data.
|
||
|
|
||
|
The UV coordinate data is a packed float array with element interleaving
|
||
|
(see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x43584554, or "TEXC" when read as ASCII).\\ \hline
|
||
|
4 & String & Unique UV map name ($p$ bytes long string).\\ \hline
|
||
|
$8+p$ & String & UV map file name reference ($q$ bytes long string).\\ \hline
|
||
|
$12+p+q$ & - & Packed UV coordinate data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
...where $p$ is the name string length, and $q$ is the file name reference string
|
||
|
length.
|
||
|
|
||
|
The unpacked UV coordinate array is stored as in the RAW format ($u, v$).
|
||
|
|
||
|
\subsection{Attribute maps}
|
||
|
There can be zero or more attribute maps. The number of attribute maps is given by the
|
||
|
attribute map count in the header.
|
||
|
|
||
|
Each attribute map starts with an integer identifier, 0x52545441 ("ATTR"), followed
|
||
|
by the attribute map name string, and finally the packed attribute values.
|
||
|
|
||
|
The attribute value data is a packed float array with element interleaving
|
||
|
(see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x52545441, or "ATTR" when read as ASCII).\\ \hline
|
||
|
4 & String & Unique attribute map name ($p$ bytes long string).\\ \hline
|
||
|
$8+p$ & - & Packed attribute value data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
...where $p$ is the name string length.
|
||
|
|
||
|
The unpacked attribute value array is stored as in the RAW format ($a, b, c, d$).
|
||
|
|
||
|
|
||
|
\section{MG2}
|
||
|
The layout of the body data for the MG2 compression method is:
|
||
|
|
||
|
[MG2 header]\newline
|
||
|
[Vertices]\newline
|
||
|
[Grid indices]\newline
|
||
|
[Indices]\newline
|
||
|
[Normals]\newline
|
||
|
[UV map 0]\newline
|
||
|
[UV map 1]\newline
|
||
|
...\newline
|
||
|
[UV map N]\newline
|
||
|
[Attribute map 0]\newline
|
||
|
[Attribute map 1]\newline
|
||
|
...\newline
|
||
|
[Attribute map M]
|
||
|
|
||
|
\subsection{MG2 vertex coordinate coding}
|
||
|
\label{sec:MG2VertexCoding}
|
||
|
In the MG2 compression method, all the vertices are divided into a 3D grid,
|
||
|
which can be described by an axis aligned bounding box (minimum fit to the
|
||
|
vertices), and the division factors along the $x$, $y$ and $z$ axes, as shown
|
||
|
in figure \ref{fig:Grid}.
|
||
|
|
||
|
\begin{figure}[pht]
|
||
|
\centering
|
||
|
\includegraphics[width=10.0cm]{grid.pdf}
|
||
|
\caption{3D space subdivision grid. $LB$ and $HB$ are the lower and higher bounds
|
||
|
of the axis aligned bounding box. $div_x$, $div_y$ and $div_z$ are the number
|
||
|
of divisions along each of the axes.}
|
||
|
\label{fig:Grid}
|
||
|
\end{figure}
|
||
|
|
||
|
The vertices are all coded relative to the grid origin of the grid box to which
|
||
|
they belong, and all vertices are associated with a grid box with a unique
|
||
|
grid index.
|
||
|
|
||
|
The grid index, $gi$, is encoded as:
|
||
|
|
||
|
$gi = g_x + div_x(g_y + div_y \times g_z)$
|
||
|
|
||
|
...where $g_x$, $g_y$ and $g_z$ are the integer $x$, $y$ and $z$ positions of the grid
|
||
|
box, within the grid, and:
|
||
|
|
||
|
$g_x \in [0, div_x), g_y \in [0, div_y), g_z \in [0, div_z)$
|
||
|
|
||
|
The grid box origin (lower bound) of each grid box is defined by:
|
||
|
|
||
|
$gridorigin_x(g_x) = LB_x + \frac{HB_x - LB_x}{div_x} g_x$
|
||
|
|
||
|
$gridorigin_y(g_y) = LB_y + \frac{HB_y - LB_y}{div_y} g_y$
|
||
|
|
||
|
$gridorigin_z(g_z) = LB_z + \frac{HB_z - LB_z}{div_z} g_z$
|
||
|
|
||
|
|
||
|
\subsection{MG2 header}
|
||
|
The MG2 header contains information about how to interpret the mesh data. The
|
||
|
header looks as follows:
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x4832474d, or "MG2H" when read as ASCII).\\ \hline
|
||
|
4 & Float & Vertex precision.\\ \hline
|
||
|
8 & Float & Normal precision.\\ \hline
|
||
|
12 & Float & $LB_x$ ($z$ coordinate of the lower bound of the bounding box).\\ \hline
|
||
|
16 & Float & $LB_y$ ($y$ coordinate of the lower bound of the bounding box).\\ \hline
|
||
|
20 & Float & $LB_z$ ($z$ coordinate of the lower bound of the bounding box).\\ \hline
|
||
|
24 & Float & $HB_x$ ($x$ coordinate of the higher bound of the bounding box).\\ \hline
|
||
|
28 & Float & $HB_y$ ($y$ coordinate of the higher bound of the bounding box).\\ \hline
|
||
|
32 & Float & $HB_z$ ($z$ coordinate of the higher bound of the bounding box).\\ \hline
|
||
|
36 & Integer & $div_x$ (number of grid divisions along the $x$ axis, $\geq 1$).\\ \hline
|
||
|
40 & Integer & $div_y$ (number of grid divisions along the $y$ axis, $\geq 1$).\\ \hline
|
||
|
44 & Integer & $div_z$ (number of grid divisions along the $z$ axis, $\geq 1$).\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
|
||
|
\subsection{Vertices}
|
||
|
The vertices are stored as an integer identifier, 0x54524556 ("VERT"), followed
|
||
|
by the packed vertex coordinate data.
|
||
|
|
||
|
The vertex coordinate data is a packed integer array with element interleaving
|
||
|
(see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x54524556, or "VERT" when read as ASCII).\\ \hline
|
||
|
4 & - & Packed vertex coordinate data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The unpacked vertex array has three elements per vertex:
|
||
|
|
||
|
$x'_1, y'_1, z'_1, x'_2, y'_2, z'_2, ..., x'_N, y'_N, z'_N$
|
||
|
|
||
|
The original vertex coordinate, ($x_k$, $y_k$, $z_k$), for vertex number $k$ is defined as:
|
||
|
|
||
|
$dx_k = \begin{cases}
|
||
|
x'_k + dx_{k-1} & (k \geq 2, gi_k = gi_{k-1})\\
|
||
|
x'_k & (otherwise)
|
||
|
\end{cases}$
|
||
|
|
||
|
$x_k = s \times dx_k + gridorigin_x(gi_k)$
|
||
|
|
||
|
$y_k = s \times y'_k + gridorigin_y(gi_k)$
|
||
|
|
||
|
$z_k = s \times z'_k + gridorigin_z(gi_k)$
|
||
|
|
||
|
...where $s$ is the vertex precision, $gi_k$ is the $k$:th grid index (see \ref{sec:GridIndices}),
|
||
|
and $gridorigin(gi_k)$ is the origin (lower bound) of the grid box that is indicated by
|
||
|
grid index $gi_k$, according to \ref{sec:MG2VertexCoding}.
|
||
|
|
||
|
Please note that the vertices should be sorted in such a manner that $x'_k \geq 0, y'_k \geq 0$
|
||
|
and $z'_k \geq 0 \; \forall \: k$.
|
||
|
|
||
|
|
||
|
\subsection{Grid indices}
|
||
|
\label{sec:GridIndices}
|
||
|
The grid indices are stored as an integer identifier, 0x58444947 ("GIDX"), followed
|
||
|
by a packed integer array (see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x58444947, or "GIDX" when read as ASCII).\\ \hline
|
||
|
4 & - & Packed grid indices data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
The unpacked grid indices array has one element per vertex:
|
||
|
|
||
|
$gi'_1, gi'_2, ..., gi'_N$
|
||
|
|
||
|
The grid index for vertex number $k$ is defined as:
|
||
|
|
||
|
$gi_k = \begin{cases}
|
||
|
gi'_k + gi_{k-1} & (k \geq 2)\\
|
||
|
gi'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
Please note that the vertices should be sorted in such a manner that $gi'_k \geq 0 \: \forall \: k$.
|
||
|
|
||
|
|
||
|
\subsection{Indices}
|
||
|
The triangle indices are stored exactly as in the MG1 method (see \ref{sec:MG1Indices}).
|
||
|
|
||
|
\subsection{Normals}
|
||
|
The normals section is optional, and only present if the per-vertex normals
|
||
|
flag is set in the header.
|
||
|
|
||
|
The normals are stored as an integer identifier, 0x4d524f4e ("NORM"), followed
|
||
|
by a packed integer array with element interleaving (see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x4d524f4e, or "NORM" when read as ASCII).\\ \hline
|
||
|
4 & - & Packed normals data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
Note: This section of the document is not yet complete... Please see the source
|
||
|
code file compressMG2.c for more information about how to interpret the
|
||
|
normal data array.
|
||
|
|
||
|
|
||
|
\subsection{UV maps}
|
||
|
There can be zero or more UV maps. The number of UV maps is given by the
|
||
|
UV map count in the header.
|
||
|
|
||
|
Each UV map starts with an integer identifier, 0x43584554 ("TEXC"), followed
|
||
|
by two strings (the UV map name and the UV map file name reference), the
|
||
|
UV coordinate precision (a float value), and finally the packed UV coordinate data.
|
||
|
|
||
|
The UV coordinate data is a packed integer array with element interleaving
|
||
|
and signed magnitude format (see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x43584554, or "TEXC" when read as ASCII).\\ \hline
|
||
|
4 & String & Unique UV map name ($p$ bytes long string).\\ \hline
|
||
|
$8+p$ & String & UV map file name reference ($q$ bytes long string).\\ \hline
|
||
|
$12+p+q$ & Float & UV coordinate precision, $s$.\\ \hline
|
||
|
$16+p+q$ & - & Packed UV coordinate data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
...where $p$ is the name string length, and $q$ is the file name reference string
|
||
|
length.
|
||
|
|
||
|
The unpacked UV coordinate array contains delta-encoded coordinates:
|
||
|
|
||
|
$u'_1, v'_1, u'_2, v'_2, ..., u'_N, v'_N$
|
||
|
|
||
|
The original UV coordinates are restored with the following method:
|
||
|
|
||
|
$u_k = \begin{cases}
|
||
|
s \times (u'_k + u_{k-1}) & (k \geq 2)\\
|
||
|
s \times u'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
$v_k = \begin{cases}
|
||
|
s \times (v'_k + v_{k-1}) & (k \geq 2)\\
|
||
|
s \times v'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
...where $s$ is the UV coordinate precision.
|
||
|
|
||
|
\subsection{Attribute maps}
|
||
|
There can be zero or more attribute maps. The number of attribute maps is given by the
|
||
|
attribute map count in the header.
|
||
|
|
||
|
Each attribute map starts with an integer identifier, 0x52545441 ("ATTR"), followed
|
||
|
by the attribute map name string, the attribute value precision (a float value), and
|
||
|
finally the packed attribute values.
|
||
|
|
||
|
The attribute value data is a packed integer array with element interleaving
|
||
|
and signed magnitude format (see \ref{sec:PackedData}).
|
||
|
|
||
|
\begin{tabular}{|l|l|l|}\hline
|
||
|
\textbf{Offset} & \textbf{Type} & \textbf{Description}\\ \hline
|
||
|
0 & Integer & Identifier (0x52545441, or "ATTR" when read as ASCII).\\ \hline
|
||
|
4 & String & Unique attribute map name ($p$ bytes long string).\\ \hline
|
||
|
$8+p$ & Float & Attribute value precision, $s$.\\ \hline
|
||
|
$12+p$ & - & Packed attribute value data.\\ \hline
|
||
|
\end{tabular}
|
||
|
|
||
|
...where $p$ is the name string length.
|
||
|
|
||
|
The unpacked attribute value array contains delta-encoded attribute values:
|
||
|
|
||
|
$a'_1, b'_1, c'_1, d'_1, a'_2, b'_2, c'_2, d'_2, ..., a'_N, b'_N, c'_N, d'_N$
|
||
|
|
||
|
The original attributes are restored with the following method:
|
||
|
|
||
|
$a_k = \begin{cases}
|
||
|
s \times (a'_k + a_{k-1}) & (k \geq 2)\\
|
||
|
s \times a'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
$b_k = \begin{cases}
|
||
|
s \times (b'_k + b_{k-1}) & (k \geq 2)\\
|
||
|
s \times b'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
$c_k = \begin{cases}
|
||
|
s \times (c'_k + c_{k-1}) & (k \geq 2)\\
|
||
|
s \times c'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
$d_k = \begin{cases}
|
||
|
s \times (d'_k + d_{k-1}) & (k \geq 2)\\
|
||
|
s \times d'_k & (k = 1)
|
||
|
\end{cases}$
|
||
|
|
||
|
...where $s$ is the attribute value precision.
|
||
|
|
||
|
\end{document}
|