├── README.md └── cro_mipmap.h /README.md: -------------------------------------------------------------------------------- 1 | # cro lib 2 | These librares are inspired by the [stb libraries]( https://github.com/nothings/stb ) which are single purpose C / C++ files. They are easy to implement and have minimal dependencies. They will be written with the intention of being used in video games (as this is where my interests lie). All files in the cro lib are public domain. 3 | 4 | ## cro_mipmap.h -- Mipmap Generation 5 | This header file has functions to generate mipmaps. Reasons you might want this: 6 | * Doesn't use any graphics API's or GPU calls 7 | * Can see what your textures' mipmaps might look like as basis for custom ones 8 | * Generated mipmaps outside of your application and put them into asset packs to avoid GPU overhead of generating them real time 9 | * Generate mipmaps on CPU in case the GPU is busy doing other things 10 | 11 | The library currently support the following pixel types: 12 | * 32-bit pixel images (order doesn't matter so RGBA, ARGB, etc) for traditional mipmap generation 13 | * floating point pixel images for use with depth textures 14 | 15 | The functions currently used to generate the mipmaps are: 16 | * Average of 4 pixels 17 | * Minumum of 4 pixels 18 | * Maximum of 4 pixels 19 | * Minumum and Maximum of 4 pixels. This was is preferred if you need both min and max mipmaps as it does both at the same time, avoiding redundant work. 20 | 21 | These functions will not allocate any memory, so the function cro_GetMipMapSize is provided to inform the user how big a resulting mipmap will be. The functions can also be run in parallel, breaking the work up based on rows. A number of the functions are created via a macro which uses a basic template of how the code will run. If a function down sampling function is needed, it can be very easy to extend the code. -------------------------------------------------------------------------------- /cro_mipmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | CRO Libaries -- Mipmap Generation -- public domain 3 | no warranty is offered or implied; use this code at your own risk 4 | 5 | C code for created various types of mipmaps for textures. 6 | 7 | Pixel types supported: 8 bit 4 channels (i.e. 32-bit such as RGBA, ABGR, etc) 8 | 32-bit floating point pixels (ie depth textures) 9 | 10 | Down sampling functions: Average (traditional mipmap generation) 11 | Minimum (for depth values) 12 | Maximum (for depth values) 13 | Minimum and maximum (done at the same time to 14 | avoid redundant work of 15 | deparate calls) 16 | 17 | ========================================================================= 18 | LICENSE 19 | 20 | This software is in the public domain. Where that dedication is not 21 | recognized, you are granted a perpetual, irrevocable license to copy, 22 | distribute, and modify this file as you see fit. 23 | ========================================================================= 24 | 25 | Credits: 26 | Written by Cody Olivier 27 | 28 | 29 | */ 30 | 31 | #ifndef cro_mipmap_h 32 | #define cro_mipmap_h 33 | 34 | #ifdef CRO_Min 35 | #undef CRO_Min; 36 | #endif 37 | 38 | #ifdef CRO_Max 39 | #undef CRO_Max; 40 | #endif 41 | 42 | #define CRO_Max( x, y ) ( (x) > (y) ? (x) : (y) ) 43 | #define CRO_Min( x, y ) ( (x) < (y) ? (x) : (y) ) 44 | 45 | static inline void cro_GetMipMapSize( unsigned int width, unsigned int height, 46 | unsigned int *newWidth, unsigned int *newHeight) 47 | { 48 | *newWidth = width >> 1; 49 | *newHeight = height >> 1; 50 | } 51 | 52 | // 53 | //---------------------------------------------------- 54 | // 55 | // Integer MipMaps 56 | // -These functions assume that each pixel is made up of 4 channels, each 1 byte. 57 | // -Odd image dimensions will be rounded down when down sampled. 58 | // -Odd width will ignore last column, odd height will ignore last row 59 | // -These functions will not allocate memory. If you are unsure how big the 60 | // generated mip map will be, use cro_GetMipMapSize. 61 | // 62 | // Main Use: 32-bit color images 63 | // 64 | //---------------------------------------------------- 65 | // 66 | static inline int cro_AvgBits( int n1, int n2, int n3, int n4, int bitShifts ) 67 | { 68 | int byte1 = (n1 >> bitShifts) & 0xff; 69 | int byte2 = (n2 >> bitShifts) & 0xff; 70 | int byte3 = (n3 >> bitShifts) & 0xff; 71 | int byte4 = (n4 >> bitShifts) & 0xff; 72 | return ( byte1 + byte2 + byte3 + byte4 ) >> 2; 73 | } 74 | 75 | static inline int cro_MaxBits( int n1, int n2, int n3, int n4, int bitShifts ) 76 | { 77 | 78 | int byte1 = (n1 >> bitShifts) & 0xff; 79 | int byte2 = (n2 >> bitShifts) & 0xff; 80 | int byte3 = (n3 >> bitShifts) & 0xff; 81 | int byte4 = (n4 >> bitShifts) & 0xff; 82 | return CRO_Max( CRO_Max( byte1, byte2 ), CRO_Max( byte3, byte4 ) ); 83 | } 84 | 85 | static inline int cro_MinBits( int n1, int n2, int n3, int n4, int bitShifts ) 86 | { 87 | int byte1 = (n1 >> bitShifts) & 0xff; 88 | int byte2 = (n2 >> bitShifts) & 0xff; 89 | int byte3 = (n3 >> bitShifts) & 0xff; 90 | int byte4 = (n4 >> bitShifts) & 0xff; 91 | return CRO_Min( CRO_Min( byte1, byte2 ), CRO_Min( byte3, byte4 ) ); 92 | } 93 | 94 | 95 | static inline void cro_MinMaxBits( int n1, int n2, int n3, int n4, int bitShifts, int *min, int *max ) 96 | { 97 | int byte1 = (n1 >> bitShifts) & 0xff; 98 | int byte2 = (n2 >> bitShifts) & 0xff; 99 | int byte3 = (n3 >> bitShifts) & 0xff; 100 | int byte4 = (n4 >> bitShifts) & 0xff; 101 | 102 | int max1, max2, min1, min2; 103 | 104 | if ( byte1 > byte2 ) 105 | { 106 | max1 = byte1; 107 | min1 = byte2; 108 | } 109 | else 110 | { 111 | max1 = byte2; 112 | min1 = byte1; 113 | } 114 | 115 | if ( byte3 > byte4 ) 116 | { 117 | max2 = byte3; 118 | min2 = byte4; 119 | } 120 | else 121 | { 122 | max2 = byte4; 123 | min2 = byte3; 124 | } 125 | 126 | *min = CRO_Min( min1, min2 ); 127 | *max = CRO_Max( max1, max2 ); 128 | } 129 | 130 | static inline int cro_GetMipMapLevels( unsigned int width, unsigned int height ) 131 | { 132 | int levels = 0; 133 | while ( width > 1 && height > 1 ) 134 | { 135 | width >>= 1; 136 | height >>= 1; 137 | levels++; 138 | } 139 | return levels; 140 | } 141 | 142 | #define CRO_GenMipMapI_Template( name, fn ) \ 143 | static inline void cro_GenMipMap##name##I( const int *image, unsigned int width, unsigned int height, int *newImage ) \ 144 | { \ 145 | if ( width == 0 || height == 0 ) \ 146 | return; \ 147 | \ 148 | unsigned int newWidth, newHeight; \ 149 | int *newPixel = newImage; \ 150 | cro_GetMipMapSize( width, height, &newWidth, &newHeight ); \ 151 | \ 152 | for ( int h = 0; h < newHeight; ++h ) \ 153 | { \ 154 | const int *row1 = &image[ width * ( 2 * h + 0 ) ]; \ 155 | const int *row2 = &image[ width * ( 2 * h + 1 ) ]; \ 156 | for ( int w = 0; w < newWidth; ++w, ++newPixel, row1 += 2, row2 += 2 ) \ 157 | { \ 158 | int p1 = row1[0]; \ 159 | int p2 = row2[0]; \ 160 | int p3 = row1[1]; \ 161 | int p4 = row2[1]; \ 162 | \ 163 | int byte1 = fn( p1, p2, p3, p4, 24 ); \ 164 | int byte2 = fn( p1, p2, p3, p4, 16 ); \ 165 | int byte3 = fn( p1, p2, p3, p4, 8 ); \ 166 | int byte4 = fn( p1, p2, p3, p4, 0 ); \ 167 | \ 168 | *newPixel = ( byte1 << 24 ) | \ 169 | ( byte2 << 16 ) | \ 170 | ( byte3 << 8 ) | \ 171 | ( byte4 << 0 ); \ 172 | } \ 173 | } \ 174 | } 175 | 176 | // template macros for: cro_GenMipMapAvgI 177 | // cro_GenMipMapMinI 178 | // cro_GenMipMapMaxI 179 | CRO_GenMipMapI_Template( Avg, cro_AvgBits ); 180 | CRO_GenMipMapI_Template( Min, cro_MinBits ); 181 | CRO_GenMipMapI_Template( Max, cro_MaxBits ); 182 | 183 | static inline void cro_GenMipMapMinMaxI( const int *image, unsigned int width, unsigned int height, int *minMip, int *maxMip ) 184 | { 185 | if ( width == 0 || height == 0 ) 186 | return; 187 | 188 | unsigned int newWidth, newHeight; 189 | int *minPixel = minMip; 190 | int *maxPixel = maxMip; 191 | cro_GetMipMapSize( width, height, &newWidth, &newHeight ); 192 | 193 | for ( int h = 0; h < newHeight; ++h ) 194 | { 195 | const int *row1 = &image[ width * ( 2 * h + 0 ) ]; 196 | const int *row2 = &image[ width * ( 2 * h + 1 ) ]; 197 | for ( int w = 0; w < newWidth; ++w, ++minPixel, ++maxPixel, row1 += 2, row2 += 2 ) 198 | { 199 | int p1 = row1[0]; 200 | int p2 = row2[0]; 201 | int p3 = row1[1]; 202 | int p4 = row2[1]; 203 | 204 | int max1, max2, max3, max4; 205 | int min1, min2, min3, min4; 206 | 207 | cro_MinMaxBits( p1, p2, p3, p4, 24, &min1, &max1 ); 208 | cro_MinMaxBits( p1, p2, p3, p4, 16, &min2, &max2 ); 209 | cro_MinMaxBits( p1, p2, p3, p4, 8, &min3, &max3 ); 210 | cro_MinMaxBits( p1, p2, p3, p4, 0, &min4, &max4 ); 211 | 212 | *minMip = ( min1 << 24 ) | ( min2 << 16 ) | ( min3 << 8 ) | ( min4 << 0 ); 213 | *maxMip = ( max1 << 24 ) | ( max2 << 16 ) | ( max3 << 8 ) | ( max4 << 0 ); 214 | } 215 | } 216 | } 217 | 218 | // 219 | //---------------------------------------------------- 220 | // 221 | // Float MipMaps 222 | // -Odd image dimensions will be rounded down when down sampled. 223 | // -Odd width will ignore last column, odd height will ignore last row 224 | // -These functions will not allocate memory. If you are unsure how big the 225 | // generated mip map will be, use cro_GetMipMapSize. 226 | // 227 | // Main Use: determining min/max values of a depth texture. 228 | // Avg varient is added for completeness 229 | // 230 | //---------------------------------------------------- 231 | // 232 | static inline float cro_AvgF( float n1, float n2, float n3, float n4 ) 233 | { 234 | //NOTE: doesn't take into account if sum overflows before being multiplied 235 | return ( n1 + n2 + n3 + n4 ) * 0.25f; 236 | } 237 | 238 | static inline float cro_MinF( float n1, float n2, float n3, float n4 ) 239 | { 240 | return CRO_Min( CRO_Min( n1, n2 ), CRO_Min( n3, n4 )); 241 | } 242 | 243 | static inline float cro_MaxF( float n1, float n2, float n3, float n4 ) 244 | { 245 | return CRO_Max( CRO_Max( n1, n2 ), CRO_Max( n3, n4 )); 246 | } 247 | 248 | static inline void cro_MinMaxF( float n1, float n2, float n3, float n4, float *min, float *max ) 249 | { 250 | float max1, max2, min1, min2; 251 | 252 | if ( n1 > n2 ) 253 | { 254 | max1 = n1; 255 | min1 = n2; 256 | } 257 | else 258 | { 259 | max1 = n2; 260 | min1 = n1; 261 | } 262 | 263 | if ( n3 > n4 ) 264 | { 265 | max2 = n3; 266 | min2 = n4; 267 | } 268 | else 269 | { 270 | max2 = n4; 271 | min2 = n3; 272 | } 273 | 274 | *min = CRO_Min( min1, min2 ); 275 | *max = CRO_Max( max1, max2 ); 276 | } 277 | 278 | 279 | #define CRO_GenMipMapF_Template( name, fn ) \ 280 | static inline void cro_GenMipMap##name##F( const float *image, unsigned int width, unsigned int height, float *newImage ) \ 281 | { \ 282 | if ( width == 0 || height == 0 ) \ 283 | return; \ 284 | \ 285 | unsigned int newWidth, newHeight; \ 286 | float *newPixel = newImage; \ 287 | cro_GetMipMapSize( width, height, &newWidth, &newHeight ); \ 288 | \ 289 | for ( int h = 0; h < newHeight; ++h ) \ 290 | { \ 291 | const float *row1 = &image[ width * ( 2 * h + 0 ) ]; \ 292 | const float *row2 = &image[ width * ( 2 * h + 1 ) ]; \ 293 | for ( int w = 0; w < newWidth; ++w, ++newPixel, row1 += 2, row2 += 2 ) \ 294 | { \ 295 | float p1 = row1[0]; \ 296 | float p2 = row2[0]; \ 297 | float p3 = row1[1]; \ 298 | float p4 = row2[1]; \ 299 | *newPixel = fn( p1, p2, p3, p4 ); \ 300 | } \ 301 | } \ 302 | } 303 | 304 | // template macros for: cro_GenMipMapAvgF 305 | // cro_GenMipMapMinF 306 | // cro_GenMipMapMaxF 307 | CRO_GenMipMapF_Template( Avg, cro_AvgF ); 308 | CRO_GenMipMapF_Template( Min, cro_MinF ); 309 | CRO_GenMipMapF_Template( Max, cro_MaxF ); 310 | 311 | static inline void cro_GenMipMapMinMaxF( const float *image, unsigned int width, unsigned int height, float *minMip, float *maxMip ) 312 | { 313 | if ( width == 0 || height == 0 ) 314 | return; 315 | 316 | unsigned int newWidth, newHeight; 317 | float *minPixel = minMip; 318 | float *maxPixel = maxMip; 319 | cro_GetMipMapSize( width, height, &newWidth, &newHeight ); 320 | 321 | for ( int h = 0; h < newHeight; ++h ) 322 | { 323 | const float *row1 = &image[ width * ( 2 * h + 0 ) ]; 324 | const float *row2 = &image[ width * ( 2 * h + 1 ) ]; 325 | for ( int w = 0; w < newWidth; ++w, ++minPixel, ++maxPixel, row1 += 2, row2 += 2 ) 326 | { 327 | int p1 = row1[0]; 328 | int p2 = row2[0]; 329 | int p3 = row1[1]; 330 | int p4 = row2[1]; 331 | cro_MinMaxF( p1, p2, p3, p4, minPixel, maxPixel ); 332 | } 333 | } 334 | } 335 | 336 | #endif 337 | --------------------------------------------------------------------------------