tools/pngtotex.c
static Texture *generate_mipmaps(Texture *texture, int mipmaps,
                                 uint32_t *extra_pixels_ret)
{
    /* Worst case is a 1x2^n texture, which will have mipmaps of size
     * 1x2^(n-1), 1x2^(n-2), ..., 1x4, 1x2, 1x1, for a total of 2^(n+1)-1
     * pixels. */
    const uint32_t struct_size = align_up(sizeof(*texture), 64);
    const uint32_t alloc_size =
        struct_size + (texture->stride * texture->height * 4) * 2;
    Texture *new_texture = realloc(texture, alloc_size);
    if (!new_texture) {
        fprintf(stderr, "Out of memory generating mipmaps\n");
        free_texture(texture);
        return NULL;
    }
    texture = new_texture;
    texture->pixels = (uint8_t *)texture + struct_size;

    if (extra_pixels_ret) {
        *extra_pixels_ret = 0;
    }

    unsigned int width  = texture->width;
    unsigned int height = texture->height;
    unsigned int stride = texture->stride;
    uint8_t *    pixels = texture->pixels;

    for (int level = 1; level <= mipmaps && (width > 1 || height > 1); level++) {

        const unsigned int old_width  = width;
        const unsigned int old_height = height;
        const unsigned int old_stride = stride;
        uint8_t * const    old_pixels = pixels;

        pixels += stride * height * 4;
        width  = lbound(width/2, 1);
        height = lbound(height/2, 1);
        stride = lbound(stride/2, 1);

        ZoomInfo *zi = zoom_init(old_width, old_height, width, height,
                                 4, old_stride*4, stride*4,
                                 1, TCV_ZOOM_CUBIC_KEYS4);
        if (!zi) {
            fprintf(stderr, "zoom_init() failed\n");
            free_texture(texture);
            return NULL;
        }
        zoom_process(zi, old_pixels, pixels);
        zoom_free(zi);

        for (int i = 0; i < num_mipmap_regions; i++) {
            if (mipmap_regions[i].w == 0 || mipmap_regions[i].h == 0) {
                /* Invalid or previously disabled. */
            } else if ((mipmap_regions[i].x % 2) != 0
                    || (mipmap_regions[i].y % 2) != 0
                    || (mipmap_regions[i].w % 2) != 0
                    || (mipmap_regions[i].h % 2) != 0) {
                /* Doesn't shrink to pixel boundaries, so disable the entry. */
                mipmap_regions[i].w = mipmap_regions[i].h = 0;
            } else {
                zi = zoom_init(mipmap_regions[i].w, mipmap_regions[i].h,
                               mipmap_regions[i].w/2, mipmap_regions[i].h/2,
                               4, old_stride*4, stride*4,
                               1, TCV_ZOOM_CUBIC_KEYS4);
                if (!zi) {
                    fprintf(stderr,
                            "zoom_init() failed for mipmap region %d\n", i);
                    free_texture(texture);
                    return NULL;
                }
                const uint8_t *src = old_pixels
                    + (mipmap_regions[i].y * old_stride
                       + mipmap_regions[i].x) * 4;
                uint8_t *dest = pixels
                    + ((mipmap_regions[i].y/2) * stride
                       + (mipmap_regions[i].x/2)) * 4;
                zoom_process(zi, src, dest);
                zoom_free(zi);
                mipmap_regions[i].x /= 2;
                mipmap_regions[i].y /= 2;
                mipmap_regions[i].w /= 2;
                mipmap_regions[i].h /= 2;
            }
        }  // for (i = 0; i < num_mipmap_regions; i++)

        if (mipmaps_transparent_at != 0 && level >= mipmaps_transparent_at) {
            /* Retain the color data (for inter-mipmap interpolation); just
             * clear the alpha channel. */
            for (uint32_t i = 0; i < stride*height; i++) {
                pixels[i*4+3] = 0;
            }
        }

        texture->mipmaps++;
        if (extra_pixels_ret) {
            *extra_pixels_ret += width * height;
        }

    }

    return texture;
}
/**
 * generate_mipmaps:  Generate the given number of mipmaps for the given
 * 32bpp texture, stopping if the mipmap size reaches 1x1.  The texture
 * buffer is reallocated by this function, and freed on error.
 *
 * [Parameters]
 *     tex: Texture to generate mipmaps for.
 *     mipmaps: Maximum number of mipmaps to generate.
 *     extra_pixels_ret: Pointer to variable to receive the number of
 *         pixels added, or NULL if not needed.
 * [Return value]
 *     New texture pointer, or NULL on error.
 */
