1 /* Copyright (C) 2010 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 * support routines and interface for texture codecs. 25 */ 26 27 #ifndef INCLUDED_TEX_CODEC 28 #define INCLUDED_TEX_CODEC 29 30 #include "tex.h" 31 #include "tex_internal.h" // for codec's convenience 32 33 /** 34 * virtual method table for TexCodecs. 35 * rationale: this works in C and also allows storing name and next in vtbl. 36 * 'template method'-style interface to increase code reuse and 37 * simplify writing new codecs. 38 **/ 39 class ITexCodec 40 { 41 public: 42 /** 43 * decode the file into a Tex structure. 44 * 45 * @param data input data array (non-const, because the texture 46 * may have to be flipped in-place - see "texture orientation"). 47 * @param size [bytes] of data, always >= 4 48 * (this is usually enough to compare the header's "magic" field, 49 * and no legitimate file will be smaller) 50 * @param t output texture object 51 * @return Status 52 **/ 53 virtual Status decode(u8* data, size_t size, Tex* RESTRICT t) const = 0; 54 55 /** 56 * encode the texture data into the codec's file format (in memory). 57 * 58 * @param t input texture object. note: non-const because encoding may 59 * require a Tex::transform. 60 * @param da output data array, allocated by codec. 61 * rationale: some codecs cannot calculate the output size beforehand 62 * (e.g. PNG output via libpng), so the output memory cannot be allocated 63 * by the caller. 64 * @return Status 65 **/ 66 virtual Status encode(Tex* RESTRICT t, DynArray* RESTRICT da) const = 0; 67 68 /** 69 * transform the texture's pixel format. 70 * 71 * @param t texture object 72 * @param transforms: OR-ed combination of TEX_* flags that are to 73 * be changed. note: the codec needs only handle situations specific 74 * to its format; generic pixel format transforms are handled by 75 * the caller. 76 **/ 77 virtual Status transform(Tex* t, size_t transforms) const = 0; 78 79 /** 80 * indicate if the data appears to be an instance of this codec's header, 81 * i.e. can this codec decode it? 82 * 83 * @param file input data; only guaranteed to be 4 bytes! 84 * (this should be enough to examine the header's 'magic' field) 85 * @return bool 86 **/ 87 virtual bool is_hdr(const u8* file) const = 0; 88 89 /** 90 * is the extension that of a file format supported by this codec? 91 * 92 * rationale: cannot just return the extension string and have 93 * caller compare it (-> smaller code) because a codec's file format 94 * may have several valid extensions (e.g. jpg and jpeg). 95 * 96 * @param extension (including '.') 97 * @return bool 98 **/ 99 virtual bool is_ext(const OsPath& extension) const = 0; 100 101 /** 102 * return size of the file header supported by this codec. 103 * 104 * @param file the specific header to return length of (taking its 105 * variable-length fields into account). if NULL, return minimum 106 * guaranteed header size, i.e. the header without any 107 * variable-length fields. 108 * @return size [bytes] 109 **/ 110 virtual size_t hdr_size(const u8* file) const = 0; 111 112 /** 113 * name of codec for debug purposes. typically set via TEX_CODEC_REGISTER. 114 **/ 115 virtual const wchar_t* get_name() const = 0; 116 ~ITexCodec()117 virtual ~ITexCodec() {} 118 }; 119 120 class TexCodecPng:ITexCodec { 121 public: 122 virtual Status decode(u8* data, size_t size, Tex* RESTRICT t) const; 123 virtual Status encode(Tex* RESTRICT t, DynArray* RESTRICT da) const; 124 virtual Status transform(Tex* t, size_t transforms) const; 125 virtual bool is_hdr(const u8* file) const; 126 virtual bool is_ext(const OsPath& extension) const; 127 virtual size_t hdr_size(const u8* file) const; get_name()128 virtual const wchar_t* get_name() const { 129 static const wchar_t *name = L"png"; 130 return name; 131 }; 132 }; 133 134 class TexCodecDds:ITexCodec { 135 public: 136 virtual Status decode(u8* data, size_t size, Tex* RESTRICT t) const; 137 virtual Status encode(Tex* RESTRICT t, DynArray* RESTRICT da) const; 138 virtual Status transform(Tex* t, size_t transforms) const; 139 virtual bool is_hdr(const u8* file) const; 140 virtual bool is_ext(const OsPath& extension) const; 141 virtual size_t hdr_size(const u8* file) const; get_name()142 virtual const wchar_t* get_name() const { 143 static const wchar_t *name = L"dds"; 144 return name; 145 }; 146 }; 147 148 class TexCodecTga:ITexCodec { 149 public: 150 virtual Status decode(u8* data, size_t size, Tex* RESTRICT t) const; 151 virtual Status encode(Tex* RESTRICT t, DynArray* RESTRICT da) const; 152 virtual Status transform(Tex* t, size_t transforms) const; 153 virtual bool is_hdr(const u8* file) const; 154 virtual bool is_ext(const OsPath& extension) const; 155 virtual size_t hdr_size(const u8* file) const; get_name()156 virtual const wchar_t* get_name() const { 157 static const wchar_t *name = L"tga"; 158 return name; 159 }; 160 }; 161 162 class TexCodecBmp:ITexCodec { 163 public: 164 virtual Status decode(u8* data, size_t size, Tex* RESTRICT t) const; 165 virtual Status encode(Tex* RESTRICT t, DynArray* RESTRICT da) const; 166 virtual Status transform(Tex* t, size_t transforms) const; 167 virtual bool is_hdr(const u8* file) const; 168 virtual bool is_ext(const OsPath& extension) const; 169 virtual size_t hdr_size(const u8* file) const; get_name()170 virtual const wchar_t* get_name() const { 171 static const wchar_t *name = L"bmp"; 172 return name; 173 }; 174 }; 175 176 /** 177 * Find codec that recognizes the desired output file extension. 178 * 179 * @param extension 180 * @param c (out) vtbl of responsible codec 181 * @return Status; ERR::RES_UNKNOWN_FORMAT (without warning, because this is 182 * called by tex_is_known_extension) if no codec indicates they can 183 * handle the given extension. 184 **/ 185 extern Status tex_codec_for_filename(const OsPath& extension, const ITexCodec** c); 186 187 /** 188 * find codec that recognizes the header's magic field. 189 * 190 * @param data typically contents of file, but need only include the 191 * (first 4 bytes of) header. 192 * @param data_size [bytes] 193 * @param c (out) vtbl of responsible codec 194 * @return Status; ERR::RES_UNKNOWN_FORMAT if no codec indicates they can 195 * handle the given format (header). 196 **/ 197 extern Status tex_codec_for_header(const u8* data, size_t data_size, const ITexCodec** c); 198 199 /** 200 * transform the texture's pixel format. 201 * tries each codec's transform method once, or until one indicates success. 202 * 203 * @param t texture object 204 * @param transforms: OR-ed combination of TEX_* flags that are to 205 * be changed. 206 * @return Status 207 **/ 208 extern Status tex_codec_transform(Tex* t, size_t transforms); 209 210 /** 211 * allocate an array of row pointers that point into the given texture data. 212 * for texture decoders that support output via row pointers (e.g. PNG), 213 * this allows flipping the image vertically (useful when matching bottom-up 214 * textures to a global orientation) directly, which is much more 215 * efficient than transforming later via copying all pixels. 216 * 217 * @param data the texture data into which row pointers will point. 218 * note: we don't allocate it here because this function is 219 * needed for encoding, too (where data is already present). 220 * @param h height [pixels] of texture. 221 * @param pitch size [bytes] of one texture row, i.e. width*bytes_per_pixel. 222 * @param src_flags TexFlags of source texture. used to extract its 223 * orientation. 224 * @param dst_orientation desired orientation of the output data. 225 * can be one of TEX_BOTTOM_UP, TEX_TOP_DOWN, or 0 for the 226 * "global orientation". 227 * depending on src and dst, the row array is flipped if necessary. 228 **/ 229 typedef const u8* RowPtr; 230 extern std::vector<RowPtr> tex_codec_alloc_rows(const u8* data, size_t h, size_t pitch, size_t src_flags, size_t dst_orientation); 231 232 /** 233 * apply transforms and then copy header and image into output buffer. 234 * 235 * @param t input texture object 236 * @param transforms transformations to be applied to pixel format 237 * @param hdr header data 238 * @param hdr_size [bytes] 239 * @param da output data array (will be expanded as necessary) 240 * @return Status 241 **/ 242 extern Status tex_codec_write(Tex* t, size_t transforms, const void* hdr, size_t hdr_size, DynArray* da); 243 244 #endif // #ifndef INCLUDED_TEX_CODEC 245