nvidia-texture-tools/wiki/ApiDocumentation.wiki

431 lines
17 KiB
Plaintext
Raw Normal View History

#summary API Documentation
#labels Documentation,Featured
== Contents ==
* [ApiDocumentation#Introduction Introduction]
* [ApiDocumentation#Usage Usage]
* [ApiDocumentation#Input_Options Input Options]
* [ApiDocumentation#Specifying_Input_Images Specifying Input Images]
* [ApiDocumentation#Mipmap_Generation Mipmap Generation]
* [ApiDocumentation#Gamma_Correction Gamma Correction]
* [ApiDocumentation#Processing_Normal_Maps Processing Normal Maps]
* [ApiDocumentation#Generating_Normal_Maps Generating Normal Maps]
* [ApiDocumentation#Image_Resizing Image Resizing]
* [ApiDocumentation#Compression_Options Compression Options]
* [ApiDocumentation#Compression_Formats Compression Formats]
* [ApiDocumentation#Compression_Quality Compression Quality]
* [ApiDocumentation#GPU_Acceleration GPU Acceleration]
* [ApiDocumentation#Color_Weighting Color Weighting]
* [ApiDocumentation#Pixel_Format_Conversion Pixel Format Conversion]
* [ApiDocumentation#Quantization Quantization]
* [ApiDocumentation#Output_Options Output Options]
* [ApiDocumentation#Output_Handler Output Handler]
* [ApiDocumentation#Producing_DDS_Files Producing DDS Files]
* [ApiDocumentation#Reporting_Progress Reporting Progress]
* [ApiDocumentation#Handling_Errors Handling Errors]
== Introduction ==
The NVIDIA Texture Tools library (NVTT for short) is a C++ library that allows you to create textures compressed in any of the DX10 texture formats, and apply certain transformations to them such as mipmap generation, and normal map conversion.
== Usage ==
By default NVTT is compiled as a shared library. To use it in your application you only have to link it implicitly. With gcc that's achieved using `-lnvtt`, and with Visual Studio you have to add `nvtt.lib` to the Linker -> Input -> Additional Dependencies field of the project settings. Dynamic linking the library explicitly is not recommended.
In order to access the API you only have to include the [http://nvidia-texture-tools.googlecode.com/svn/trunk/src/nvtt/nvtt.h nvtt.h] header file:
{{{
#include <nvtt/nvtt.h>
}}}
All the members of the API are in the `nvtt` namespace. Members outside of the `nvtt` namespace should not be considered public and are subject to change. If you want your code to always stay compatible with the latest release of NVTT, you should not include other headers, nor use members outside of the `nvtt` namespace.
As new features are added to NVTT, binary compatibility will always be preserved. That should allow upgrading to new versions without even having to recompile the application code.
The most important function of the NVTT API is the following:
{{{
bool Compressor::process(const InputOptions &, const CompressionOptions &, const OutputOptions &);
}}}
It takes the texture defined by `InputOptions`, compresses it according to the `CompressionOptions` and outputs it according to the `OutputOptions`. These classes are documented in detail in the following sections.
Here's a very simple usage example:
{{{
InputOptions inputOptions;
inputOptions.setTextureLayout(TextureType_2D, w, h);
inputOptions.setMipmapData(data, w, h);
OutputOptions outputOptions;
outputOptions.setFileName("output.dds");
CompressionOptions compressionOptions;
compressionOptions.setFormat(Format_DXT1);
Compressor compressor;
compressor.process(inputOptions, compressionOptions, outputOptions);
}}}
== Input Options ==
The `InputOptions` class describes the images that compose the compressed texture, and several image processing operations that can be applied to them.
=== Specifying Input Images ===
Before specifying the image data, the layout of the texture has to be defined. This is done with the following method:
{{{
void InputOptions::setTextureLayout(TextureType type, int width, int height, int depth=1);
}}}
where texture `type` is one of the following:
* !TextureType_2D
* !TextureType_Cube
Note that 3D textures are not supported yet. The `depth` argument should always be equal to 1.
Once the layout of the texture has been defined, the data for each of the images can be provided with the following method:
{{{
bool InputOptions::setMipmapData(const void * data, int w, int h, int d, int face, int mipmap);
}}}
NVTT internally allocates a copy of the provided data, that allows you to delete or reuse the memory.
If the width, height or depth of the provided mipmap does not match the one expected by the layout the function returns false, otherwise it returns true.
Again, since 3D textures are not supported, the depth argument should always be set to 1.
*TODO*: explain how the size of the mipmaps is computed, specially for non powers of two.
=== Mipmap Generation ===
Each of the faces of the surface is composed of a mipmap chain. You can provide each of these images explicitely with the `setMipmapData` method, but you can also disable mipmap generation or let the library compute the mipmaps procedurally. The following method provides some control over this process:
{{{
void InputOptions::setMipmapping(bool generateMipmaps, MipmapFilter filter, int maxLevel);
}}}
In order to output mipmaps for each of the faces of the surface, the `generateMipmaps` argument should be set to true.
If the mipmap image is not provided explicitly by the application, and generate mipmaps is enabled, then the mipmaps will be generated automatically from the previous level using a downsampling filter.
*TODO*: Partial mipmap chains.
By default the entire mipmap chain is generated, but it's possible to limit the number of mimap levels generated with the `maxLevel` argument. When `maxLevel` is set to -1, this argument has no effect.
It's possible to specify what filter should be used using the `filter` argument. The available options are:
* !MipmapFilter_Box
* !MipmapFilter_Triangle
* !MipmapFilter_Kaiser
`MipmapFilter_Box` is a [http://developer.nvidia.com/object/np2_mipmapping.html polyphase box filter]. It's the default option and good choice for most cases. It's also much faster than the other filters.
`MipmapFilter_Triangle` uses a triangle filter. The kernel has a larger width and thus produces blurrier results than the box filter.
`MipmapFilter_Kaiser` is a Kaiser-windowed sinc filter. That's generally considered the best choice for downsampling filters, but in order to obtain best results it may be required to tweak some of the parameters of the filter, otherwise the resulting images could suffer from ringing artifacts or the result may not be as sharp as desired. The default values of the parameters are generally safe, but it's possible to tweak them using the following method:
{{{
void InputOptions::setKaiserParameters(float width, float alpha, float stretch);
}}}
The default values are:
{{{
inputOptions.setKaiserParameters(3.0f, 4.0f, 1.0f);
}}}
Larger kernel widths are supposed to approximate better a perfect low pass filter, but sometimes result in ringing artifacts. Values above 5 are not recommended. You should not change the alpha and stretch values unless you know what you are doing.
You can compare the result of each of these filters at [ResizeFilters]. For more information about mipmap generation algorithms see [MipmapGeneration].
When evaluating the color of texels that are near the border, most the filters usually sample outside of the texture. By default, NVTT assumes the texture wrapping mode is to mirror, because that generally looks good, but better results can be achieved by explicitly specifying the desired wrapping mode. That can be done with the following method:
{{{
void InputOptions::setWrapMode(WrapMode wrapMode);
}}}
Where the `wrapMode` argument must have one the following values:
* !WrapMode_Mirror
* !WrapMode_Repeat
* !WrapMode_Clamp
Note that the `wrapMode` is also used for other image processing operations, like normal map generation. So, it's a good idea to set it even if you are not generating mipmaps. The default `wrapMode` is `WrapMode_Mirror`.
=== Gamma Correction ===
*TODO*: Explain why gamma correction is important. Filtering in linear space. Energy conservation. Etc.
{{{
void InputOptions::setGamma(float inputGamma, float outputGamma);
}}}
By default, both the `inputGamma` and the `outputGamma` are set to 2.2. Gamma correction is only applied to the RGB channels. It's not applied to the alpha channel and it's never applied to normal maps. You can disable gamma correction by setting these values to 1.0 as follows:
{{{
inputOptions.setGamma(1.0f, 1.0f);
}}}
Note, that using different values for `inputGamma` and `outputGamma` could result in quantization artifacts when the input components only have 8 bits (that is always the case in the current version).
=== Processing Normal Maps ===
If the input image is a normal map, it may require some special treatment. For example, gamma correction won't be applied, and some operations will only be active for normal maps. To indicate that the input image is a normal map the following method is used:
{{{
void InputOptions::setNormalMap(bool isNormalMap);
}}}
Normal map mipmaps are generated by down filtering the previous normal map level, just like with regular images. However, after down filtering the resulting normals are generally not unit length. By default, these normals are re-normalized, but you can chose to left them unnormalized with the following method:
{{{
void InputOptions::setNormalizeMipmaps(bool normalizeMipmaps);
}}}
=== Generating Normal Maps ===
*TODO*: Explain how normal maps are generated from color images or height maps.
{{{
inputOptions.convertToNormalMap(true);
}}}
{{{
bool InputOptions::setHeightEvaluation(float r, float g, float b, float a);
}}}
For example, to use the alpha channel of the input texture as the height you would use the following weights:
{{{
inputOptions.setHeightEvaluation(0, 0, 0, 1);
}}}
The height factors do not necessarily sum 1. So, you can also use them to change the steepness of the height map, and the sharpness of the resulting normal map.
*TODO*: Explain normal filter, add wiki page that compares different values.
{{{
void InputOptions::setNormalFilter(float small, float medium, float big, float large);
}}}
Mipmap generation behaves as with regular normal maps. The input images are first converted to normal map. Then the mipmaps are generated from the normal maps as usual, unless the user provides the mipmaps explicitly, in which case normal map conversion is applied again.
*TODO*: Normal map conversion is only done to the input images. Mipmaps are generated from the normal map as usual.
=== Image Resizing ===
It's possible to constrain the size of the textures to a certain limit. This is accomplished with the following method:
{{{
void InputOptions::setMaxExtents(int d);
}}}
NVTT is able to handle non power of two textures correctly, but not all hardware supports them. It's possible to round the size of the input images to the next, nearest, or previous power of two. The rounding mode is specified with the following method.
{{{
void InputOptions::setRoundMode(RoundMode mode);
}}}
where `RoundMode` is one of the following:
* !RoundMode_None
* !RoundMode_ToNextPowerOfTwo
* !RoundMode_ToNearestPowerOfTwo
* !RoundMode_ToPreviousPowerOfTwo
The default round mode is none.
== Compression Options ==
*TODO*
=== Compression Formats ===
*TODO*
* RGB, RGBA
* DXT1, BC1
* DXT1a, BC1a
* DXT3, BC2
* DXT5, BC3
* DXT5n, BC3n
* BC4
* BC5, LATC, RGTC
=== Compression Quality ===
It's possible to control the quality of the compressor using the following method:
{{{
compressionOptions.setQuality(quality);
}}}
Where `quality` is one of the following:
* !Quality_Fastest
* !Quality_Normal
* !Quality_Production
* !Quality_Highest
`Quality_Fastest` will select a quick compressor that produces reasonable results in a very short amount of time. Note that this is not a real-time compressor. The code is not highly optimized, but still it's generally one order of magnitude faster than the normal CPU compression mode. If you need real-time compression you can find more resources at: [RealTimeDXTCompression].
`Quality_Normal` is the default mode and the one you should use in most cases. It provides a good trade off between compression quality and speed.
`Quality_Production` will generally produce similar results as `Quality_Normal`, but it may double or triple the compression time to obtain minor quality improvements.
`Quality_Highest` is a brute force compressor. In some cases, depending on the size of the search space, this compressor will be extremely slow. Use this only for testing purposes, to determine how much room is left for improvement in the regular compressors.
The following table indicates what compressor types are available for each of the compression formats.
|| || *Fastest* || *Normal* || *Production* || *Highest* ||
|| BC1 || Yes || Yes || || ||
|| BC1a || Yes || || || ||
|| BC2 || Yes || Yes || || ||
|| BC3 || Yes || Yes || || ||
|| BC3n || Yes || Yes || || ||
|| BC4 || Yes || Yes || Yes || ||
|| BC5 || Yes || Yes || Yes || ||
Selecting a compression quality that's not available won't produce any error, but instead it will fall back to another compression mode. If `Quality_Production` is not available, `Quality_Normal` will be used instead, and if `Quality_Normal` is not available, `Quality_Fastest` will be used. `Quality_Highest` will never be used as a fallback.
=== GPU Acceleration ===
Not all the compressors are GPU accelerated. Some formats can be compressed relatively fast, but others are much more expensive. Currently GPU acceleration is implemented only for the slowest compression modes, as shown in the following table:
|| || *GPU Accelerated* ||
|| BC1 || Yes ||
|| BC1a || ||
|| BC2 || Yes ||
|| BC3 || Yes ||
|| BC3n || ||
|| BC4 || ||
|| BC5 || ||
High quality texture compression is a complex problem that would be very hard to solve using traditional GPGPU approaches (that is, using the graphics API, vertex, and fragment shaders). For this reason GPU compression is implemented in CUDA. Note that currently, CUDA is only available on NVIDIA !GeForce 8 series.
When available, CUDA compression is enabled by default, but can be disabled as follows:
{{{
compressor.enableCudaAcceleration(false);
}}}
The GPU compressors do not provide exactly the same result as the CPU compressors. However, the difference between the two compressors is always very small and not noticeable to the eye.
=== Color Weighting ===
*TODO*
{{{
compressionOptions.setColorWeights(float red, float green, float blue);
}}}
=== Pixel Format Conversion ===
*TODO*
{{{
compressionOptions.setFormat(Format_RGB);
}}}
{{{
void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
}}}
=== Quantization ===
*TODO*
{{{
void CompressionOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127);
}}}
== Output Options ==
The most simple way of configuring the output options is by only providing the name of the file that will contain the resulting DDS texture:
{{{
OutputOptions::setFileName(const char *);
}}}
{{{
OutputOptions::setOutputHandler(OutputHandler *);
}}}
=== Output Handler ===
The output handler is an interface that defines two methods:
{{{
virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel) = 0;
virtual bool writeData(const void * data, int size) = 0;
}}}
Applications need to implement this interface in order to receive compressed data from the compressor.
*TODO*
In order to minimize memory allocations NVTT will call `writeData` as soon as compressed data is available. Some compressors output one block at a time, while others output many.
=== Producing DDS Files ===
By default the compressor calls the `writeData` method before indicating the image that the data belongs to. That means that the data does not belong to any of the surface images, but is part of the header file. If you don't want to output the header file, you can ignore these calls, or disable this behavior with:
{{{
outputOptions.setOutputHeader(false);
}}}
=== Reporting Progress ===
*TODO*
=== Handling Errors ===
NVTT will produce errors in some circumstances. In order to detect them it's possible to register an error handler with the following method:
{{{
OutputOptions::setErrorHandler(ErrorHandler *);
}}}
The `ErrorHandler` interface has a single method:
{{{
virtual void error(Error e) = 0;
}}}
That receives one of these error codes:
* !Error_Unknown
* !Error_InvalidInput
* !Error_UnsupportedFeature
* !Error_CudaError
* !Error_FileOpen
* !Error_FileWrite
It's possible to translate the error codes to strings using the following function:
{{{
const char * nvtt::errorString(Error e);
}}}