Elaztek Developer Hub
Blamite Game Engine - Guerilla (Library)  00456.10.01.26.0053.blamite
The tag editor for the Blamite Game Engine.
bitmap.cpp File Reference
#include "bitmap.h"
#include <sail/sail.h>
#include <sail-manip/sail-manip.h>
#include <map>
#include <vector>
#include <bimg/bimg.h>
#include <bimg/encode.h>
#include <bx/allocator.h>
#include <bx/error.h>
#include <Strings/components/utils/io/io.h>
#include <Strings/components/logger/logger.h>
#include <Strings/components/utils/converters/converters.h>
#include <Strings/components/utils/string/string.h>
#include "components/tags/fields/enum/enum.h"
#include "components/tags/fields/int/int.h"
#include "components/tags/fields/dataref/dataref.h"
#include "components/tags/fields/vector/vector.h"
#include "components/tags/fields/block/block.h"
#include "components/tags/fields/bitfield/bitfield.h"
#include "components/tags/tags.h"
+ Include dependency graph for bitmap.cpp:

Functions

bool validate_image_pixel_format (sail_image **image_pointer, SailPixelFormat default_pixel_format=SailPixelFormat::SAIL_PIXEL_FORMAT_BPP32_RGBA)
 Ensures that the provided image is converted to a supported pixel format. More...
 
void update_format_value (BlamTagField_Enum *format_field, SailPixelFormat pixel_format)
 
void update_format_value (BlamTagField_Enum *format_field, bimg::TextureFormat::Enum pixel_format)
 
void write_import_info (BlamTagField_Block *import_info, int64_t file_size, std::string file_path, std::string file_format, std::string source_pixel_format, std::string parsed_pixel_format)
 
float srgb_to_linear (float srgb_value)
 Converts a single sRGB-encoded color channel value to linear space. More...
 
float linear_to_srgb (float linear_value)
 Converts a single linear-space color channel value to sRGB encoding. More...
 
void downsample_mip_2x2 (const uint8_t *source, int source_width, int source_height, uint8_t *destination, int destination_width, int destination_height, bool treat_as_srgb)
 Generates the next mip level for an RGBA8 image by averaging 2x2 pixel blocks. More...
 
int compute_mip_count (int width, int height)
 Computes the number of mip levels in a complete chain for the given dimensions. More...
 
int compute_mip_chain_size_rgba8 (int base_width, int base_height)
 Computes the total byte count required to hold a complete mip chain for an RGBA8 image of the given base dimensions. More...
 
void * build_mip_chain_rgba8 (const void *base_pixel_data, int base_width, int base_height, bool treat_as_srgb, int *out_chain_size)
 Builds a complete RGBA8 mip chain from a base level. More...
 
bimg::ImageContainer * build_mipped_rgba8_image (bx::AllocatorI *allocator, const bimg::ImageContainer &source, bool treat_as_srgb)
 Produces a copy of an image with a complete mip chain attached, ready to be handed to bimg::imageEncode. More...
 
bool mip_chain_is_gpu_addressable (int width, int height, bimg::TextureFormat::Enum format)
 Checks whether a complete mip chain for these dimensions can actually be addressed by the GPU in a block-compressed format. More...
 
bimg::ImageContainer * encode_mipped_image (bx::AllocatorI *allocator, bimg::TextureFormat::Enum destination_format, bimg::Quality::Enum quality, const bimg::ImageContainer &source)
 Encodes an image and every mip level it carries into a block-compressed format. More...
 

Variables

std::map< SailPixelFormat, std::string > supported_pixel_formats = std::map<SailPixelFormat, std::string>()
 
std::map< bimg::TextureFormat::Enum, std::string > supported_pixel_formats_bimg = std::map<bimg::TextureFormat::Enum, std::string>()
 

Function Documentation

◆ build_mip_chain_rgba8()

void* build_mip_chain_rgba8 ( const void *  base_pixel_data,
int  base_width,
int  base_height,
bool  treat_as_srgb,
int *  out_chain_size 
)

Builds a complete RGBA8 mip chain from a base level.

Allocates a single buffer sized for the entire chain, copies the provided base data into the mip 0 region, then iteratively downsamples each subsequent mip from the previous one using a 2x2 box filter. The output is packed in the layout that bimg and bgfx expect - mip 0 first, followed by each subsequent mip contiguously.

