1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
29 // Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
34 #pragma warning (disable: 4127) // conditional expression is constant
37 #define VOGL_VERSION 104
39 #define VOGL_SUPPORT_ATI_COMPRESS 0
40 #define VOGL_SUPPORT_SQUISH 0
42 typedef unsigned char vogl_uint8;
43 typedef unsigned short vogl_uint16;
44 typedef unsigned int vogl_uint32;
45 typedef signed char vogl_int8;
46 typedef signed short vogl_int16;
47 typedef signed int vogl_int32;
48 typedef unsigned int vogl_bool;
55 // .DDS using regular DXT or clustered DXT
58 cCRNFileTypeForceDWORD = 0xFFFFFFFF
61 // Supported compressed pixel formats.
62 // Basically all the standard DX9 formats, with some swizzled DXT5 formats
63 // (most of them supported by ATI's Compressonator), along with some ATI/X360 GPU specific formats.
70 cCRNFmtFirstValid = cCRNFmtDXT1,
72 // cCRNFmtDXT3 is not currently supported when writing to CRN - only DDS.
77 // Various DXT5 derivatives
78 cCRNFmtDXT5_CCxY, // Luma-chroma
79 cCRNFmtDXT5_xGxR, // Swizzled 2-component
80 cCRNFmtDXT5_xGBR, // Swizzled 3-component
81 cCRNFmtDXT5_AGBR, // Swizzled 4-component
83 // ATI 3DC and X360 DXN
87 // DXT5 alpha blocks only
94 cCRNFmtForceDWORD = 0xFFFFFFFF
97 // Various library/file format limits.
100 // Max. mipmap level resolution on any axis.
101 cCRNMaxLevelResolution = 4096,
103 cCRNMinPaletteSize = 8,
104 cCRNMaxPaletteSize = 8192,
109 cCRNMaxHelperThreads = 16,
111 cCRNMinQualityLevel = 0,
112 cCRNMaxQualityLevel = 255
115 // CRN/DDS compression flags.
116 // See the m_flags member in the vogl_comp_params struct, below.
119 // Enables perceptual colorspace distance metrics if set.
120 // Important: Be sure to disable this when compressing non-sRGB colorspace images, like normal maps!
122 cCRNCompFlagPerceptual = 1,
124 // Enables (up to) 8x8 macroblock usage if set. If disabled, only 4x4 blocks are allowed.
125 // Compression ratio will be lower when disabled, but may cut down on blocky artifacts because the process used to determine
126 // where large macroblocks can be used without artifacts isn't perfect.
128 cCRNCompFlagHierarchical = 2,
130 // cCRNCompFlagQuick disables several output file optimizations - intended for things like quicker previews.
132 cCRNCompFlagQuick = 4,
134 // DXT1: OK to use DXT1 alpha blocks for better quality or DXT1A transparency.
135 // DXT5: OK to use both DXT5 block types.
136 // Currently only used when writing to .DDS files, as .CRN uses only a subset of the possible DXTn block types.
138 cCRNCompFlagUseBothBlockTypes = 8,
140 // OK to use DXT1A transparent indices to encode black (assumes pixel shader ignores fetched alpha).
141 // Currently only used when writing to .DDS files, .CRN never uses alpha blocks.
143 cCRNCompFlagUseTransparentIndicesForBlack = 16,
145 // Disables endpoint caching, for more deterministic output.
146 // Currently only used when writing to .DDS files.
148 cCRNCompFlagDisableEndpointCaching = 32,
150 // If enabled, use the cCRNColorEndpointPaletteSize, etc. params to control the CRN palette sizes. Only useful when writing to .CRN files.
152 cCRNCompFlagManualPaletteSizes = 64,
154 // If enabled, DXT1A alpha blocks are used to encode single bit transparency.
156 cCRNCompFlagDXT1AForTransparency = 128,
158 // If enabled, the DXT1 compressor's color distance metric assumes the pixel shader will be converting the fetched RGB results to luma (Y part of YCbCr).
159 // This increases quality when compressing grayscale images, because the compressor can spread the luma error amoung all three channels (i.e. it can generate blocks
160 // with some chroma present if doing so will ultimately lead to lower luma error).
161 // Only enable on grayscale source images.
163 cCRNCompFlagGrayscaleSampling = 256,
165 // If enabled, debug information will be output during compression.
167 cCRNCompFlagDebugging = 0x80000000,
169 cCRNCompFlagForceDWORD = 0xFFFFFFFF
172 // Controls DXTn quality vs. speed control - only used when compressing to .DDS.
173 enum vogl_dxt_quality
175 cCRNDXTQualitySuperFast,
177 cCRNDXTQualityNormal,
178 cCRNDXTQualityBetter,
183 cCRNDXTQualityForceDWORD = 0xFFFFFFFF
186 // Which DXTn compressor to use when compressing to plain (non-clustered) .DDS.
187 enum vogl_dxt_compressor_type
189 cCRNDXTCompressorCRN, // Use voglcore's ETC1 or DXTc block compressor (default, highest quality, comparable or better than ati_compress or squish, and voglcore's ETC1 is a lot faster with similiar quality to Erricson's)
190 cCRNDXTCompressorCRNF, // Use voglcore's "fast" DXTc block compressor
191 cCRNDXTCompressorRYG, // Use RYG's DXTc block compressor (low quality, but very fast)
193 #if VOGL_SUPPORT_ATI_COMPRESS
194 cCRNDXTCompressorATI,
197 #if VOGL_SUPPORT_SQUISH
198 cCRNDXTCompressorSquish,
201 cCRNTotalDXTCompressors,
203 cCRNDXTCompressorForceDWORD = 0xFFFFFFFF
206 // Progress callback function.
207 // Processing will stop prematurely (and fail) if the callback returns false.
208 // phase_index, total_phases - high level progress
209 // subphase_index, total_subphases - progress within current phase
210 typedef vogl_bool (*vogl_progress_callback_func)(vogl_uint32 phase_index, vogl_uint32 total_phases, vogl_uint32 subphase_index, vogl_uint32 total_subphases, void* pUser_data_ptr);
212 // CRN/DDS compression parameters struct.
213 struct vogl_comp_params
215 inline vogl_comp_params() { clear(); }
217 // Clear struct to default parameters.
220 m_size_of_obj = sizeof(*this);
221 m_file_type = cCRNFileTypeCRN;
226 m_format = cCRNFmtDXT1;
227 m_flags = cCRNCompFlagPerceptual | cCRNCompFlagHierarchical | cCRNCompFlagUseBothBlockTypes;
229 for (vogl_uint32 f = 0; f < cCRNMaxFaces; f++)
230 for (vogl_uint32 l = 0; l < cCRNMaxLevels; l++)
231 m_pImages[f][l] = NULL;
233 m_target_bitrate = 0.0f;
234 m_quality_level = cCRNMaxQualityLevel;
235 m_dxt1a_alpha_threshold = 128;
236 m_dxt_quality = cCRNDXTQualityUber;
237 m_dxt_compressor_type = cCRNDXTCompressorCRN;
238 m_alpha_component = 3;
240 m_vogl_adaptive_tile_color_psnr_derating = 2.0f;
241 m_vogl_adaptive_tile_alpha_psnr_derating = 2.0f;
242 m_vogl_color_endpoint_palette_size = 0;
243 m_vogl_color_selector_palette_size = 0;
244 m_vogl_alpha_endpoint_palette_size = 0;
245 m_vogl_alpha_selector_palette_size = 0;
247 m_num_helper_threads = 0;
250 m_pProgress_func = NULL;
251 m_pProgress_func_data = NULL;
254 inline bool operator== (const vogl_comp_params& rhs) const
256 #define VOGL_COMP(x) do { if ((x) != (rhs.x)) return false; } while(0)
257 VOGL_COMP(m_size_of_obj);
258 VOGL_COMP(m_file_type);
265 VOGL_COMP(m_target_bitrate);
266 VOGL_COMP(m_quality_level);
267 VOGL_COMP(m_dxt1a_alpha_threshold);
268 VOGL_COMP(m_dxt_quality);
269 VOGL_COMP(m_dxt_compressor_type);
270 VOGL_COMP(m_alpha_component);
271 VOGL_COMP(m_vogl_adaptive_tile_color_psnr_derating);
272 VOGL_COMP(m_vogl_adaptive_tile_alpha_psnr_derating);
273 VOGL_COMP(m_vogl_color_endpoint_palette_size);
274 VOGL_COMP(m_vogl_color_selector_palette_size);
275 VOGL_COMP(m_vogl_alpha_endpoint_palette_size);
276 VOGL_COMP(m_vogl_alpha_selector_palette_size);
277 VOGL_COMP(m_num_helper_threads);
278 VOGL_COMP(m_userdata0);
279 VOGL_COMP(m_userdata1);
280 VOGL_COMP(m_pProgress_func);
281 VOGL_COMP(m_pProgress_func_data);
283 for (vogl_uint32 f = 0; f < cCRNMaxFaces; f++)
284 for (vogl_uint32 l = 0; l < cCRNMaxLevels; l++)
285 VOGL_COMP(m_pImages[f][l]);
291 // Returns true if the input parameters are reasonable.
292 inline bool check() const
294 if ( (m_file_type > cCRNFileTypeDDS) ||
295 (((int)m_quality_level < (int)cCRNMinQualityLevel) || ((int)m_quality_level > (int)cCRNMaxQualityLevel)) ||
296 (m_dxt1a_alpha_threshold > 255) ||
297 ((m_faces != 1) && (m_faces != 6)) ||
298 ((m_width < 1) || (m_width > cCRNMaxLevelResolution)) ||
299 ((m_height < 1) || (m_height > cCRNMaxLevelResolution)) ||
300 ((m_levels < 1) || (m_levels > cCRNMaxLevels)) ||
301 ((m_format < cCRNFmtDXT1) || (m_format >= cCRNFmtTotal)) ||
302 ((m_vogl_color_endpoint_palette_size) && ((m_vogl_color_endpoint_palette_size < cCRNMinPaletteSize) || (m_vogl_color_endpoint_palette_size > cCRNMaxPaletteSize))) ||
303 ((m_vogl_color_selector_palette_size) && ((m_vogl_color_selector_palette_size < cCRNMinPaletteSize) || (m_vogl_color_selector_palette_size > cCRNMaxPaletteSize))) ||
304 ((m_vogl_alpha_endpoint_palette_size) && ((m_vogl_alpha_endpoint_palette_size < cCRNMinPaletteSize) || (m_vogl_alpha_endpoint_palette_size > cCRNMaxPaletteSize))) ||
305 ((m_vogl_alpha_selector_palette_size) && ((m_vogl_alpha_selector_palette_size < cCRNMinPaletteSize) || (m_vogl_alpha_selector_palette_size > cCRNMaxPaletteSize))) ||
306 (m_alpha_component > 3) ||
307 (m_num_helper_threads > cCRNMaxHelperThreads) ||
308 (m_dxt_quality > cCRNDXTQualityUber) ||
309 (m_dxt_compressor_type >= cCRNTotalDXTCompressors) )
316 // Helper to set/get flags from m_flags member.
317 inline bool get_flag(vogl_comp_flags flag) const { return (m_flags & flag) != 0; }
318 inline void set_flag(vogl_comp_flags flag, bool val) { m_flags &= ~flag; if (val) m_flags |= flag; }
320 vogl_uint32 m_size_of_obj;
322 vogl_file_type m_file_type; // Output file type: cCRNFileTypeCRN or cCRNFileTypeDDS.
324 vogl_uint32 m_faces; // 1 (2D map) or 6 (cubemap)
325 vogl_uint32 m_width; // [1,cCRNMaxLevelResolution], non-power of 2 OK, non-square OK
326 vogl_uint32 m_height; // [1,cCRNMaxLevelResolution], non-power of 2 OK, non-square OK
327 vogl_uint32 m_levels; // [1,cCRNMaxLevelResolution], non-power of 2 OK, non-square OK
329 vogl_format m_format; // Output pixel format.
331 vogl_uint32 m_flags; // see vogl_comp_flags enum
333 // Array of pointers to 32bpp input images.
334 const vogl_uint32* m_pImages[cCRNMaxFaces][cCRNMaxLevels];
336 // Target bitrate - if non-zero, the compressor will use an interpolative search to find the
337 // highest quality level that is <= the target bitrate. If it fails to find a bitrate high enough, it'll
338 // try disabling adaptive block sizes (cCRNCompFlagHierarchical flag) and redo the search. This process can be pretty slow.
339 float m_target_bitrate;
341 // Desired quality level.
342 // Currently, CRN and DDS quality levels are not compatible with eachother from an image quality standpoint.
343 vogl_uint32 m_quality_level; // [cCRNMinQualityLevel, cCRNMaxQualityLevel]
345 // DXTn compression parameters.
346 vogl_uint32 m_dxt1a_alpha_threshold;
347 vogl_dxt_quality m_dxt_quality;
348 vogl_dxt_compressor_type m_dxt_compressor_type;
350 // Alpha channel's component. Defaults to 3.
351 vogl_uint32 m_alpha_component;
353 // Various low-level CRN specific parameters.
354 float m_vogl_adaptive_tile_color_psnr_derating;
355 float m_vogl_adaptive_tile_alpha_psnr_derating;
357 vogl_uint32 m_vogl_color_endpoint_palette_size; // [cCRNMinPaletteSize,cCRNMaxPaletteSize]
358 vogl_uint32 m_vogl_color_selector_palette_size; // [cCRNMinPaletteSize,cCRNMaxPaletteSize]
360 vogl_uint32 m_vogl_alpha_endpoint_palette_size; // [cCRNMinPaletteSize,cCRNMaxPaletteSize]
361 vogl_uint32 m_vogl_alpha_selector_palette_size; // [cCRNMinPaletteSize,cCRNMaxPaletteSize]
363 // Number of helper threads to create during compression. 0=no threading.
364 vogl_uint32 m_num_helper_threads;
366 // CRN userdata0 and userdata1 members, which are written directly to the header of the output file.
367 vogl_uint32 m_userdata0;
368 vogl_uint32 m_userdata1;
370 // User provided progress callback.
371 vogl_progress_callback_func m_pProgress_func;
372 void* m_pProgress_func_data;
375 // Mipmap generator's mode.
378 cCRNMipModeUseSourceOrGenerateMips, // Use source texture's mipmaps if it has any, otherwise generate new mipmaps
379 cCRNMipModeUseSourceMips, // Use source texture's mipmaps if it has any, otherwise the output has no mipmaps
380 cCRNMipModeGenerateMips, // Always generate new mipmaps
381 cCRNMipModeNoMips, // Output texture has no mipmaps
385 cCRNModeForceDWORD = 0xFFFFFFFF
388 const char* vogl_get_mip_mode_desc(vogl_mip_mode m);
389 const char* vogl_get_mip_mode_name(vogl_mip_mode m);
391 // Mipmap generator's filter kernel.
396 cCRNMipFilterLanczos4,
397 cCRNMipFilterMitchell,
398 cCRNMipFilterKaiser, // Kaiser=default mipmap filter
402 cCRNMipFilterForceDWORD = 0xFFFFFFFF
405 const char* vogl_get_mip_filter_name(vogl_mip_filter f);
407 // Mipmap generator's scale mode.
419 cCRNSMForceDWORD = 0xFFFFFFFF
422 const char* vogl_get_scale_mode_desc(vogl_scale_mode sm);
424 // Mipmap generator parameters.
425 struct vogl_mipmap_params
427 inline vogl_mipmap_params() { clear(); }
431 m_size_of_obj = sizeof(*this);
432 m_mode = cCRNMipModeUseSourceOrGenerateMips;
433 m_filter = cCRNMipFilterKaiser;
434 m_gamma_filtering = true;
436 // Default "blurriness" factor of .9 actually sharpens the output a little.
438 m_renormalize = false;
440 m_max_levels = cCRNMaxLevels;
443 m_scale_mode = cCRNSMDisabled;
452 m_clamp_scale = false;
457 inline bool check() const { return true; }
459 inline bool operator== (const vogl_mipmap_params& rhs) const
461 #define VOGL_COMP(x) do { if ((x) != (rhs.x)) return false; } while(0)
462 VOGL_COMP(m_size_of_obj);
465 VOGL_COMP(m_gamma_filtering);
467 VOGL_COMP(m_blurriness);
468 VOGL_COMP(m_renormalize);
470 VOGL_COMP(m_max_levels);
471 VOGL_COMP(m_min_mip_size);
472 VOGL_COMP(m_scale_mode);
473 VOGL_COMP(m_scale_x);
474 VOGL_COMP(m_scale_y);
475 VOGL_COMP(m_window_left);
476 VOGL_COMP(m_window_top);
477 VOGL_COMP(m_window_right);
478 VOGL_COMP(m_window_bottom);
479 VOGL_COMP(m_clamp_scale);
480 VOGL_COMP(m_clamp_width);
481 VOGL_COMP(m_clamp_height);
485 vogl_uint32 m_size_of_obj;
487 vogl_mip_mode m_mode;
488 vogl_mip_filter m_filter;
490 vogl_bool m_gamma_filtering;
495 vogl_uint32 m_max_levels;
496 vogl_uint32 m_min_mip_size;
498 vogl_bool m_renormalize;
501 vogl_scale_mode m_scale_mode;
505 vogl_uint32 m_window_left;
506 vogl_uint32 m_window_top;
507 vogl_uint32 m_window_right;
508 vogl_uint32 m_window_bottom;
510 vogl_bool m_clamp_scale;
511 vogl_uint32 m_clamp_width;
512 vogl_uint32 m_clamp_height;
515 // -------- High-level helper function definitions for CDN/DDS compression.
517 #ifndef VOGL_MIN_ALLOC_ALIGNMENT
518 #define VOGL_MIN_ALLOC_ALIGNMENT sizeof(size_t) * 2
521 // -------- String helpers.
523 // Converts a vogl_file_type to a string.
524 const char* vogl_get_file_type_ext(vogl_file_type file_type);
526 // Converts a vogl_format to a string.
527 const char* vogl_get_format_string(vogl_format fmt);