Pyrogenesis  trunk
tex.h
Go to the documentation of this file.
1 /* Copyright (c) 2014 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * read/write 2d texture files; allows conversion between pixel formats
25  * and automatic orientation correction.
26  */
27 
28 /**
29 
30 Introduction
31 ------------
32 
33 This module allows reading/writing 2d images in various file formats and
34 encapsulates them in Tex objects.
35 It supports converting between pixel formats; this is to an extent done
36 automatically when reading/writing. Provision is also made for flipping
37 all images to a default orientation.
38 
39 
40 Format Conversion
41 -----------------
42 
43 Image file formats have major differences in their native pixel format:
44 some store in BGR order, or have rows arranged bottom-up.
45 We must balance runtime cost/complexity and convenience for the
46 application (not dumping the entire problem on its lap).
47 That means rejecting really obscure formats (e.g. right-to-left pixels),
48 but converting everything else to uncompressed RGB "plain" format
49 except where noted in enum TexFlags (1).
50 
51 Note: conversion is implemented as a pipeline: e.g. "DDS decompress +
52 vertical flip" would be done by decompressing to RGB (DDS codec) and then
53 flipping (generic transform). This is in contrast to all<->all
54 conversion paths: that would be much more complex, if more efficient.
55 
56 Since any kind of preprocessing at runtime is undesirable (the absolute
57 priority is minimizing load time), prefer file formats that are
58 close to the final pixel format.
59 
60 1) one of the exceptions is S3TC compressed textures. glCompressedTexImage2D
61  requires these be passed in their original format; decompressing would be
62  counterproductive. In this and similar cases, TexFlags indicates such
63  deviations from the plain format.
64 
65 
66 Default Orientation
67 -------------------
68 
69 After loading, all images (except DDS, because its orientation is
70 indeterminate) are automatically converted to the global row
71 orientation: top-down or bottom-up, as specified by
72 tex_set_global_orientation. If that isn't called, the default is top-down
73 to match Photoshop's DDS output (since this is meant to be the
74 no-preprocessing-required optimized format).
75 Reasons to change it might be to speed up loading bottom-up
76 BMP or TGA images, or to match OpenGL's convention for convenience;
77 however, be aware of the abovementioned issues with DDS.
78 
79 Rationale: it is not expected that this will happen at the renderer layer
80 (a 'flip all texcoords' flag is too much trouble), so the
81 application would have to do the same anyway. By taking care of it here,
82 we unburden the app and save time, since some codecs (e.g. PNG) can
83 flip for free when loading.
84 
85 
86 Codecs / IO Implementation
87 --------------------------
88 
89 To ease adding support for new formats, they are organized as codecs.
90 The interface aims to minimize code duplication, so it's organized
91 following the principle of "Template Method" - this module both
92 calls into codecs, and provides helper functions that they use.
93 
94 IO is done via VFS, but the codecs are decoupled from this and
95 work with memory buffers. Access to them is endian-safe.
96 
97 When "writing", the image is put into an expandable memory region.
98 This supports external libraries like libpng that do not know the
99 output size beforehand, but avoids the need for a buffer between
100 library and IO layer. Read and write are zero-copy.
101 
102 **/
103 
104 #ifndef INCLUDED_TEX
105 #define INCLUDED_TEX
106 
107 #include "lib/res/handle.h"
108 #include "lib/os_path.h"
109 #include "lib/file/vfs/vfs_path.h"
110 #include "lib/allocators/dynarray.h"
111 
112 
113 namespace ERR
114 {
115  const Status TEX_UNKNOWN_FORMAT = -120100;
116  const Status TEX_INCOMPLETE_HEADER = -120101;
117  const Status TEX_FMT_INVALID = -120102;
120  const Status TEX_INVALID_LAYOUT = -120105;
121  const Status TEX_COMPRESSED = -120106;
122  const Status TEX_INVALID_SIZE = -120107;
123 }
124 
125 namespace WARN
126 {
127  const Status TEX_INVALID_DATA = +120108;
128 }
129 
130 namespace INFO
131 {
133 }
134 
135 
136 /**
137  * flags describing the pixel format. these are to be interpreted as
138  * deviations from "plain" format, i.e. uncompressed RGB.
139  **/
141 {
142  /**
143  * flags & TEX_DXT is a field indicating compression.
144  * if 0, the texture is uncompressed;
145  * otherwise, it holds the S3TC type: 1,3,5 or DXT1A.
146  * not converted by default - glCompressedTexImage2D receives
147  * the compressed data.
148  **/
149  TEX_DXT = 0x7, // mask
150 
151  /**
152  * we need a special value for DXT1a to avoid having to consider
153  * flags & TEX_ALPHA to determine S3TC type.
154  * the value is arbitrary; do not rely on it!
155  **/
156  DXT1A = 7,
157 
158  /**
159  * indicates B and R pixel components are exchanged. depending on
160  * flags & TEX_ALPHA or bpp, this means either BGR or BGRA.
161  * not converted by default - it's an acceptable format for OpenGL.
162  **/
163  TEX_BGR = 0x08,
164 
165  /**
166  * indicates the image contains an alpha channel. this is set for
167  * your convenience - there are many formats containing alpha and
168  * divining this information from them is hard.
169  * (conversion is not applicable here)
170  **/
171  TEX_ALPHA = 0x10,
172 
173  /**
174  * indicates the image is 8bpp greyscale. this is required to
175  * differentiate between alpha-only and intensity formats.
176  * not converted by default - it's an acceptable format for OpenGL.
177  **/
178  TEX_GREY = 0x20,
179 
180  /**
181  * flags & TEX_ORIENTATION is a field indicating orientation,
182  * i.e. in what order the pixel rows are stored.
183  *
184  * tex_load always sets this to the global orientation
185  * (and flips the image accordingly to match).
186  * texture codecs may in intermediate steps during loading set this
187  * to 0 if they don't know which way around they are (e.g. DDS),
188  * or to whatever their file contains.
189  **/
191  TEX_TOP_DOWN = 0x80,
193 
194  /**
195  * indicates the image data includes mipmaps. they are stored from lowest
196  * to highest (1x1), one after the other.
197  * (conversion is not applicable here)
198  **/
199  TEX_MIPMAPS = 0x100,
200 
202 };
203 
204 /**
205  * stores all data describing an image.
206  * we try to minimize size, since this is stored in OglTex resources
207  * (which are big and pushing the h_mgr limit).
208  **/
209 struct Tex
210 {
211  /**
212  * file buffer or image data. note: during the course of transforms
213  * (which may occur when being loaded), this may be replaced with
214  * a new buffer (e.g. if decompressing file contents).
215  **/
216  shared_ptr<u8> m_Data;
217 
218  size_t m_DataSize;
219 
220  /**
221  * offset to image data in file. this is required since
222  * tex_get_data needs to return the pixels, but data
223  * returns the actual file buffer. zero-copy load and
224  * write-back to file is also made possible.
225  **/
226  size_t m_Ofs;
227 
228  size_t m_Width;
229  size_t m_Height;
230  size_t m_Bpp;
231 
232  /// see TexFlags and "Format Conversion" in docs.
233  size_t m_Flags;
234 
236  {
237  free();
238  }
239 
240  /**
241  * Is the texture object valid and self-consistent?
242  *
243  * @return Status
244  **/
245  Status validate() const;
246 
247  /**
248  * free all resources associated with the image and make further
249  * use of it impossible.
250  *
251  * @return Status
252  **/
253  void free();
254 
255  /**
256  * decode an in-memory texture file into texture object.
257  *
258  * FYI, currently BMP, TGA, JPG, JP2, PNG, DDS are supported - but don't
259  * rely on this (not all codecs may be included).
260  *
261  * @param data Input data.
262  * @param data_size Its size [bytes].
263  * @return Status.
264  **/
265  Status decode(const shared_ptr<u8>& data, size_t data_size);
266 
267  /**
268  * encode a texture into a memory buffer in the desired file format.
269  *
270  * @param extension (including '.').
271  * @param da Output memory array. Allocated here; caller must free it
272  * when no longer needed. Invalid unless function succeeds.
273  * @return Status
274  **/
275  Status encode(const OsPath& extension, DynArray* da);
276 
277  /**
278  * store the given image data into a Tex object; this will be as if
279  * it had been loaded via tex_load.
280  *
281  * rationale: support for in-memory images is necessary for
282  * emulation of glCompressedTexImage2D and useful overall.
283  * however, we don't want to provide an alternate interface for each API;
284  * these would have to be changed whenever fields are added to Tex.
285  * instead, provide one entry point for specifying images.
286  * note: since we do not know how <img> was allocated, the caller must free
287  * it themselves (after calling tex_free, which is required regardless of
288  * alloc type).
289  *
290  * we need only add bookkeeping information and "wrap" it in
291  * our Tex struct, hence the name.
292  *
293  * @param w,h Pixel dimensions.
294  * @param bpp Bits per pixel.
295  * @param flags TexFlags.
296  * @param data Img texture data. note: size is calculated from other params.
297  * @param ofs
298  * @return Status
299  **/
300  Status wrap(size_t w, size_t h, size_t bpp, size_t flags, const shared_ptr<u8>& data, size_t ofs);
301 
302  //
303  // modify image
304  //
305 
306  /**
307  * Change the pixel format.
308  *
309  * @param transforms TexFlags that are to be flipped.
310  * @return Status
311  **/
312  Status transform(size_t transforms);
313 
314  /**
315  * Change the pixel format (2nd version)
316  * (note: this is equivalent to Tex::transform(t, t->flags^new_flags).
317  *
318  * @param new_flags desired new value of TexFlags.
319  * @return Status
320  **/
321  Status transform_to(size_t new_flags);
322 
323  //
324  // return image information
325  //
326 
327  /**
328  * return a pointer to the image data (pixels), taking into account any
329  * header(s) that may come before it.
330  *
331  * @return pointer to data returned by mem_get_ptr (holds reference)!
332  **/
333  u8* get_data();
334 
335  /**
336  * return the ARGB value of the 1x1 mipmap level of the texture.
337  *
338  * @return ARGB value (or 0 if texture does not have mipmaps)
339  **/
340  u32 get_average_color() const;
341 
342  /**
343  * return total byte size of the image pixels. (including mipmaps!)
344  * rationale: this is preferable to calculating manually because it's
345  * less error-prone (e.g. confusing bits_per_pixel with bytes).
346  *
347  * @return size [bytes]
348  **/
349  size_t img_size() const;
350 
351 };
352 
353 
354 /**
355  * Set the orientation to which all loaded images will
356  * automatically be converted (excepting file formats that don't specify
357  * their orientation, i.e. DDS). See "Default Orientation" in docs.
358  * @param orientation Either TEX_BOTTOM_UP or TEX_TOP_DOWN.
359  **/
360 extern void tex_set_global_orientation(int orientation);
361 
362 
363 /**
364  * special value for levels_to_skip: the callback will only be called
365  * for the base mipmap level (i.e. 100%)
366  **/
367 const int TEX_BASE_LEVEL_ONLY = -1;
368 
369 /**
370  * callback function for each mipmap level.
371  *
372  * @param level number; 0 for base level (i.e. 100%), or the first one
373  * in case some were skipped.
374  * @param level_w, level_h pixel dimensions (powers of 2, never 0)
375  * @param level_data the level's texels
376  * @param level_data_size [bytes]
377  * @param cbData passed through from tex_util_foreach_mipmap.
378  **/
379 typedef void (*MipmapCB)(size_t level, size_t level_w, size_t level_h, const u8* RESTRICT level_data, size_t level_data_size, void* RESTRICT cbData);
380 
381 /**
382  * for a series of mipmaps stored from base to highest, call back for
383  * each level.
384  *
385  * @param w,h Pixel dimensions.
386  * @param bpp Bits per pixel.
387  * @param data Series of mipmaps.
388  * @param levels_to_skip Number of levels (counting from base) to skip, or
389  * TEX_BASE_LEVEL_ONLY to only call back for the base image.
390  * Rationale: this avoids needing to special case for images with or
391  * without mipmaps.
392  * @param data_padding Minimum pixel dimensions of mipmap levels.
393  * This is used in S3TC images, where each level is actually stored in
394  * 4x4 blocks. usually 1 to indicate levels are consecutive.
395  * @param cb MipmapCB to call.
396  * @param cbData Extra data to pass to cb.
397  **/
398 extern void tex_util_foreach_mipmap(size_t w, size_t h, size_t bpp, const u8* data, int levels_to_skip, size_t data_padding, MipmapCB cb, void* RESTRICT cbData);
399 
400 
401 //
402 // image writing
403 //
404 
405 /**
406  * Is the file's extension that of a texture format supported by tex_load?
407  *
408  * Rationale: tex_load complains if the given file is of an
409  * unsupported type. this API allows users to preempt that warning
410  * (by checking the filename themselves), and also provides for e.g.
411  * enumerating only images in a file picker.
412  * an alternative might be a flag to suppress warning about invalid files,
413  * but this is open to misuse.
414  *
415  * @param pathname Only the extension (starting with '.') is used. case-insensitive.
416  * @return bool
417  **/
418 extern bool tex_is_known_extension(const VfsPath& pathname);
419 
420 /**
421  * return the minimum header size (i.e. offset to pixel data) of the
422  * file format corresponding to the filename.
423  *
424  * rationale: this can be used to optimize calls to tex_write: when
425  * allocating the buffer that will hold the image, allocate this much
426  * extra and pass the pointer as base+hdr_size. this allows writing the
427  * header directly into the output buffer and makes for zero-copy IO.
428  *
429  * @param filename Filename; only the extension (that after '.') is used.
430  * case-insensitive.
431  * @return size [bytes] or 0 on error (i.e. no codec found).
432  **/
433 extern size_t tex_hdr_size(const VfsPath& filename);
434 
435 #endif // INCLUDED_TEX
const Status TEX_INVALID_COLOR_TYPE
Definition: tex.h:118
size_t m_Width
Definition: tex.h:228
void tex_set_global_orientation(int orientation)
Set the orientation to which all loaded images will automatically be converted (excepting file format...
Definition: tex.cpp:513
const Status TEX_CODEC_CANNOT_HANDLE
Definition: tex.h:132
const int TEX_BASE_LEVEL_ONLY
special value for levels_to_skip: the callback will only be called for the base mipmap level (i...
Definition: tex.h:367
const Status TEX_COMPRESSED
Definition: tex.h:121
size_t m_Flags
see TexFlags and "Format Conversion" in docs.
Definition: tex.h:233
flags & TEX_DXT is a field indicating compression.
Definition: tex.h:149
mask
Definition: tex.h:199
indicates the image contains an alpha channel.
Definition: tex.h:171
Definition: tex.h:125
provides a memory range that can be expanded but doesn&#39;t waste physical memory or relocate itself...
Definition: dynarray.h:39
const Status TEX_INCOMPLETE_HEADER
Definition: tex.h:116
indicates the image is 8bpp greyscale.
Definition: tex.h:178
indicates B and R pixel components are exchanged.
Definition: tex.h:163
uint8_t u8
Definition: types.h:37
flags & TEX_ORIENTATION is a field indicating orientation, i.e.
Definition: tex.h:190
Definition: debug.h:420
Definition: tex.h:191
size_t m_Ofs
offset to image data in file.
Definition: tex.h:226
const Status TEX_FMT_INVALID
Definition: tex.h:117
uint32_t u32
Definition: types.h:39
Definition: path.h:77
const Status TEX_NOT_8BIT_PRECISION
Definition: tex.h:119
Definition: tex.h:192
shared_ptr< u8 > m_Data
file buffer or image data.
Definition: tex.h:216
void tex_util_foreach_mipmap(size_t w, size_t h, size_t bpp, const u8 *data, int levels_to_skip, size_t data_padding, MipmapCB cb, void *RESTRICT cbData)
for a series of mipmaps stored from base to highest, call back for each level.
Definition: tex.cpp:132
size_t m_DataSize
Definition: tex.h:218
size_t tex_hdr_size(const VfsPath &filename)
return the minimum header size (i.e.
Definition: tex.cpp:705
const Status TEX_UNKNOWN_FORMAT
Definition: tex.h:115
i64 Status
Error handling system.
Definition: status.h:171
stores all data describing an image.
Definition: tex.h:209
~Tex()
Definition: tex.h:235
Introduction
Definition: debug.h:404
we need a special value for DXT1a to avoid having to consider flags & TEX_ALPHA to determine S3TC typ...
Definition: tex.h:156
size_t m_Height
Definition: tex.h:229
const Status TEX_INVALID_DATA
Definition: tex.h:127
const char * extension
Definition: mongoose.cpp:1733
const Status TEX_INVALID_LAYOUT
Definition: tex.h:120
#define RESTRICT
Definition: code_annotation.h:320
void(* MipmapCB)(size_t level, size_t level_w, size_t level_h, const u8 *RESTRICT level_data, size_t level_data_size, void *RESTRICT cbData)
callback function for each mipmap level.
Definition: tex.h:379
bool tex_is_known_extension(const VfsPath &pathname)
Is the file&#39;s extension that of a texture format supported by tex_load?
Definition: tex.cpp:570
size_t m_Bpp
Definition: tex.h:230
const Status TEX_INVALID_SIZE
Definition: tex.h:122
Definition: tex.h:201
TexFlags
flags describing the pixel format.
Definition: tex.h:140