Skip to content

Adapter API

Gabe Rundlett edited this page Mar 6, 2023 · 7 revisions

This is a feature for more advanced users, if you just want to know about how to use the common API, take a look the Consumer API page

Getting Started

There are currently 4 different types of adapters: input, output, parse, and serialize

Each adapter has 4 common functions - create, destroy, blit_begin, and blit_end. (NOTE: The function names are not of importance to the signature currently, since you manually register the functions. `${NAME} is the name of the adapter, ${TYPE} is the type of adapter)

These functions must be provided in order for your format to communicate with the gvox library, and in turn, with any other format that also implements the necessary functions.

The Parse and Serialize adapters deal directly with the voxel data - which may be packed/arranged in a proprietary manner, depending on the format. This is okay because gvox 1.x- supplies rules as to what the data for each channel must be. Each channel can provide 32 bits of information, but these bits are not necessarily meant to represent integers:

COLOR         8bpc RGB color, pow(linear_value, 1/2.2) ranging [0, 1]
NORMAL        8bpc XYZ, linear_value ranging [-1, 1]
MATERIAL_ID   u32
ROUGHNESS     f32 linear_value [0, 1]
METALNESS     f32 linear_value [0, 1]
TRANSPARENCY  f32 linear_value [0, 1]
IOR           f32 linear_value (0, inf)
EMISSIVITY    8bpc RGB color, pow(linear_value, 1/2.2) ranging [0, 1]
HARDNESS      ...

Common Functions

Create

void gvox_${TYPE}_adapter_${NAME}_create(GvoxAdapterContext *ctx, void *config);

create is called when a new adapter context of that type is called. A pointer to the adapter context is provided, as well as a void pointer to a config that the consumer provides. It is perfectly valid for the config to be a NULL pointer, so you must handle this on your end. If you believe your adapter needs additional state, you may allocate it yourself and use gvox_adapter_set_user_pointer to link that pointer to the adapter context.

Destroy

void gvox_${TYPE}_adapter_${NAME}_destroy(GvoxAdapterContext *ctx);

destroy is called when the adapter context is destroyed by the user. If you have managed objects at the data pointed to by the user pointer, now is the time to destruct, clean up, or "drop" them. You are only provided with a pointer to the adapter context in this function. Use gvox_adapter_get_user_pointer to retrieve that state to destroy.

Blit Begin

void gvox_${TYPE}_adapter_${NAME}_blit_begin(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx);

blit_begin is called when the user has dispatched a blit operation, and it has just begun. The begin functions are called in order of adapter type as follows: input -> output -> parse -> serialize. This makes it so that parse adapters are able to start using the input adapter functionality.

for parse adapters, it would be common to load in a format's header using gvox_input_read in this function.

Blit End

void gvox_${TYPE}_adapter_${NAME}_blit_end(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx);

blit_end is called when the user has dispatched a blit operation, and it has just finished. The end functions are called in reverse order of adapter type as follows: serialize -> parse -> output -> input.

Input Adapter Functions

void gvox_input_adapter_${NAME}_read(GvoxAdapterContext *ctx, size_t position, size_t size, void *data);

Output Adapter Functions

void gvox_output_adapter_${NAME}_write(GvoxAdapterContext *ctx, size_t position, size_t size, void const *data);
void gvox_output_adapter_${NAME}_reserve(GvoxAdapterContext *ctx, size_t size);

Parse Adapter Functions

uint32_t gvox_parse_adapter_${NAME}_query_region_flags(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegionRange const *range, uint32_t channel_flags);
GvoxRegion gvox_parse_adapter_${NAME}_load_region(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegionRange const *range, uint32_t channel_flags);
void gvox_parse_adapter_${NAME}_unload_region(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegion *region);
uint32_t gvox_parse_adapter_${NAME}_sample_region(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegion const *region, GvoxOffset3D const *offset, uint32_t channel_id);

Serialize Adapter Functions

void gvox_serialize_adapter_${NAME}_serialize_region(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegionRange const *range, uint32_t channel_flags);

The 2 simpler types of adapters are input and output adapters. They just handle where the data stream comes from and goes to.

WORK IN PROGRESS:

Creating an Input Adapter

For demonstration's sake, we'll go ahead and create an adapter that just provides the user with the ability to use an array of bytes as an input stream.

Creating an Output Adapter

...

Creating a Parse Adapter

...

Creating a Serialize Adapter

...