Generate the given number of mipmaps for the given
32bpp texture, stopping if the mipmap size reaches 1x1.  The texture
buffer is reallocated by this function, and freed on error.

[Parameters]
tex: Texture to generate mipmaps for.
mipmaps: Maximum number of mipmaps to generate.
extra_pixels_ret: Pointer to variable to receive the number of
pixels added, or NULL if not needed.
[Return value]
New texture pointer, or NULL on error.
Generate the given number of mipmaps for the given 32bpp texture stopping if the mipmap size reaches 1x1 . The texture buffer is reallocated by this function and freed on error . [ Parameters ] tex : Texture to generate mipmaps for . mipmaps : Maximum number of mipmaps to generate . extra_pixels_ret : Pointer to variable to receive the number of pixels added or NULL if not needed . [ Return value ] New texture pointer or NULL on error .
static Texture *generate_mipmaps(Texture *texture, int mipmaps,
                                 uint32_t *extra_pixels_ret)
{
    const uint32_t struct_size = align_up(sizeof(*texture), 64);
    const uint32_t alloc_size =
        struct_size + (texture->stride * texture->height * 4) * 2;
    Texture *new_texture = realloc(texture, alloc_size);
    if (!new_texture) {
        fprintf(stderr, "Out of memory generating mipmaps\n");
        free_texture(texture);
        return NULL;
    }
    texture = new_texture;
    texture->pixels = (uint8_t *)texture + struct_size;
    if (extra_pixels_ret) {
        *extra_pixels_ret = 0;
    }
    unsigned int width  = texture->width;
    unsigned int height = texture->height;
    unsigned int stride = texture->stride;
    uint8_t *    pixels = texture->pixels;
    for (int level = 1; level <= mipmaps && (width > 1 || height > 1); level++) {
        const unsigned int old_width  = width;
        const unsigned int old_height = height;
        const unsigned int old_stride = stride;
        uint8_t * const    old_pixels = pixels;
        pixels += stride * height * 4;
        width  = lbound(width/2, 1);
        height = lbound(height/2, 1);
        stride = lbound(stride/2, 1);
        ZoomInfo *zi = zoom_init(old_width, old_height, width, height,
                                 4, old_stride*4, stride*4,
                                 1, TCV_ZOOM_CUBIC_KEYS4);
        if (!zi) {
            fprintf(stderr, "zoom_init() failed\n");
            free_texture(texture);
            return NULL;
        }
        zoom_process(zi, old_pixels, pixels);
        zoom_free(zi);
        for (int i = 0; i < num_mipmap_regions; i++) {
            if (mipmap_regions[i].w == 0 || mipmap_regions[i].h == 0) {
            } else if ((mipmap_regions[i].x % 2) != 0
                    || (mipmap_regions[i].y % 2) != 0
                    || (mipmap_regions[i].w % 2) != 0
                    || (mipmap_regions[i].h % 2) != 0) {
                mipmap_regions[i].w = mipmap_regions[i].h = 0;
            } else {
                zi = zoom_init(mipmap_regions[i].w, mipmap_regions[i].h,
                               mipmap_regions[i].w/2, mipmap_regions[i].h/2,
                               4, old_stride*4, stride*4,
                               1, TCV_ZOOM_CUBIC_KEYS4);
                if (!zi) {
                    fprintf(stderr,
                            "zoom_init() failed for mipmap region %d\n", i);
                    free_texture(texture);
                    return NULL;
                }
                const uint8_t *src = old_pixels
                    + (mipmap_regions[i].y * old_stride
                       + mipmap_regions[i].x) * 4;
                uint8_t *dest = pixels
                    + ((mipmap_regions[i].y/2) * stride
                       + (mipmap_regions[i].x/2)) * 4;
                zoom_process(zi, src, dest);
                zoom_free(zi);
                mipmap_regions[i].x /= 2;
                mipmap_regions[i].y /= 2;
                mipmap_regions[i].w /= 2;
                mipmap_regions[i].h /= 2;
            }
        }  
        if (mipmaps_transparent_at != 0 && level >= mipmaps_transparent_at) {
            for (uint32_t i = 0; i < stride*height; i++) {
                pixels[i*4+3] = 0;
            }
        }
        texture->mipmaps++;
        if (extra_pixels_ret) {
            *extra_pixels_ret += width * height;
        }
    }
    return texture;
}
static Texture * generate_mipmaps ( Texture * texture , int mipmaps , uint32_t * extra_pixels_ret ) { const uint32_t struct_size = align_up ( sizeof ( * texture ) , 64 ) ; const uint32_t alloc_size = struct_size + ( texture -> stride * texture -> height * 4 ) * 2 ; Texture * new_texture = realloc ( texture , alloc_size ) ; if ( ! new_texture ) { fprintf ( stderr , " \n " ) ; free_texture ( texture ) ; return NULL ; } texture = new_texture ; texture -> pixels = ( uint8_t * ) texture + struct_size ; if ( extra_pixels_ret ) { * extra_pixels_ret = 0 ; } unsigned int width = texture -> width ; unsigned int height = texture -> height ; unsigned int stride = texture -> stride ; uint8_t * pixels = texture -> pixels ; for ( int level = 1 ; level <= mipmaps && ( width > 1 || height > 1 ) ; level ++ ) { const unsigned int old_width = width ; const unsigned int old_height = height ; const unsigned int old_stride = stride ; uint8_t * const old_pixels = pixels ; pixels += stride * height * 4 ; width = lbound ( width / 2 , 1 ) ; height = lbound ( height / 2 , 1 ) ; stride = lbound ( stride / 2 , 1 ) ; ZoomInfo * zi = zoom_init ( old_width , old_height , width , height , 4 , old_stride * 4 , stride * 4 , 1 , TCV_ZOOM_CUBIC_KEYS4 ) ; if ( ! zi ) { fprintf ( stderr , " \n " ) ; free_texture ( texture ) ; return NULL ; } zoom_process ( zi , old_pixels , pixels ) ; zoom_free ( zi ) ; for ( int i = 0 ; i < num_mipmap_regions ; i ++ ) { if ( mipmap_regions [ i ] . w == 0 || mipmap_regions [ i ] . h == 0 ) { } else if ( ( mipmap_regions [ i ] . x % 2 ) != 0 || ( mipmap_regions [ i ] . y % 2 ) != 0 || ( mipmap_regions [ i ] . w % 2 ) != 0 || ( mipmap_regions [ i ] . h % 2 ) != 0 ) { mipmap_regions [ i ] . w = mipmap_regions [ i ] . h = 0 ; } else { zi = zoom_init ( mipmap_regions [ i ] . w , mipmap_regions [ i ] . h , mipmap_regions [ i ] . w / 2 , mipmap_regions [ i ] . h / 2 , 4 , old_stride * 4 , stride * 4 , 1 , TCV_ZOOM_CUBIC_KEYS4 ) ; if ( ! zi ) { fprintf ( stderr , " \n " , i ) ; free_texture ( texture ) ; return NULL ; } const uint8_t * src = old_pixels + ( mipmap_regions [ i ] . y * old_stride + mipmap_regions [ i ] . x ) * 4 ; uint8_t * dest = pixels + ( ( mipmap_regions [ i ] . y / 2 ) * stride + ( mipmap_regions [ i ] . x / 2 ) ) * 4 ; zoom_process ( zi , src , dest ) ; zoom_free ( zi ) ; mipmap_regions [ i ] . x /= 2 ; mipmap_regions [ i ] . y /= 2 ; mipmap_regions [ i ] . w /= 2 ; mipmap_regions [ i ] . h /= 2 ; } } if ( mipmaps_transparent_at != 0 && level >= mipmaps_transparent_at ) { for ( uint32_t i = 0 ; i < stride * height ; i ++ ) { pixels [ i * 4 + 3 ] = 0 ; } } texture -> mipmaps ++ ; if ( extra_pixels_ret ) { * extra_pixels_ret += width * height ; } } return texture ; }
generate_mipmaps:  Generate the given number of mipmaps for the given
 32bpp texture, stopping if the mipmap size reaches 1x1.
generate_mipmaps : Generate the given number of mipmaps for the given 32bpp texture stopping if the mipmap size reaches 1x1 .
/* Worst case is a 1x2^n texture, which will have mipmaps of size
     * 1x2^(n-1), 1x2^(n-2), ..., 1x4, 1x2, 1x1, for a total of 2^(n+1)-1
     * pixels. */ /* Invalid or previously disabled. */ /* Doesn't shrink to pixel boundaries, so disable the entry. */ // for (i = 0; i < num_mipmap_regions; i++) /* Retain the color data (for inter-mipmap interpolation); just
             * clear the alpha channel. */