| 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 | |