Say something like, "It was conceived by a comity formed by the
clones of history's greatest minds, inscribed on sheets of silk by immaculate
virgins using ink made by blind monks who used ground down charred pieces
of the true cross. It was prompty lost in a sea of paganistic anarchy for a
thousand years, kept secret by templar knights and guarded by the last great
Chinese dragon and curses more powerful than those of Tutankhamen, until DooMWiz
performed an ancient series of rituals and rights-of-passage until finally he
was allowed the right to glimpse its wonderous magnificence. He promptly stole it."
.oil files are always in little endian format.
File Header
The .oil format is powerful, yet easy to read and begins with the obligatory
file header.
- typedef struct OILHEAD
{
- char ByteHead[4];
ILuint MagicNum;
ILushort Version;
ILuint NumImages;
ILuint DirOffset;
ILuint AnimInfoOffset;
char HeadString[HEAD_STRING_LEN];
- } OILHEAD;
ByteHead: This is a string that spells "OIL" (with the terminating zero).
MagicNum: This unsigned long "magic" number is 0x693D71
(or 6897009 in decimal format). Do not ask how this number was generated, as
it was a horrid process that noone should ever submit themselves to.
Version: Simply states what version of the .oil format this file is.
Unless the .oil format undergoes some major revision, more than likely, this
number will stay at 1.
NumImages: Since the .oil format supports animation, this value is the
number of images in the entire file, minus mipmaps, as they are considered
"subsets" of an image.
DirOffset: Offset from the beginning of the file to the directory.
The directory will be explained later in this document.
AnimInfoOffset: If 0, there is no animation info, else refer to the
section titled "Animation Info".
HeadString: This is a human-readable string that just describes the
type of file it is. If you want to make absolutely certain it's an .oil
file and aren't convinced up to now, check this string. You can skip it if
you want -- just skip to DirOffset. The string is currently:
"This is a graphics file based on the Open Image Library file format specification."
The length of this string is 83 bytes long (HEAD_STRING_LEN) and includes
the terminating null character.
The Directory
To accomodate for animation quite easily, .oil files have a directory at
DirOffset of the OILHEAD struct. This directory basically just tells
where all of the images are located throughout the file. With this kind of
system, there is no need to keep images in order in the file, though it is
probably desirable for sequential access. You can even put the directory
at the end of the file if you so desire. There are as many directory entries
as there are number of images, so use the NumImages member of the OILHEAD
struct to determine how many directory entries to load. The directory
entry is described as such:
- typedef struct DIRENT
{
- char Name[DIRNAME_LEN];
ILuint Offset;
ILuint ImageSize;
- } DIRENT;
DIRNAME_LEN is 255 characters, and Name is the filename of the file that this
image was taken from or even just the regular name of this image. There is
no significance to this name, except as a convenience to the author.
Offset is the number of bytes from the beginning of the file to this image.
ImageSize is the total size in bytes of the image, including mipmaps and anything
else that may be present in the image.
The Image
Finally, we are down to the image itself. An image begins with its own
little header:
- typedef struct IMAGEHEAD
{
- ILuint Width;
ILuint Height;
ILuint Depth;
ILubyte NumChan;
ILubyte Bpc;
ILubyte Type;
ILubyte Compression;
ILubyte NumMipmaps;
ILuint Duration;
ILuint SizeOfData;
- } IMAGEHEAD;
Width: Specifies the number of pixels in the x direction.
Height: Specifies the number of pixels in the y direction.
Depth: Specifies the number of pixels in the z direction.
NumChan: Number of colour channels per pixel -- typically equated to bytes
per pixel (or bits per pixel / 8). This number is usually 1, 3 or 4, but any
number is theoretically support in the format, though support for it will
not be available in any immediate fashion.
Bpc: Bytes per channel -- usually, this is 1, showing that each channel
only occupies one byte (one byte for red, one for green, one for blue, etc.).
The other common value for this field is 2, usually signifying 64 bits per pixel.
- Type: Type is what type the image format is.
-
If Type is 1, then the image has a palette.
If Type is 2, then the image is only luminance values (greyscale).
If Type is 3, then the image's data is in bgr (blue-green-red) format.
If Type is 4, then the image's data is in bgra (blue-green-red-alpha) format.
Compression: Tells how the image data has been compressed. This field
is what allows us to have virtually any kind of compression. Applications
can even try to compress an image various ways before deciding on the best
compression style for that particular image before compressing the image. With
this field in place, we even have the option of lossy compression! The .oil
specifications were designed with lossless compression in mind, but lossy
compression may be ideally suited to certain types of images. There are currently
four "official" compression schemes right now:
- Compression Type:
- 0: No compression. Image data is to be read directly.
- 1: Run-length encoding. This version of rle is adapted from the .tga
specification, which can be found at
Wotsit's Format.
- 2: lzo compression. Just uses the lzo1x_decompress and lzo1x_compress functions from miniLZO.
miniLZO can be found at the LZO Homepage.
- 3: zlib compression. Just uses the uncompress and compress functions from zlib.
zlib can be found at the zlib Homepage.
Source examples for all three of these can be found in the
DevIL sources, in oil.c.
NumMipmaps: Tells how many mipmaps immediately follow the image data. These
are discussed in greater detail later in this document.
Duration: Specifies the number of milliseconds this image ("frame") should be
displayed if part of an animation.
SizeOfData: Actual size of the image data on disk. This is the compressed
size, if the image was compressed, or if not, it is the size of the image data in memory
and on disk. This field is particularly useful for skipping the correct number of
bytes if you do not understand the compression type used in this image (such as
new compression engines being used in future versions of DevIL or other programs).
The main use of this field though is for decompression of the image data, because
you don't want to read too much when decompressing, so you don't overstep an array's
boundaries.
Palettes
Only if the Type field of the image's header (IMAGEHEAD) is 1, then the image has a
palette. The palette is always in bgra (blue-green-red-alpha) format. Immediately
following the SizeOfData member of the image's header is the size of the entire palette
in number of bytes as an unsigned long. For instance, if there are 256 palette entries,
at 4 bytes per entry (bgra), 1024 should be written here. If the Type field of the
image's header is not 1, this unsigned long value is not present.
Image Data
All multichannel image data is in blue-green-red format instead of
red-green-blue, like some other image formats. The data is interleaved, meaning
that we do not separate data into channels. In other words, our data looks like
bgrbgrbgr instead of bbbgggrrr. Luminance data (type 2) is just read as a series
of values, as is colour indexed data. How many bytes you read per pixel is
dependent on both the number of channels and the bytes per channel. Just multiply
these two values to determine how many bytes you must read per pixel. For programs
that can only make sense out of one byte per channel, assume that the data is only
in the top byte.
Mipmaps
Immediately following the (compressed or uncompressed) image data is the mipmaps.
Mipmaps have the exact same format as their parents and even share the same
image header, though the Duration and NumMipmaps members are ignored for mipmaps.
The duration of the mipmap is the same duration as its parent, and mipmaps are
not allowed to have mipmaps of their own.
Animation Info
This "directory" at the offset specified by AnimInfoOffset in OILHEAD is a simple
list of the animation frames and their duration. This feature should be useful
if you are wanting to reuse frames and do not wish to waste space by including them twice.
- typedef struct FRAME
{
- ILuint FrameNum;
ILuint Duration;
- } FRAME;
- typedef struct ANIM_INFO
{
- ILuint NumFrames;
FRAME Frames[NumFrames];
- } ANIM_INFO;
The first four bytes (NumFrames) make up an unsigned long that tells how many frames
follow. Immediately after, there are NumFrames "frames" that make up the animation
info. Each frame is just 8 bytes. The first unsigned int (FrameNum) is the frame
number to display, and the second unsigned int (Duration) is the duration
(in milliseconds) to show the frame for.
That should be all for the .oil format. Any comments, questions or suggestions
should be sent to Denton Woods.