Parameters
base_pixel_data- Pointer to the source mip 0 data (RGBA8, tightly packed).
base_width- Width of the base image in pixels.
base_height- Height of the base image in pixels.
treat_as_srgb- Whether downsampling should be gamma-correct for color images.
out_chain_size- Receives the total size of the returned buffer, in bytes.
Returns
A malloc'd buffer containing the full mip chain, which the caller is responsible for freeing. Returns nullptr if allocation failed.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ build_mipped_rgba8_image()

bimg::ImageContainer* build_mipped_rgba8_image ( bx::AllocatorI *  allocator,
const bimg::ImageContainer &  source,
bool  treat_as_srgb 
)

Produces a copy of an image with a complete mip chain attached, ready to be handed to bimg::imageEncode.

Mips are always generated from RGBA8 data, so images in any other format are converted first. The result is a freshly allocated bimg image container whose mip 0 matches the source, and whose remaining levels were produced by successive 2x2 box filtering.

Parameters
allocator- The allocator to use for the converted/mipped images.
source- The image to build a mip chain for. Should be a single-mip image.
treat_as_srgb- Whether downsampling should be gamma-correct for color images.
Returns
The mipped image, which the caller must release with bimg::imageFree. Returns nullptr if the source could not be converted to RGBA8, or if the mipped image could not be allocated.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compute_mip_chain_size_rgba8()

int compute_mip_chain_size_rgba8 ( int  base_width,
int  base_height 
)

Computes the total byte count required to hold a complete mip chain for an RGBA8 image of the given base dimensions.

The mip chain follows the standard "halve each dimension, minimum 1" rule and terminates when both dimensions reach 1. Each mip's contribution is its width * height * 4 bytes. This matches the level count and layout that both bimg and bgfx expect from a complete chain.

Parameters
base_width- Width of mip 0 in pixels.
base_height- Height of mip 0 in pixels.
Returns
The sum of all mip levels' byte sizes.
+ Here is the caller graph for this function:

◆ compute_mip_count()

int compute_mip_count ( int  width,
int  height 
)

Computes the number of mip levels in a complete chain for the given dimensions.

The mip count is determined by the largest dimension, halved repeatedly until it reaches 1. The base level (mip 0) is always counted, so this returns at least 1.

Parameters
width- Width of the base image in pixels.
height- Height of the base image in pixels.
Returns
The number of mip levels in a complete chain from the base down to 1x1.
+ Here is the caller graph for this function:

◆ downsample_mip_2x2()

void downsample_mip_2x2 ( const uint8_t *  source,
int  source_width,
int  source_height,
uint8_t *  destination,
int  destination_width,
int  destination_height,
bool  treat_as_srgb 
)

Generates the next mip level for an RGBA8 image by averaging 2x2 pixel blocks.

When sRGB correctness is requested, the color channels (RGB) are converted to linear space before averaging and converted back to sRGB afterward. This avoids the brightness-shift artifact that occurs when sRGB-encoded values are averaged directly. Alpha is always averaged in raw bytes since it isn't gamma encoded. Source data is sampled with edge-clamp behavior so non-power-of-two dimensions are handled correctly.

Parameters
source- Pointer to the source mip's pixel buffer (RGBA8, tightly packed).
source_width- Width in pixels of the source buffer.
source_height- Height in pixels of the source buffer.
destination- Pointer to the destination buffer to write the new mip into.
destination_width- Width in pixels of the destination buffer.
destination_height- Height in pixels of the destination buffer.
treat_as_srgb- If true, RGB channels go through gamma-correct averaging.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ encode_mipped_image()

bimg::ImageContainer* encode_mipped_image ( bx::AllocatorI *  allocator,
bimg::TextureFormat::Enum  destination_format,
bimg::Quality::Enum  quality,
const bimg::ImageContainer &  source 
)

Encodes an image and every mip level it carries into a block-compressed format.

This exists instead of the single-call bimg::imageEncode(allocator, format, quality, image) because that one does not write a whole destination level when the level's dimensions do not line up with the format's block grid, leaving part of the level holding whatever the allocation came with.

Two things cause that misalignment. Block formats store whole 4x4 blocks, so the last levels of a chain (2x2 and 1x1) still occupy a full block. And for sizes that are not a power of two, bimg rounds each level up to a whole block before halving it, so its levels drift larger than the plainly halved levels the chain was generated with - a 1600x1600 texture generates a 12x12 level 7 while the destination expects 16x16, which is nine blocks written out of sixteen. The rest decoded as near-black, which dragged whole surfaces dark.

