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