1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "BsCorePrerequisites.h" |
6 | #include "Image/BsPixelData.h" |
7 | |
8 | namespace bs |
9 | { |
10 | // Undefine conflicting defines from other libs |
11 | #undef None |
12 | |
13 | /** @addtogroup Utility-Core |
14 | * @{ |
15 | */ |
16 | |
17 | /** Types of texture compression quality. */ |
18 | enum class CompressionQuality |
19 | { |
20 | Fastest, |
21 | Normal, |
22 | Production, |
23 | Highest |
24 | }; |
25 | |
26 | /** Mode of the alpha channel in a texture. */ |
27 | enum class AlphaMode |
28 | { |
29 | None, /*< Texture has no alpha values. */ |
30 | Transparency, /*< Alpha is in the separate transparency channel. */ |
31 | Premultiplied /*< Alpha values have been pre-multiplied with the color values. */ |
32 | }; |
33 | |
34 | /** Wrap mode to use when generating mip maps. */ |
35 | enum class MipMapWrapMode |
36 | { |
37 | Mirror, |
38 | Repeat, |
39 | Clamp |
40 | }; |
41 | |
42 | /** Filter to use when generating mip maps. */ |
43 | enum class MipMapFilter |
44 | { |
45 | Box, |
46 | Triangle, |
47 | Kaiser |
48 | }; |
49 | |
50 | /** Determines on which axes to mirror an image. */ |
51 | enum class MirrorModeBits |
52 | { |
53 | X = 1 << 0, |
54 | Y = 1 << 1, |
55 | Z = 1 << 2 |
56 | }; |
57 | |
58 | typedef Flags<MirrorModeBits> MirrorMode; |
59 | BS_FLAGS_OPERATORS(MirrorModeBits); |
60 | |
61 | /** Options used to control texture compression. */ |
62 | struct CompressionOptions |
63 | { |
64 | PixelFormat format = PF_BC1; /*< Format to compress to. Must be a format containing compressed data. */ |
65 | AlphaMode alphaMode = AlphaMode::None; /*< Controls how to (and if) to compress the alpha channel. */ |
66 | bool isNormalMap = false; /*< Determines does the input data represent a normal map. */ |
67 | bool isSRGB = false; /*< Determines has the input data been gamma corrected. */ |
68 | CompressionQuality quality = CompressionQuality::Normal; /*< Compressed image quality. Better compression might take longer to execute but will generate better results. */ |
69 | }; |
70 | |
71 | /** Options used to control texture mip map generation. */ |
72 | struct MipMapGenOptions |
73 | { |
74 | MipMapFilter filter = MipMapFilter::Box; /*< Filter to use when downsamping input data. */ |
75 | MipMapWrapMode wrapMode = MipMapWrapMode::Mirror; /*< Determines how to downsample pixels on borders. */ |
76 | bool isNormalMap = false; /*< Determines does the input data represent a normal map. */ |
77 | bool normalizeMipmaps = false; /*< Should the downsampled values be re-normalized. Only relevant for mip-maps representing normal maps. */ |
78 | bool isSRGB = false; /*< Determines has the input data been gamma corrected. */ |
79 | }; |
80 | |
81 | /** Utility methods for converting and managing pixel data and formats. */ |
82 | class BS_CORE_EXPORT PixelUtil |
83 | { |
84 | public: |
85 | /** Filtering types to use when scaling images. */ |
86 | enum Filter |
87 | { |
88 | FILTER_NEAREST, /*< No filtering is performed and nearest existing value is used. */ |
89 | FILTER_LINEAR /*< Box filter is applied, averaging nearby pixels. */ |
90 | }; |
91 | |
92 | /** Returns the size of a single pixel of the provided pixel format, in bytes. */ |
93 | static UINT32 getNumElemBytes(PixelFormat format); |
94 | |
95 | /** Returns the size of a single pixel of the provided pixel format, in bits. */ |
96 | static UINT32 getNumElemBits(PixelFormat format); |
97 | |
98 | /** Returns the size of the memory region required to hold pixels of the provided size ana format. */ |
99 | static UINT32 getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format); |
100 | |
101 | /** Calculates the size of a mip level of a texture with the provided size. */ |
102 | static void getSizeForMipLevel(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevel, |
103 | UINT32& mipWidth, UINT32& mipHeight, UINT32& mipDepth); |
104 | |
105 | /** |
106 | * Calculates row and depth pitch for a texture surface of the specified size and format. For most this will be |
107 | * equal to their width & height, respectively. But some texture formats (especially compressed ones) might |
108 | * require extra padding. |
109 | */ |
110 | static void getPitch(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format, |
111 | UINT32& rowPitch, UINT32& depthPitch); |
112 | |
113 | /** |
114 | * Returns property flags for this pixel format. |
115 | * |
116 | * @see PixelFormatFlags |
117 | */ |
118 | static UINT32 getFlags(PixelFormat format); |
119 | |
120 | /** Checks if the provided pixel format has an alpha channel. */ |
121 | static bool hasAlpha(PixelFormat format); |
122 | |
123 | /** Checks is the provided pixel format a floating point format. */ |
124 | static bool isFloatingPoint(PixelFormat format); |
125 | |
126 | /** Checks is the provided pixel format compressed. */ |
127 | static bool isCompressed(PixelFormat format); |
128 | |
129 | /** Checks is the provided pixel format a depth/stencil buffer format. */ |
130 | static bool isDepth(PixelFormat format); |
131 | |
132 | /** Checks does the provided format store data in normalized range. */ |
133 | static bool isNormalized(PixelFormat format); |
134 | |
135 | /** |
136 | * Checks is the provided format valid for the texture type and usage. |
137 | * |
138 | * @param[in, out] format Format to check. If format is not valid the method will update this with the closest |
139 | * relevant format. |
140 | * @param[in] texType Type of the texture the format will be used for. |
141 | * @param[in] usage A set of TextureUsage flags that define how will a texture be used. |
142 | * @return True if the format is valid, false if not. |
143 | * |
144 | * @note This method checks only for obvious format mismatches: |
145 | * - Using depth format for anything but a depth-stencil buffer |
146 | * - Using anything but a depth format for a depth-stencil-buffer |
147 | * - Using compressed format for anything but normal textures |
148 | * - Using compressed format for 1D textures |
149 | * |
150 | * Caller should still check for platform-specific unsupported formats. |
151 | */ |
152 | static bool checkFormat(PixelFormat& format, TextureType texType, int usage); |
153 | |
154 | /** |
155 | * Checks are the provided dimensions valid for the specified pixel format. Some formats (like BC) require |
156 | * width/height to be multiples of four and some formats dont allow depth larger than 1. |
157 | */ |
158 | static bool isValidExtent(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format); |
159 | |
160 | /** |
161 | * Returns the number of bits per each element in the provided pixel format. This will return all zero for |
162 | * compressed and depth/stencil formats. |
163 | */ |
164 | static void getBitDepths(PixelFormat format, int(&rgba)[4]); |
165 | |
166 | /** |
167 | * Returns bit masks that determine in what bit range is each channel stored. |
168 | * |
169 | * @note |
170 | * For example if your color is stored in an UINT32 and you want to extract the red channel you should AND the color |
171 | * UINT32 with the bit-mask for the red channel and then right shift it by the red channel bit shift amount. |
172 | */ |
173 | static void getBitMasks(PixelFormat format, UINT32(&rgba)[4]); |
174 | |
175 | /** |
176 | * Returns number of bits you need to shift a pixel element in order to move it to the start of the data type. |
177 | * |
178 | * @note |
179 | * For example if your color is stored in an UINT32 and you want to extract the red channel you should AND the color |
180 | * UINT32 with the bit-mask for the red channel and then right shift it by the red channel bit shift amount. |
181 | */ |
182 | static void getBitShifts(PixelFormat format, UINT8 (&rgba)[4]); |
183 | |
184 | /** Returns the name of the pixel format. */ |
185 | static String getFormatName(PixelFormat srcformat); |
186 | |
187 | /** |
188 | * Returns true if the pixel data in the format can be directly accessed and read. This is generally not true |
189 | * for compressed formats. |
190 | */ |
191 | static bool isAccessible(PixelFormat srcformat); |
192 | |
193 | /** Returns the type of an individual pixel element in the provided format. */ |
194 | static PixelComponentType getElementType(PixelFormat format); |
195 | |
196 | /** Returns the number of pixel elements in the provided format. */ |
197 | static UINT32 getNumElements(PixelFormat format); |
198 | |
199 | /** |
200 | * Returns the maximum number of mip maps that can be generated until we reach the minimum size possible. This |
201 | * does not count the base level. |
202 | */ |
203 | static UINT32 getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format); |
204 | |
205 | /** Writes the color to the provided memory location. */ |
206 | static void packColor(const Color& color, PixelFormat format, void* dest); |
207 | |
208 | /** |
209 | * Writes the color to the provided memory location. If the destination format is floating point, the byte values |
210 | * will be converted into [0.0, 1.0] range. |
211 | */ |
212 | static void packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format, void* dest); |
213 | |
214 | /** |
215 | * Writes the color to the provided memory location. If the destination format in non-floating point, the float |
216 | * values will be assumed to be in [0.0, 1.0] which will be converted to integer range. ([0, 255] in the case of bytes) |
217 | */ |
218 | static void packColor(float r, float g, float b, float a, const PixelFormat format, void* dest); |
219 | |
220 | /** Reads the color from the provided memory location and stores it into the provided color object. */ |
221 | static void unpackColor(Color* color, PixelFormat format, const void* src); |
222 | |
223 | /** |
224 | * Reads the color from the provided memory location and stores it into the provided color elements, as bytes |
225 | * clamped to [0, 255] range. |
226 | */ |
227 | static void unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src); |
228 | |
229 | /** |
230 | * Reads the color from the provided memory location and stores it into the provided color elements. If the format |
231 | * is not natively floating point a conversion is done in such a way that returned values range [0.0, 1.0]. |
232 | */ |
233 | static void unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src); |
234 | |
235 | /** Writes a depth value to the provided memory location. Depth should be in range [0, 1]. */ |
236 | static void packDepth(float depth, const PixelFormat format, void* dest); |
237 | |
238 | /** Reads the depth from the provided memory location. Value ranges in [0, 1]. */ |
239 | static float unpackDepth(PixelFormat format, void* src); |
240 | |
241 | /** |
242 | * Converts pixels from one format to another. Provided pixel data objects must have previously allocated buffers |
243 | * of adequate size and their sizes must match. |
244 | */ |
245 | static void bulkPixelConversion(const PixelData& src, PixelData& dst); |
246 | |
247 | /** Flips the order of components in each individual pixel. For example RGBA -> ABGR. */ |
248 | static void flipComponentOrder(PixelData& data); |
249 | |
250 | /** Compresses the provided data using the specified compression options. */ |
251 | static void compress(const PixelData& src, PixelData& dst, const CompressionOptions& options); |
252 | |
253 | /** |
254 | * Generates mip-maps from the provided source data using the specified compression options. Returned list includes |
255 | * the base level. |
256 | * |
257 | * @return A list of calculated mip-map data. First entry is the largest mip and other follow in order from |
258 | * largest to smallest. |
259 | */ |
260 | static Vector<SPtr<PixelData>> genMipmaps(const PixelData& src, const MipMapGenOptions& options); |
261 | |
262 | /** |
263 | * Scales pixel data in the source buffer and stores the scaled data in the destination buffer. Provided pixel data |
264 | * objects must have previously allocated buffers of adequate size. You may also provided a filtering method to use |
265 | * when scaling. |
266 | */ |
267 | static void scale(const PixelData& src, PixelData& dst, Filter filter = FILTER_LINEAR); |
268 | |
269 | /** |
270 | * Mirrors the contents of the provided object along the X, Y and/or Z axes. */ |
271 | static void mirror(PixelData& pixelData, MirrorMode mode); |
272 | |
273 | /** |
274 | * Copies the contents of the @p src buffer into the @p dst buffer. The size of the copied contents is determined |
275 | * by the size of the @p dst buffer. First pixel copied from @p src is determined by offset provided in |
276 | * @p offsetX, @p offsetY and @p offsetZ parameters. |
277 | */ |
278 | static void copy(const PixelData& src, PixelData& dst, UINT32 offsetX = 0, UINT32 offsetY = 0, UINT32 offsetZ = 0); |
279 | |
280 | /** Converts a color in linear space to a color in sRGB space. Only converts the RGB components. */ |
281 | static Color linearToSRGB(const Color& color); |
282 | |
283 | /** Converts a color in sRGB space to a color in linear space. Only converts the RGB components. */ |
284 | static Color SRGBToLinear(const Color& color); |
285 | |
286 | /** Converts pixel data in linear space to one in sRGB space. Only converts the RGB components. */ |
287 | static void linearToSRGB(PixelData& pixelData); |
288 | |
289 | /** Converts pixel data in sRGB space to one in linear space. Only converts the RGB components. */ |
290 | static void SRGBToLinear(PixelData& pixelData); |
291 | }; |
292 | |
293 | /** @} */ |
294 | } |
295 | |