So each level is encoded from a buffer of the destination level's own size, built by clamping to the generated level's edges. That fills every block the destination holds, from real colour, whatever the two sizes are.

Parameters
allocator- The allocator to use for the encoded image.
destination_format- The block-compressed format to encode into.
quality- The encoder quality preset to use.
source- The image to encode. Must be RGBA8, and may carry a mip chain.
Returns
The encoded image, which the caller must release with bimg::imageFree. Returns nullptr if the output image could not be allocated.
+ Here is the caller graph for this function:

◆ linear_to_srgb()

float linear_to_srgb ( float  linear_value)

Converts a single linear-space color channel value to sRGB encoding.

The inverse of srgb_to_linear. Used after averaging color values in linear space to produce a result that is correctly gamma-encoded for storage in an sRGB texture.

Parameters
linear_value- The linear-space value, normalized to the [0, 1] range.
Returns
The equivalent sRGB-encoded value, also in the [0, 1] range.
+ Here is the caller graph for this function:

◆ mip_chain_is_gpu_addressable()

bool mip_chain_is_gpu_addressable ( int  width,
int  height,
bimg::TextureFormat::Enum  format 
)

Checks whether a complete mip chain for these dimensions can actually be addressed by the GPU in a block-compressed format.

bimg and the graphics APIs disagree about how a mip level's size is derived. bimg rounds each level up to a whole block and then halves that, while D3D11 and OpenGL define level N as max(1, width >> N) from the base size. Those agree for every power-of-two size and for most others, but where a dimension's padding compounds they can land on different block counts - a 1600x1600 texture's level 7 is 16x16 (4x4 blocks) to bimg and 12x12 (3x3 blocks) to the API. From that level down the driver reads each level at the wrong stride and offset, and the texture ends up unusable no matter how correct the stored data is.

Uncompressed formats have a block size of one, so nothing ever rounds and this always passes for them.

Parameters
width- Width of the base image in pixels.
height- Height of the base image in pixels.
format- The format the chain will be stored in.
Returns
true if every level of the chain resolves to the same block count both ways, meaning the chain is safe to build.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ srgb_to_linear()

float srgb_to_linear ( float  srgb_value)

Converts a single sRGB-encoded color channel value to linear space.

Uses the proper piecewise transform from the sRGB specification rather than the gamma-2.2 approximation. The piecewise version handles values near black more accurately - the gamma curve goes flat in that region and a pure power function would produce slightly wrong results.

Parameters
srgb_value- The sRGB-encoded value, normalized to the [0, 1] range.
Returns
The equivalent value in linear color space, also in the [0, 1] range.
+ Here is the caller graph for this function:

◆ update_format_value() [1/2]

void update_format_value ( BlamTagField_Enum *  format_field,
bimg::TextureFormat::Enum  pixel_format 
)
Todo:
document

◆ update_format_value() [2/2]

void update_format_value ( BlamTagField_Enum *  format_field,
SailPixelFormat  pixel_format 
)
Todo:
document
+ Here is the caller graph for this function:

◆ validate_image_pixel_format()

bool validate_image_pixel_format ( sail_image **  image_pointer,
SailPixelFormat  default_pixel_format = SailPixelFormat::SAIL_PIXEL_FORMAT_BPP32_RGBA 
)

Ensures that the provided image is converted to a supported pixel format.

If the source image data does not use a pixel format supported by the engine, then sail will attempt to convert the image to the best possible pixel format.

Parameters
image_pointer- Pointer to the created image data.
default_pixel_format- The format to convert the image to if the original image format is not supported.
Returns
true if the image was either already in a supported format, or was successfully converted. If image conversion failed, then this will return false.
Todo:
Add support more pixel formats.
+ Here is the caller graph for this function:

◆ write_import_info()

void write_import_info ( BlamTagField_Block *  import_info,
int64_t  file_size,
std::string  file_path,
std::string  file_format,
std::string  source_pixel_format,
std::string  parsed_pixel_format 
)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ supported_pixel_formats

std::map<SailPixelFormat, std::string> supported_pixel_formats = std::map<SailPixelFormat, std::string>()

◆ supported_pixel_formats_bimg

std::map<bimg::TextureFormat::Enum, std::string> supported_pixel_formats_bimg = std::map<bimg::TextureFormat::Enum, std::string>()