Dactyloidae/gfx/wr/wr_context.c
2026-09-18 12:00:30 -07:00

145 lines
3.7 KiB
C

#include <wr_internal.h>
wr_context*
wr_context_create(size_t initial_capacity)
{
wr_context* context = (wr_context*)calloc(1, sizeof(*context));
if (!context)
return NULL;
context->viewport.x = -FLT_MAX;
context->viewport.y = -FLT_MAX;
context->viewport.width = FLT_MAX;
context->viewport.height = FLT_MAX;
context->transform = wr_identity_transform();
context->opacity = 1.0f;
context->next_item_id = 1;
if (initial_capacity &&
!wr_reserve((void**)&context->commands, &context->command_capacity,
initial_capacity, sizeof(*context->commands))) {
wr_context_destroy(context);
return NULL;
}
return context;
}
void
wr_context_destroy(wr_context* context)
{
if (!context)
return;
free(context->commands);
free(context->quads);
free(context->batches);
free(context->clip_stack);
free(context->state_stack);
free(context->images);
for (size_t i = 0; i < context->transaction_depth; ++i)
free(context->transactions[i].commands);
free(context->transactions);
free(context);
}
void
wr_context_clear(wr_context* context)
{
if (!context)
return;
context->command_count = 0;
context->quad_count = 0;
context->batch_count = 0;
context->clip_depth = 0;
context->state_depth = 0;
context->frame_valid = 0;
while (context->transaction_depth)
free(context->transactions[--context->transaction_depth].commands);
}
void
wr_context_set_viewport(wr_context* context, wr_rect viewport)
{
if (context && wr_valid_rect(viewport))
context->viewport = viewport;
if (context)
context->frame_valid = 0;
}
void
wr_context_set_transform(wr_context* context, wr_transform transform)
{
if (context && wr_valid_transform(transform))
context->transform = transform;
}
void
wr_context_set_opacity(wr_context* context, float opacity)
{
if (context && isfinite(opacity)) {
context->opacity = wr_clamp01(opacity);
context->frame_valid = 0;
}
}
int
wr_display_list_push_stacking_context(wr_context* context,
wr_transform transform,
float opacity)
{
wr_display_state state;
if (!context || !wr_valid_transform(transform) || !isfinite(opacity) ||
context->state_depth == SIZE_MAX)
return 0;
if (!wr_reserve((void**)&context->state_stack, &context->state_capacity,
context->state_depth + 1, sizeof(*context->state_stack)))
return 0;
state.transform = context->transform;
state.opacity = context->opacity;
state.clip_depth = context->clip_depth;
context->state_stack[context->state_depth++] = state;
context->transform = wr_multiply_transform(context->transform, transform);
context->opacity = wr_clamp01(context->opacity * wr_clamp01(opacity));
return 1;
}
void
wr_display_list_pop_stacking_context(wr_context* context)
{
wr_display_state state;
if (!context || !context->state_depth)
return;
state = context->state_stack[--context->state_depth];
context->transform = state.transform;
context->opacity = state.opacity;
context->clip_depth = state.clip_depth;
}
int
wr_display_list_push_clip(wr_context* context, wr_rect clip)
{
wr_rect effective_clip;
if (!context || !wr_valid_rect(clip) ||
context->clip_depth == SIZE_MAX)
return 0;
if (!wr_reserve((void**)&context->clip_stack, &context->clip_capacity,
context->clip_depth + 1, sizeof(*context->clip_stack)))
return 0;
effective_clip = clip;
if (context->clip_depth)
effective_clip = wr_intersect_rect(
context->clip_stack[context->clip_depth - 1], clip);
context->clip_stack[context->clip_depth++] = effective_clip;
return 1;
}
void
wr_display_list_pop_clip(wr_context* context)
{
if (context && context->clip_depth)
--context->clip_depth;
}